| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /* GATE PROJECT LICENSE: | ||
| 2 | +----------------------------------------------------------------------------+ | ||
| 3 | | Copyright(c) 2018-2025, Stefan Meislinger | | ||
| 4 | | All rights reserved. | | ||
| 5 | | | | ||
| 6 | | Redistribution and use in source and binary forms, with or without | | ||
| 7 | | modification, are permitted provided that the following conditions are met:| | ||
| 8 | | | | ||
| 9 | | 1. Redistributions of source code must retain the above copyright notice, | | ||
| 10 | | this list of conditions and the following disclaimer. | | ||
| 11 | | 2. Redistributions in binary form must reproduce the above copyright | | ||
| 12 | | notice, this list of conditions and the following disclaimer in the | | ||
| 13 | | documentation and/or other materials provided with the distribution. | | ||
| 14 | | | | ||
| 15 | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"| | ||
| 16 | | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | ||
| 17 | | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | ||
| 18 | | ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | | ||
| 19 | | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | ||
| 20 | | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | ||
| 21 | | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | ||
| 22 | | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | ||
| 23 | | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | ||
| 24 | | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | | ||
| 25 | | THE POSSIBILITY OF SUCH DAMAGE. | | ||
| 26 | +----------------------------------------------------------------------------+ | ||
| 27 | */ | ||
| 28 | |||
| 29 | #include "gate/system/storagevolumes.h" | ||
| 30 | #include "gate/results.h" | ||
| 31 | #include "gate/debugging.h" | ||
| 32 | |||
| 33 | #if defined(GATE_SYS_WIN) && !defined(GATE_SYS_WIN16) | ||
| 34 | # define GATE_SYSTEM_STORAGEVOLUMES_WINAPI_IMPL 1 | ||
| 35 | #elif defined(GATE_SYS_POSIX) && !defined(GATE_SYS_ANDROID) && !defined(GATE_SYS_BEOS) && !defined(GATE_SYS_DARWIN) | ||
| 36 | # define GATE_SYSTEM_STORAGEVOLUMES_POSIX_IMPL 1 | ||
| 37 | #else | ||
| 38 | # define GATE_SYSTEM_STORAGEVOLUMES_NO_IMPL 1 | ||
| 39 | #endif | ||
| 40 | |||
| 41 | /* generic implementation */ | ||
| 42 | |||
| 43 | static char const gate_storagevolume_typename_harddrive[] = "Fixed disk"; | ||
| 44 | static char const gate_storagevolume_typename_removable[] = "Removable medium"; | ||
| 45 | static char const gate_storagevolume_typename_removable_rom[] = "CD/DVD/Blu-Ray"; | ||
| 46 | static char const gate_storagevolume_typename_networkdrive[] = "Network drive"; | ||
| 47 | static char const gate_storagevolume_typename_ramdrive[] = "RAM drive"; | ||
| 48 | static char const gate_storagevolume_typename_system[] = "System or virtual storage"; | ||
| 49 | static char const gate_storagevolume_typename_system_private[] = "System internal storage"; | ||
| 50 | |||
| 51 | #define GATE_STORAGEVOLUME_TYPE_UNKNOWN 0 | ||
| 52 | #define GATE_STORAGEVOLUME_TYPE_HARDDRIVE 1 | ||
| 53 | #define GATE_STORAGEVOLUME_TYPE_REMOVABLEDRIVE 2 | ||
| 54 | #define GATE_STORAGEVOLUME_TYPE_REMOVABLEROM 3 | ||
| 55 | #define GATE_STORAGEVOLUME_TYPE_NETWORKDRIVE 4 | ||
| 56 | #define GATE_STORAGEVOLUME_TYPE_RAMDRIVE 5 | ||
| 57 | #define GATE_STORAGEVOLUME_TYPE_SYSTEM 6 | ||
| 58 | #define GATE_STORAGEVOLUME_TYPE_SYSTEMPRIVATE 7 | ||
| 59 | |||
| 60 | ✗ | char const* gate_storagevolume_print_type(gate_enumint_t volume_type) | |
| 61 | { | ||
| 62 | ✗ | switch (volume_type) | |
| 63 | { | ||
| 64 | ✗ | case GATE_STORAGEVOLUME_TYPE_HARDDRIVE: return gate_storagevolume_typename_harddrive; | |
| 65 | ✗ | case GATE_STORAGEVOLUME_TYPE_REMOVABLEDRIVE: return gate_storagevolume_typename_removable; | |
| 66 | ✗ | case GATE_STORAGEVOLUME_TYPE_REMOVABLEROM: return gate_storagevolume_typename_removable_rom; | |
| 67 | ✗ | case GATE_STORAGEVOLUME_TYPE_NETWORKDRIVE: return gate_storagevolume_typename_networkdrive; | |
| 68 | ✗ | case GATE_STORAGEVOLUME_TYPE_RAMDRIVE: return gate_storagevolume_typename_ramdrive; | |
| 69 | ✗ | case GATE_STORAGEVOLUME_TYPE_SYSTEM: return gate_storagevolume_typename_system; | |
| 70 | ✗ | case GATE_STORAGEVOLUME_TYPE_SYSTEMPRIVATE: return gate_storagevolume_typename_system_private; | |
| 71 | ✗ | default: return NULL; | |
| 72 | } | ||
| 73 | } | ||
| 74 | |||
| 75 | struct gate_storagevolume_find_param | ||
| 76 | { | ||
| 77 | gate_enumint_t field_type; | ||
| 78 | gate_string_t const* field_value; | ||
| 79 | gate_bool_t found; | ||
| 80 | gate_storagevolume_t* target_volume; | ||
| 81 | }; | ||
| 82 | |||
| 83 | 45 | static gate_bool_t gate_storagevolume_find_callback(gate_storagevolume_t const* volume, void* user_param) | |
| 84 | { | ||
| 85 | 45 | struct gate_storagevolume_find_param* param = (struct gate_storagevolume_find_param*)user_param; | |
| 86 | 45 | gate_bool_t is_matching = false; | |
| 87 |
3/4✓ Branch 0 taken 15 times.
✓ Branch 1 taken 15 times.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
|
45 | switch (param->field_type) |
| 88 | { | ||
| 89 | 15 | case GATE_STORAGEVOLUME_PATH: | |
| 90 | { | ||
| 91 | 45 | is_matching = 0 == gate_str_compare(param->field_value->str, param->field_value->length, | |
| 92 | 15 | volume->path, gate_str_length(volume->path)); | |
| 93 | 15 | break; | |
| 94 | } | ||
| 95 | 15 | case GATE_STORAGEVOLUME_UID: | |
| 96 | { | ||
| 97 | 45 | is_matching = 0 == gate_str_compare(param->field_value->str, param->field_value->length, | |
| 98 | 15 | volume->uid, gate_str_length(volume->uid)); | |
| 99 | 15 | break; | |
| 100 | } | ||
| 101 | 15 | case GATE_STORAGEVOLUME_NAME: | |
| 102 | { | ||
| 103 | 45 | is_matching = 0 == gate_str_compare(param->field_value->str, param->field_value->length, | |
| 104 | 15 | volume->name, gate_str_length(volume->name)); | |
| 105 | 15 | break; | |
| 106 | } | ||
| 107 | } | ||
| 108 | |||
| 109 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 30 times.
|
45 | if (is_matching) |
| 110 | { | ||
| 111 | 15 | param->found = true; | |
| 112 | 15 | gate_mem_copy(param->target_volume, volume, sizeof(gate_storagevolume_t)); | |
| 113 | 15 | return false; /* cancel enumeration */ | |
| 114 | } | ||
| 115 | else | ||
| 116 | { | ||
| 117 | 30 | return true; /* continue enumeration */ | |
| 118 | } | ||
| 119 | } | ||
| 120 | |||
| 121 | 15 | gate_result_t gate_storagevolume_find(gate_string_t const* field, gate_enumint_t field_type, gate_storagevolume_t* volume) | |
| 122 | { | ||
| 123 | struct gate_storagevolume_find_param param; | ||
| 124 | 15 | param.field_type = field_type; | |
| 125 | 15 | param.field_value = field; | |
| 126 | 15 | param.found = false; | |
| 127 | 15 | param.target_volume = volume; | |
| 128 | |||
| 129 | 15 | return gate_storagevolume_enum(&gate_storagevolume_find_callback, ¶m); | |
| 130 | } | ||
| 131 | |||
| 132 | |||
| 133 | #if defined(GATE_SYSTEM_STORAGEVOLUMES_WINAPI_IMPL) | ||
| 134 | |||
| 135 | #include "gate/platforms.h" | ||
| 136 | #include "gate/system/platform/storage_winapi.h" | ||
| 137 | |||
| 138 | #if defined(GATE_SYS_WINCE) | ||
| 139 | |||
| 140 | gate_result_t gate_storagevolume_enum(gate_storagevolume_enum_callback_t callback, void* user_param) | ||
| 141 | { | ||
| 142 | gate_storagevolume_t volume; | ||
| 143 | |||
| 144 | gate_mem_clear(&volume, sizeof(volume)); | ||
| 145 | |||
| 146 | GATE_STR_PRINT_TEXT(volume.path, "\\"); | ||
| 147 | GATE_STR_PRINT_TEXT(volume.name, "\\"); | ||
| 148 | GATE_STR_PRINT_TEXT(volume.uid, "\\"); | ||
| 149 | GATE_STR_PRINT_TEXT(volume.devicepath, "\\"); | ||
| 150 | GATE_STR_PRINT_TEXT(volume.serial, ""); | ||
| 151 | GATE_STR_PRINT_TEXT(volume.devicename, "\\"); | ||
| 152 | GATE_STR_PRINT_TEXT(volume.fsname, "FS"); | ||
| 153 | /* | ||
| 154 | volume.size; | ||
| 155 | volume.sizeused; | ||
| 156 | volume.sizefree; | ||
| 157 | volume.volumetype; | ||
| 158 | volume.flags; | ||
| 159 | */ | ||
| 160 | callback(&volume, user_param); | ||
| 161 | |||
| 162 | return GATE_RESULT_OK; | ||
| 163 | } | ||
| 164 | |||
| 165 | gate_result_t gate_storagevolume_openstream(gate_storagevolume_t const* drive, gate_enumint_t open_flags, gate_controlstream_t** stream) | ||
| 166 | { | ||
| 167 | gate_result_t ret = GATE_RESULT_NOTSUPPORTED; | ||
| 168 | /*TODO*/ | ||
| 169 | return ret; | ||
| 170 | } | ||
| 171 | |||
| 172 | |||
| 173 | #else | ||
| 174 | |||
| 175 | |||
| 176 | static BOOL WINAPI win32_get_disk_free_space_ex(LPCTSTR lpDirectoryName, | ||
| 177 | PULARGE_INTEGER lpFreeBytesAvailable, | ||
| 178 | PULARGE_INTEGER lpTotalNumberOfBytes, | ||
| 179 | PULARGE_INTEGER lpTotalNumberOfFreeBytes) | ||
| 180 | { | ||
| 181 | static BOOL(WINAPI * GetDiskFreeSpaceEx_func)(LPCTSTR, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER) = NULL; | ||
| 182 | static BOOL(WINAPI * GetDiskFreeSpace_func)(LPCTSTR, LPDWORD, LPDWORD, LPDWORD, LPDWORD) = NULL; | ||
| 183 | static HMODULE hmod_kernel = NULL; | ||
| 184 | |||
| 185 | if (!GetDiskFreeSpaceEx_func && !GetDiskFreeSpace_func) | ||
| 186 | { | ||
| 187 | hmod_kernel = gate_win32_get_kernel_module(); | ||
| 188 | gate_win32_get_proc_address(hmod_kernel, GATE_WINAPI_DUAL_NAME("GetDiskFreeSpaceEx"), &GetDiskFreeSpaceEx_func); | ||
| 189 | gate_win32_get_proc_address(hmod_kernel, GATE_WINAPI_DUAL_NAME("GetDiskFreeSpace"), &GetDiskFreeSpace_func); | ||
| 190 | } | ||
| 191 | |||
| 192 | if (GetDiskFreeSpaceEx_func) | ||
| 193 | { | ||
| 194 | return GetDiskFreeSpaceEx_func(lpDirectoryName, lpFreeBytesAvailable, lpTotalNumberOfBytes, lpTotalNumberOfFreeBytes); | ||
| 195 | } | ||
| 196 | if (GetDiskFreeSpace_func) | ||
| 197 | { | ||
| 198 | BOOL ret; | ||
| 199 | DWORD sectorsPerCluster = 0, bytesPerSector = 0, numberOfFreeClusters = 0, totalNumberOfClusters = 0; | ||
| 200 | ret = GetDiskFreeSpace_func(lpDirectoryName, §orsPerCluster, &bytesPerSector, &numberOfFreeClusters, &totalNumberOfClusters); | ||
| 201 | if (ret) | ||
| 202 | { | ||
| 203 | gate_uint64_t bytes_per_cluster = (gate_uint64_t)bytesPerSector * (gate_uint64_t)sectorsPerCluster; | ||
| 204 | gate_uint64_t total_size = bytes_per_cluster * (gate_uint64_t)totalNumberOfClusters; | ||
| 205 | gate_uint64_t free_size = bytes_per_cluster * (gate_uint64_t)numberOfFreeClusters; | ||
| 206 | if (lpFreeBytesAvailable) lpFreeBytesAvailable->QuadPart = free_size; | ||
| 207 | if (lpTotalNumberOfBytes) lpTotalNumberOfBytes->QuadPart = total_size; | ||
| 208 | if (lpTotalNumberOfFreeBytes) lpTotalNumberOfFreeBytes->QuadPart = free_size; | ||
| 209 | } | ||
| 210 | return ret; | ||
| 211 | } | ||
| 212 | return FALSE; | ||
| 213 | } | ||
| 214 | |||
| 215 | |||
| 216 | gate_result_t gate_storagevolume_enum(gate_storagevolume_enum_callback_t callback, void* user_param) | ||
| 217 | { | ||
| 218 | gate_result_t ret = GATE_RESULT_OK; | ||
| 219 | DWORD drvbits = GetLogicalDrives(); | ||
| 220 | TCHAR drvpath[] = _T("A:\\"); | ||
| 221 | TCHAR drvpathnt[] = _T("\\\\.\\A:"); | ||
| 222 | TCHAR volname[MAX_PATH + 1]; | ||
| 223 | UINT drvtype; | ||
| 224 | DWORD volsernum; | ||
| 225 | DWORD maxcomponentlen; | ||
| 226 | DWORD filesysflags; | ||
| 227 | TCHAR fsname[MAX_PATH + 1]; | ||
| 228 | gate_size_t len; | ||
| 229 | ULARGE_INTEGER userspacefree, drivespacetotal, drivespacefree; | ||
| 230 | HANDLE hvolume; | ||
| 231 | GATE_WIN32_VOLUME_DISK_EXTENTS vdx; | ||
| 232 | DWORD bytesreturned; | ||
| 233 | int drvnum; | ||
| 234 | |||
| 235 | gate_storagevolume_t volume; | ||
| 236 | |||
| 237 | gate_mem_clear(&volume, sizeof(gate_storagevolume_t)); | ||
| 238 | gate_str_print_text(volume.path, sizeof(volume.path), "A:\\", 3); | ||
| 239 | gate_str_print_text(volume.name, sizeof(volume.name), "A:", 2); | ||
| 240 | gate_str_print_text(volume.uid, sizeof(volume.uid), "\\\\.\\A:", 6); | ||
| 241 | |||
| 242 | for (drvnum = 0; drvnum < 26; ++drvnum) | ||
| 243 | { | ||
| 244 | if (drvbits & (1 << drvnum)) | ||
| 245 | { | ||
| 246 | volume.path[0] = (char)('A' + drvnum); | ||
| 247 | volume.name[0] = (char)('A' + drvnum); | ||
| 248 | volume.name[2] = 0; | ||
| 249 | volume.uid[4] = (char)('A' + drvnum); | ||
| 250 | volume.flags = 0; | ||
| 251 | drvpath[0] = (TCHAR)('A' + drvnum); | ||
| 252 | drvpathnt[4] = (TCHAR)('A' + drvnum); | ||
| 253 | |||
| 254 | drvtype = GetDriveType(drvpath); | ||
| 255 | switch (drvtype) | ||
| 256 | { | ||
| 257 | case DRIVE_REMOVABLE: volume.volumetype = GATE_STORAGEVOLUME_TYPE_REMOVABLEDRIVE; break; | ||
| 258 | case DRIVE_FIXED: volume.volumetype = GATE_STORAGEVOLUME_TYPE_HARDDRIVE; break; | ||
| 259 | case DRIVE_REMOTE: volume.volumetype = GATE_STORAGEVOLUME_TYPE_NETWORKDRIVE; break; | ||
| 260 | case DRIVE_CDROM: volume.volumetype = GATE_STORAGEVOLUME_TYPE_REMOVABLEROM; break; | ||
| 261 | case DRIVE_RAMDISK: volume.volumetype = GATE_STORAGEVOLUME_TYPE_RAMDRIVE; break; | ||
| 262 | default: volume.volumetype = GATE_STORAGEVOLUME_TYPE_UNKNOWN; break; | ||
| 263 | } | ||
| 264 | |||
| 265 | if (FALSE != GetVolumeInformation(drvpath, volname, sizeof(volname) / sizeof(volname[0]), &volsernum, &maxcomponentlen, &filesysflags, fsname, sizeof(fsname) / sizeof(fsname[0]))) | ||
| 266 | { | ||
| 267 | gate_str_print_hex_byte(&volume.serial[0], 2, (gate_uint8_t)((volsernum >> 24) & 0xff), true); | ||
| 268 | gate_str_print_hex_byte(&volume.serial[2], 2, (gate_uint8_t)((volsernum >> 16) & 0xff), true); | ||
| 269 | volume.serial[4] = '-'; | ||
| 270 | gate_str_print_hex_byte(&volume.serial[5], 2, (gate_uint8_t)((volsernum >> 8) & 0xff), true); | ||
| 271 | gate_str_print_hex_byte(&volume.serial[7], 2, (gate_uint8_t)((volsernum) & 0xff), true); | ||
| 272 | volume.serial[9] = 0; | ||
| 273 | |||
| 274 | /* setting the file system name (e.g. "FAT32" or "NTFS") */ | ||
| 275 | gate_win32_winstr_2_utf8(fsname, gate_win32_winstr_length(fsname), volume.fsname, sizeof(volume.fsname)); | ||
| 276 | |||
| 277 | len = gate_win32_winstr_length(volname); | ||
| 278 | if (len > 0) | ||
| 279 | { | ||
| 280 | /* add the volume label to the name, e.g. "C: (System-Drive)" */ | ||
| 281 | volume.name[2] = ' '; | ||
| 282 | volume.name[3] = '('; | ||
| 283 | len = gate_win32_winstr_2_utf8(volname, len, &volume.name[4], sizeof(volume.name) - 6); | ||
| 284 | volume.name[len + 4] = ')'; | ||
| 285 | volume.name[len + 5] = 0; | ||
| 286 | } | ||
| 287 | volume.flags |= GATE_STORAGEVOLUME_FLAG_ONLINE; | ||
| 288 | if (GATE_FLAG_ENABLED(filesysflags, FILE_READ_ONLY_VOLUME)) volume.flags |= GATE_STORAGEVOLUME_FLAG_READONLY; | ||
| 289 | } | ||
| 290 | else | ||
| 291 | { | ||
| 292 | volume.serial[0] = 0; | ||
| 293 | volume.fsname[0] = 0; | ||
| 294 | } | ||
| 295 | |||
| 296 | if (win32_get_disk_free_space_ex(drvpath, &userspacefree, &drivespacetotal, &drivespacefree)) | ||
| 297 | { | ||
| 298 | volume.size = drivespacetotal.QuadPart; | ||
| 299 | volume.sizefree = drivespacefree.QuadPart; | ||
| 300 | volume.sizeused = drivespacetotal.QuadPart - drivespacefree.QuadPart; | ||
| 301 | } | ||
| 302 | else | ||
| 303 | { | ||
| 304 | volume.size = 0; | ||
| 305 | volume.sizefree = 0; | ||
| 306 | volume.sizeused = 0; | ||
| 307 | } | ||
| 308 | |||
| 309 | volume.devicepath[0] = 0; | ||
| 310 | |||
| 311 | hvolume = gate_win32_createfile(drvpathnt, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, OPEN_EXISTING, 0, 0, NULL); | ||
| 312 | /*hvolume = CreateFile(drvpathnt, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);*/ | ||
| 313 | if (hvolume != INVALID_HANDLE_VALUE) | ||
| 314 | { | ||
| 315 | if (DeviceIoControl(hvolume, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, NULL, 0, &vdx, sizeof(vdx), &bytesreturned, NULL)) | ||
| 316 | { | ||
| 317 | len = gate_str_print_text(volume.devicepath, sizeof(volume.devicepath), "\\\\.\\PhysicalDrive", 17); | ||
| 318 | gate_str_print_uint32(&volume.devicepath[len], sizeof(volume.devicepath) - len, (gate_uint32_t)vdx.Extents[0].DiskNumber); | ||
| 319 | } | ||
| 320 | CloseHandle(hvolume); | ||
| 321 | } | ||
| 322 | |||
| 323 | if (!callback(&volume, user_param)) | ||
| 324 | { | ||
| 325 | break; | ||
| 326 | } | ||
| 327 | } | ||
| 328 | } | ||
| 329 | |||
| 330 | return ret; | ||
| 331 | } | ||
| 332 | |||
| 333 | |||
| 334 | |||
| 335 | static void volumestream_release(void* thisptr); | ||
| 336 | static int volumestream_retain(void* thisptr); | ||
| 337 | static char const* volumestream_get_interface_name(void* thisptr); | ||
| 338 | |||
| 339 | static gate_result_t volumestream_read(void* thisptr, char* buffer, gate_size_t bufferlength, gate_size_t* returned); | ||
| 340 | static gate_result_t volumestream_peek(void* thisptr, char* buffer, gate_size_t bufferlength, gate_size_t* returned); | ||
| 341 | static gate_result_t volumestream_write(void* thisptr, char const* buffer, gate_size_t bufferlength, gate_size_t* written); | ||
| 342 | static gate_result_t volumestream_flush(void* thisptr); | ||
| 343 | |||
| 344 | static gate_result_t volumestream_get_resource(void* thisptr, gate_enumint_t resource_type, gate_uintptr_t* resource); | ||
| 345 | |||
| 346 | static gate_result_t volumestream_can_read(void* thisptr, gate_bool_t* return_value); | ||
| 347 | static gate_result_t volumestream_can_write(void* thisptr, gate_bool_t* return_value); | ||
| 348 | static gate_result_t volumestream_get_size(void* thisptr, gate_int64_t* return_value); | ||
| 349 | static gate_result_t volumestream_get_available(void* thisptr, gate_int64_t* return_value); | ||
| 350 | static gate_result_t volumestream_seek(void* thisptr, gate_int64_t position, gate_enumint_t origin, gate_int64_t* final_position); | ||
| 351 | static gate_result_t volumestream_reset(void* thisptr); | ||
| 352 | static gate_result_t volumestream_close(void* thisptr, gate_enumint_t close_type); | ||
| 353 | |||
| 354 | |||
| 355 | static GATE_INTERFACE_VTBL(gate_controlstream) gate_volumestream_vtbl; | ||
| 356 | static void gate_init_volumestream_vtbl() | ||
| 357 | { | ||
| 358 | if (!gate_volumestream_vtbl.get_interface_name) | ||
| 359 | { | ||
| 360 | static GATE_INTERFACE_VTBL(gate_controlstream) local_vtbl = | ||
| 361 | { | ||
| 362 | &volumestream_get_interface_name, | ||
| 363 | &volumestream_release, | ||
| 364 | &volumestream_retain, | ||
| 365 | |||
| 366 | &volumestream_read, | ||
| 367 | &volumestream_peek, | ||
| 368 | &volumestream_write, | ||
| 369 | &volumestream_flush, | ||
| 370 | |||
| 371 | &volumestream_get_resource, | ||
| 372 | |||
| 373 | &volumestream_can_read, | ||
| 374 | &volumestream_can_write, | ||
| 375 | &volumestream_get_size, | ||
| 376 | &volumestream_get_available, | ||
| 377 | &volumestream_seek, | ||
| 378 | &volumestream_reset, | ||
| 379 | &volumestream_close, | ||
| 380 | }; | ||
| 381 | gate_volumestream_vtbl = local_vtbl; | ||
| 382 | } | ||
| 383 | } | ||
| 384 | typedef struct gate_volumestream_class | ||
| 385 | { | ||
| 386 | GATE_INTERFACE_VTBL(gate_controlstream) const* vtbl; | ||
| 387 | |||
| 388 | gate_atomic_int_t ref_counter; | ||
| 389 | gate_bool_t writeaccess; | ||
| 390 | gate_bool_t is_locked; | ||
| 391 | char devicepath[128]; | ||
| 392 | |||
| 393 | gate_platform_stream_buffer_t block_stream; | ||
| 394 | |||
| 395 | } gate_volumestream_t; | ||
| 396 | |||
| 397 | static gate_uint64_t gate_storagevolume_get_volume_length(HANDLE hdevice) | ||
| 398 | { | ||
| 399 | DWORD bytesreturned = 0; | ||
| 400 | |||
| 401 | GATE_WIN32_GET_LENGTH_INFORMATION get_length_information = GATE_INIT_EMPTY; | ||
| 402 | GATE_DISK_GEOMETRY geometry = GATE_INIT_EMPTY; | ||
| 403 | |||
| 404 | if (DeviceIoControl(hdevice, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &get_length_information, sizeof(get_length_information), &bytesreturned, NULL)) | ||
| 405 | { | ||
| 406 | return get_length_information.Length.QuadPart; | ||
| 407 | } | ||
| 408 | else if (DeviceIoControl(hdevice, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geometry, sizeof(geometry), &bytesreturned, NULL)) | ||
| 409 | { | ||
| 410 | return (gate_uint64_t)geometry.Cylinders.QuadPart | ||
| 411 | * (gate_uint64_t)geometry.TracksPerCylinder | ||
| 412 | * (gate_uint64_t)geometry.SectorsPerTrack | ||
| 413 | * (gate_uint64_t)geometry.BytesPerSector | ||
| 414 | ; | ||
| 415 | } | ||
| 416 | return 0; | ||
| 417 | } | ||
| 418 | static gate_size_t gate_storagevolume_get_volume_block_size(HANDLE hdevice) | ||
| 419 | { | ||
| 420 | DWORD bytesreturned = 0; | ||
| 421 | |||
| 422 | /* GATE_WIN32_GET_LENGTH_INFORMATION get_length_information = GATE_INIT_EMPTY; */ | ||
| 423 | GATE_DISK_GEOMETRY geometry = GATE_INIT_EMPTY; | ||
| 424 | |||
| 425 | if (DeviceIoControl(hdevice, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geometry, sizeof(geometry), &bytesreturned, NULL)) | ||
| 426 | { | ||
| 427 | return (gate_size_t)geometry.BytesPerSector; | ||
| 428 | } | ||
| 429 | |||
| 430 | /* if we cannot retrieve it, let's use 512 as default*/ | ||
| 431 | return 512; | ||
| 432 | } | ||
| 433 | |||
| 434 | |||
| 435 | gate_result_t gate_storagevolume_openstream(gate_storagevolume_t const* volume, gate_enumint_t open_flags, gate_controlstream_t** stream) | ||
| 436 | { | ||
| 437 | gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED; | ||
| 438 | gate_volumestream_t* volumestream = NULL; | ||
| 439 | gate_bool_t writable; | ||
| 440 | TCHAR devpath[1024]; | ||
| 441 | DWORD dwaccess; | ||
| 442 | DWORD dwshare = (FILE_SHARE_READ | FILE_SHARE_WRITE); | ||
| 443 | DWORD dwflags = 0; | ||
| 444 | HANDLE hvolume = INVALID_HANDLE_VALUE; | ||
| 445 | gate_size_t ndx; | ||
| 446 | DWORD bytesreturned = 0; | ||
| 447 | gate_uint64_t volume_length = 0; | ||
| 448 | gate_size_t volume_block_size = 512; | ||
| 449 | |||
| 450 | do | ||
| 451 | { | ||
| 452 | if ((volume == NULL) || (stream == NULL)) | ||
| 453 | { | ||
| 454 | ret = GATE_RESULT_INVALIDARG; | ||
| 455 | break; | ||
| 456 | } | ||
| 457 | |||
| 458 | if (GATE_FLAG_ENABLED(open_flags, GATE_STREAM_OPEN_WRITE)) | ||
| 459 | { | ||
| 460 | writable = true; | ||
| 461 | dwaccess = GENERIC_WRITE; | ||
| 462 | dwflags = (FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH); | ||
| 463 | } | ||
| 464 | else if (GATE_FLAG_ENABLED(open_flags, GATE_STREAM_OPEN_READ)) | ||
| 465 | { | ||
| 466 | writable = false; | ||
| 467 | dwaccess = GENERIC_READ; | ||
| 468 | dwflags = FILE_FLAG_SEQUENTIAL_SCAN; | ||
| 469 | } | ||
| 470 | else | ||
| 471 | { | ||
| 472 | ret = GATE_RESULT_INVALIDARG; | ||
| 473 | break; | ||
| 474 | } | ||
| 475 | |||
| 476 | ndx = gate_win32_utf8_2_winstr(volume->uid, gate_str_length(volume->uid), devpath, sizeof(devpath) / sizeof(devpath[0])); | ||
| 477 | if (ndx == 0) | ||
| 478 | { | ||
| 479 | ret = GATE_RESULT_INVALIDARG; | ||
| 480 | } | ||
| 481 | |||
| 482 | hvolume = gate_win32_createfile(devpath, dwaccess, dwshare, OPEN_EXISTING, 0, dwflags, NULL); | ||
| 483 | if (INVALID_HANDLE_VALUE == hvolume) | ||
| 484 | { | ||
| 485 | gate_win32_print_lasterror(&ret, NULL, 0); | ||
| 486 | break; | ||
| 487 | } | ||
| 488 | |||
| 489 | volume_length = gate_storagevolume_get_volume_length(hvolume); | ||
| 490 | if (volume_length == 0) | ||
| 491 | { | ||
| 492 | volume_length = volume->size; | ||
| 493 | } | ||
| 494 | volume_block_size = gate_storagevolume_get_volume_block_size(hvolume); | ||
| 495 | |||
| 496 | volumestream = gate_mem_alloc(sizeof(gate_volumestream_t) + volume_block_size); | ||
| 497 | if (volumestream == NULL) | ||
| 498 | { | ||
| 499 | ret = GATE_RESULT_OUTOFMEMORY; | ||
| 500 | break; | ||
| 501 | } | ||
| 502 | |||
| 503 | gate_init_volumestream_vtbl(); | ||
| 504 | volumestream->vtbl = &gate_volumestream_vtbl; | ||
| 505 | gate_atomic_int_init(&volumestream->ref_counter, 1); | ||
| 506 | volumestream->writeaccess = writable; | ||
| 507 | if (DeviceIoControl(hvolume, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &bytesreturned, NULL)) | ||
| 508 | { | ||
| 509 | volumestream->is_locked = true; | ||
| 510 | } | ||
| 511 | else | ||
| 512 | { | ||
| 513 | volumestream->is_locked = false; | ||
| 514 | } | ||
| 515 | gate_platform_stream_buffer_init(&volumestream->block_stream, (gate_platform_stream_t)hvolume, | ||
| 516 | volume_length, 0, volume_block_size); | ||
| 517 | |||
| 518 | gate_str_print_text(volumestream->devicepath, sizeof(volumestream->devicepath), | ||
| 519 | volume->uid, gate_str_length_max(volume->uid, sizeof(volume->uid))); | ||
| 520 | |||
| 521 | ret = GATE_RESULT_OK; | ||
| 522 | hvolume = INVALID_HANDLE_VALUE; | ||
| 523 | *stream = (gate_controlstream_t*)volumestream; | ||
| 524 | volumestream = NULL; | ||
| 525 | } while (0); | ||
| 526 | |||
| 527 | if (GATE_FAILED(ret)) | ||
| 528 | { | ||
| 529 | if (volumestream != NULL) | ||
| 530 | { | ||
| 531 | gate_mem_dealloc(volumestream); | ||
| 532 | } | ||
| 533 | |||
| 534 | gate_win32_closehandle(hvolume); | ||
| 535 | } | ||
| 536 | return ret; | ||
| 537 | } | ||
| 538 | |||
| 539 | static void volumestream_release(void* thisptr) | ||
| 540 | { | ||
| 541 | gate_volumestream_t* stream = (gate_volumestream_t*)thisptr; | ||
| 542 | DWORD bytesreturned = 0; | ||
| 543 | |||
| 544 | if (gate_atomic_int_dec(&stream->ref_counter) == 0) | ||
| 545 | { | ||
| 546 | if (stream->is_locked) | ||
| 547 | { | ||
| 548 | DeviceIoControl((HANDLE)stream->block_stream.stream, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0, &bytesreturned, NULL); | ||
| 549 | } | ||
| 550 | gate_platform_stream_close(&stream->block_stream.stream); | ||
| 551 | gate_mem_dealloc(stream); | ||
| 552 | } | ||
| 553 | } | ||
| 554 | |||
| 555 | static int volumestream_retain(void* thisptr) | ||
| 556 | { | ||
| 557 | gate_volumestream_t* stream = (gate_volumestream_t*)thisptr; | ||
| 558 | return gate_atomic_int_inc(&stream->ref_counter); | ||
| 559 | } | ||
| 560 | |||
| 561 | static char const* volumestream_get_interface_name(void* thisptr) | ||
| 562 | { | ||
| 563 | GATE_UNUSED_ARG(thisptr); | ||
| 564 | return GATE_INTERFACE_NAME_CONTROLSTREAM; | ||
| 565 | } | ||
| 566 | |||
| 567 | static gate_result_t volumestream_read(void* thisptr, char* buffer, gate_size_t bufferlength, gate_size_t* returned) | ||
| 568 | { | ||
| 569 | gate_volumestream_t* stream = (gate_volumestream_t*)thisptr; | ||
| 570 | gate_result_t ret = GATE_RESULT_FAILED; | ||
| 571 | |||
| 572 | do | ||
| 573 | { | ||
| 574 | if (stream->writeaccess) | ||
| 575 | { | ||
| 576 | ret = GATE_RESULT_INVALIDSTATE; | ||
| 577 | break; | ||
| 578 | } | ||
| 579 | ret = gate_platform_stream_buffer_read(&stream->block_stream, buffer, bufferlength, returned); | ||
| 580 | } while (0); | ||
| 581 | |||
| 582 | return ret; | ||
| 583 | } | ||
| 584 | |||
| 585 | static gate_result_t volumestream_peek(void* thisptr, char* buffer, gate_size_t bufferlength, gate_size_t* returned) | ||
| 586 | { | ||
| 587 | GATE_UNUSED_ARG(thisptr); | ||
| 588 | GATE_UNUSED_ARG(buffer); | ||
| 589 | GATE_UNUSED_ARG(bufferlength); | ||
| 590 | GATE_UNUSED_ARG(returned); | ||
| 591 | return GATE_RESULT_NOTSUPPORTED; | ||
| 592 | } | ||
| 593 | |||
| 594 | static gate_result_t volumestream_write(void* thisptr, char const* buffer, gate_size_t bufferlength, gate_size_t* written) | ||
| 595 | { | ||
| 596 | gate_volumestream_t* stream = (gate_volumestream_t*)thisptr; | ||
| 597 | gate_result_t ret = GATE_RESULT_FAILED; | ||
| 598 | |||
| 599 | do | ||
| 600 | { | ||
| 601 | if (!stream->writeaccess) | ||
| 602 | { | ||
| 603 | ret = GATE_RESULT_INVALIDSTATE; | ||
| 604 | break; | ||
| 605 | } | ||
| 606 | ret = gate_platform_stream_buffer_write(&stream->block_stream, buffer, bufferlength, written); | ||
| 607 | } while (0); | ||
| 608 | |||
| 609 | return ret; | ||
| 610 | } | ||
| 611 | |||
| 612 | static gate_result_t volumestream_flush(void* thisptr) | ||
| 613 | { | ||
| 614 | gate_result_t ret = GATE_RESULT_OK; | ||
| 615 | gate_volumestream_t* stream = (gate_volumestream_t*)thisptr; | ||
| 616 | if (INVALID_HANDLE_VALUE == (HANDLE)stream->block_stream.stream) | ||
| 617 | { | ||
| 618 | ret = GATE_RESULT_INVALIDSTATE; | ||
| 619 | } | ||
| 620 | else if (FALSE == gate_win32_flushfilebuffers((HANDLE)stream->block_stream.stream)) | ||
| 621 | { | ||
| 622 | GATE_DEBUG_TRACE_PLATFORM_ERROR("FlushFileBuffers() failed"); | ||
| 623 | } | ||
| 624 | return ret; | ||
| 625 | } | ||
| 626 | |||
| 627 | static gate_result_t volumestream_get_resource(void* thisptr, gate_enumint_t resource_type, gate_uintptr_t* resource) | ||
| 628 | { | ||
| 629 | gate_volumestream_t* stream = (gate_volumestream_t*)thisptr; | ||
| 630 | *resource = (gate_uintptr_t)(void*)stream->block_stream.stream; | ||
| 631 | return GATE_RESULT_OK; | ||
| 632 | } | ||
| 633 | |||
| 634 | static gate_result_t volumestream_can_read(void* thisptr, gate_bool_t* return_value) | ||
| 635 | { | ||
| 636 | gate_result_t ret = GATE_RESULT_OK; | ||
| 637 | gate_volumestream_t* stream = (gate_volumestream_t*)thisptr; | ||
| 638 | if (return_value) | ||
| 639 | { | ||
| 640 | *return_value = stream->writeaccess ? false : true; | ||
| 641 | } | ||
| 642 | return ret; | ||
| 643 | } | ||
| 644 | |||
| 645 | static gate_result_t volumestream_can_write(void* thisptr, gate_bool_t* return_value) | ||
| 646 | { | ||
| 647 | gate_result_t ret = GATE_RESULT_OK; | ||
| 648 | gate_volumestream_t* stream = (gate_volumestream_t*)thisptr; | ||
| 649 | if (return_value) | ||
| 650 | { | ||
| 651 | *return_value = stream->writeaccess ? true : false; | ||
| 652 | } | ||
| 653 | return ret; | ||
| 654 | } | ||
| 655 | |||
| 656 | static gate_result_t volumestream_get_size(void* thisptr, gate_int64_t* return_value) | ||
| 657 | { | ||
| 658 | gate_result_t ret = GATE_RESULT_OK; | ||
| 659 | gate_volumestream_t* stream = (gate_volumestream_t*)thisptr; | ||
| 660 | if (stream->block_stream.total_size < 0) | ||
| 661 | { | ||
| 662 | ret = GATE_RESULT_NOTAVAILABLE; | ||
| 663 | } | ||
| 664 | else if (return_value) | ||
| 665 | { | ||
| 666 | *return_value = (gate_int64_t)stream->block_stream.total_size; | ||
| 667 | } | ||
| 668 | return ret; | ||
| 669 | } | ||
| 670 | |||
| 671 | static gate_result_t volumestream_get_available(void* thisptr, gate_int64_t* return_value) | ||
| 672 | { | ||
| 673 | gate_result_t ret = GATE_RESULT_OK; | ||
| 674 | gate_volumestream_t* stream = (gate_volumestream_t*)thisptr; | ||
| 675 | if (stream->block_stream.total_size < 0) | ||
| 676 | { | ||
| 677 | ret = GATE_RESULT_NOTAVAILABLE; | ||
| 678 | } | ||
| 679 | else if (return_value) | ||
| 680 | { | ||
| 681 | *return_value = (gate_int64_t)stream->block_stream.total_size - (gate_int64_t)stream->block_stream.position; | ||
| 682 | } | ||
| 683 | return ret; | ||
| 684 | } | ||
| 685 | |||
| 686 | static gate_result_t volumestream_seek(void* thisptr, gate_int64_t position, gate_enumint_t origin, gate_int64_t* final_position) | ||
| 687 | { | ||
| 688 | gate_volumestream_t* stream = (gate_volumestream_t*)thisptr; | ||
| 689 | int stream_origin; | ||
| 690 | switch (origin) | ||
| 691 | { | ||
| 692 | case GATE_STREAM_SEEK_BEGIN: | ||
| 693 | stream_origin = GATE_PLATFORM_STREAM_ORIGIN_BEGIN; | ||
| 694 | break; | ||
| 695 | case GATE_STREAM_SEEK_CURRENT: | ||
| 696 | stream_origin = GATE_PLATFORM_STREAM_ORIGIN_CURRENT; | ||
| 697 | break; | ||
| 698 | case GATE_STREAM_SEEK_END: | ||
| 699 | stream_origin = GATE_PLATFORM_STREAM_ORIGIN_END; | ||
| 700 | break; | ||
| 701 | default: | ||
| 702 | return GATE_RESULT_INVALIDARG; | ||
| 703 | } | ||
| 704 | |||
| 705 | return gate_platform_stream_buffer_seek(&stream->block_stream, position, stream_origin, final_position); | ||
| 706 | } | ||
| 707 | |||
| 708 | static gate_result_t volumestream_reset(void* thisptr) | ||
| 709 | { | ||
| 710 | GATE_UNUSED_ARG(thisptr); | ||
| 711 | return GATE_RESULT_NOTIMPLEMENTED; | ||
| 712 | } | ||
| 713 | |||
| 714 | static gate_result_t volumestream_close(void* thisptr, gate_enumint_t close_type) | ||
| 715 | { | ||
| 716 | gate_result_t ret = GATE_RESULT_OK; | ||
| 717 | gate_volumestream_t* stream = (gate_volumestream_t*)thisptr; | ||
| 718 | ret = gate_platform_stream_close(&stream->block_stream.stream); | ||
| 719 | return ret; | ||
| 720 | } | ||
| 721 | |||
| 722 | |||
| 723 | #endif /* defined(GATE_SYS_WINCE) */ | ||
| 724 | |||
| 725 | |||
| 726 | #endif /* defined(GATE_SYSTEM_STORAGEVOLUMES_WINAPI_IMPL) */ | ||
| 727 | |||
| 728 | |||
| 729 | #if defined(GATE_SYSTEM_STORAGEVOLUMES_POSIX_IMPL) | ||
| 730 | |||
| 731 | #include "gate/files.h" | ||
| 732 | #include "gate/encode/texts.h" | ||
| 733 | #include <stdio.h> | ||
| 734 | #if defined(GATE_SYS_LINUX) | ||
| 735 | # include <sys/statfs.h> | ||
| 736 | #endif | ||
| 737 | #if defined(GATE_SYS_BSD) | ||
| 738 | # include <sys/types.h> | ||
| 739 | # include <sys/param.h> | ||
| 740 | # include <sys/mount.h> | ||
| 741 | # if defined(GATE_SYS_NETBSD) | ||
| 742 | # define statfs statvfs | ||
| 743 | # endif | ||
| 744 | #endif | ||
| 745 | |||
| 746 | |||
| 747 | |||
| 748 | static char const* const known_internal_fs[] = | ||
| 749 | { | ||
| 750 | "sysfs", | ||
| 751 | "proc", | ||
| 752 | "udev", | ||
| 753 | "devpts", | ||
| 754 | "tmpfs", | ||
| 755 | "securityfs", | ||
| 756 | "cgroup", | ||
| 757 | "pstore", | ||
| 758 | "systemd-1", | ||
| 759 | "mqueue", | ||
| 760 | "debugfs", | ||
| 761 | "hugetlbfs", | ||
| 762 | "fusectl", | ||
| 763 | "binfmt_misc", | ||
| 764 | "gvfsd-fuse", | ||
| 765 | "devtmpfs", | ||
| 766 | "fuse.gvfsd-fuse", | ||
| 767 | "fuse.gvfs-fuse-daemon", | ||
| 768 | "nfsd", | ||
| 769 | "efivarfs", | ||
| 770 | "ramfs", | ||
| 771 | |||
| 772 | "rootfs" | ||
| 773 | }; | ||
| 774 | |||
| 775 | static char const* const known_internal_fs_paths[] = | ||
| 776 | { | ||
| 777 | "/sys/", | ||
| 778 | "/proc/", | ||
| 779 | "/run/", | ||
| 780 | "/var/run/" | ||
| 781 | }; | ||
| 782 | |||
| 783 | static char const* const known_virtual_fs[] = | ||
| 784 | { | ||
| 785 | "aufs", | ||
| 786 | }; | ||
| 787 | |||
| 788 | static char const* const known_network_fs[] = | ||
| 789 | { | ||
| 790 | "cifs", | ||
| 791 | "nfs" | ||
| 792 | }; | ||
| 793 | |||
| 794 | 256 | static gate_bool_t is_in_string_list(char const* const* const str_list, gate_size_t list_count, | |
| 795 | char const* name, gate_size_t namelen) | ||
| 796 | { | ||
| 797 | gate_size_t ndx; | ||
| 798 |
2/2✓ Branch 0 taken 2015 times.
✓ Branch 1 taken 167 times.
|
2182 | for (ndx = 0; ndx != list_count; ++ndx) |
| 799 | { | ||
| 800 |
2/2✓ Branch 2 taken 89 times.
✓ Branch 3 taken 1926 times.
|
2015 | if (gate_str_compare_ic(name, namelen, str_list[ndx], gate_str_length(str_list[ndx])) == 0) |
| 801 | { | ||
| 802 | 89 | return true; | |
| 803 | } | ||
| 804 | } | ||
| 805 | 167 | return false; | |
| 806 | } | ||
| 807 | |||
| 808 | 67 | static gate_bool_t start_with_in_string_list(char const* const* const str_list, gate_size_t list_count, | |
| 809 | char const* name, gate_size_t namelen) | ||
| 810 | { | ||
| 811 | gate_size_t ndx; | ||
| 812 |
2/2✓ Branch 0 taken 225 times.
✓ Branch 1 taken 50 times.
|
275 | for (ndx = 0; ndx != list_count; ++ndx) |
| 813 | { | ||
| 814 |
2/2✓ Branch 2 taken 17 times.
✓ Branch 3 taken 208 times.
|
225 | if (gate_str_starts_with_ic(name, namelen, str_list[ndx], gate_str_length(str_list[ndx]))) |
| 815 | { | ||
| 816 | 17 | return true; | |
| 817 | } | ||
| 818 | } | ||
| 819 | 50 | return false; | |
| 820 | } | ||
| 821 | |||
| 822 | |||
| 823 | /* | ||
| 824 | static Map<String, String> loadDiskLabels() | ||
| 825 | { | ||
| 826 | Map<String, String> ret; | ||
| 827 | Array<String> paths; | ||
| 828 | try { | ||
| 829 | File::findChildren("/dev/disk/by-label", "*", paths, false); | ||
| 830 | } catch(...) { } | ||
| 831 | for(Array<String>::iterator p(paths.begin()), pend(paths.end()); p != pend; ++p) | ||
| 832 | { | ||
| 833 | try { | ||
| 834 | StrToken parent, name; | ||
| 835 | File::parsePath(*p, parent, name); | ||
| 836 | char buffer[1024]; | ||
| 837 | ssize_t len = readlink(p->c_str(), &buffer[0], sizeof(buffer) - 1); | ||
| 838 | if(len > 0) | ||
| 839 | { | ||
| 840 | String devPath(&buffer[0], (size_t)len); | ||
| 841 | if(devPath.beginsWith("../..")) | ||
| 842 | { | ||
| 843 | String tmp; | ||
| 844 | tmp << "/dev" << devPath.subString(5); | ||
| 845 | devPath.swap(tmp); | ||
| 846 | } | ||
| 847 | size_t posEsc = name.indexOf('\\'); | ||
| 848 | if(posEsc == StrToken::npos) | ||
| 849 | { | ||
| 850 | ret.add(devPath, name); | ||
| 851 | } | ||
| 852 | else | ||
| 853 | { | ||
| 854 | String decName; | ||
| 855 | text::unescapeC(name, decName); | ||
| 856 | ret.add(devPath, decName); | ||
| 857 | } | ||
| 858 | } | ||
| 859 | } catch(...) {} | ||
| 860 | } | ||
| 861 | return ret; | ||
| 862 | } | ||
| 863 | |||
| 864 | */ | ||
| 865 | |||
| 866 | /* | ||
| 867 | static Volume loadMountInfo(MountInfo const& info) | ||
| 868 | { | ||
| 869 | static size_t const known_internal_fs_count = sizeof(known_internal_fs) / sizeof(known_internal_fs[0]); | ||
| 870 | static size_t const known_network_fs_count = sizeof(known_network_fs) / sizeof(known_network_fs[0]); | ||
| 871 | static size_t const known_virtual_fs_count = sizeof(known_virtual_fs) / sizeof(known_virtual_fs[0]); | ||
| 872 | static size_t const known_internal_fs_paths_count = sizeof(known_internal_fs_paths) / sizeof(known_internal_fs_paths[0]); | ||
| 873 | |||
| 874 | uint64_t totalSize = 0; | ||
| 875 | uint64_t freeSize = 0; | ||
| 876 | |||
| 877 | String dispName(info.MountPoint); | ||
| 878 | |||
| 879 | loadVolumeStatFs(info.MountPoint, totalSize, freeSize); | ||
| 880 | |||
| 881 | Volume::VolumeType volType = Volume::Volume_Unknown; | ||
| 882 | |||
| 883 | do | ||
| 884 | { | ||
| 885 | for(size_t n = 0; n < known_internal_fs_count; ++n) | ||
| 886 | { | ||
| 887 | if(info.FileSys.equalsIC(known_internal_fs[n])) | ||
| 888 | { | ||
| 889 | volType = Volume::Volume_VirtualInternal; | ||
| 890 | break; | ||
| 891 | } | ||
| 892 | } | ||
| 893 | if(volType != Volume::Volume_Unknown) | ||
| 894 | { | ||
| 895 | break; // skip further tests | ||
| 896 | } | ||
| 897 | |||
| 898 | for(size_t n = 0; n < known_internal_fs_paths_count; ++n) | ||
| 899 | { | ||
| 900 | if(info.MountPoint.beginsWithIC(known_internal_fs_paths[n])) | ||
| 901 | { | ||
| 902 | volType = Volume::Volume_VirtualInternal; | ||
| 903 | break; | ||
| 904 | } | ||
| 905 | } | ||
| 906 | if(volType != Volume::Volume_Unknown) | ||
| 907 | { | ||
| 908 | break; // skip further tests | ||
| 909 | } | ||
| 910 | |||
| 911 | for(size_t n = 0; n < known_virtual_fs_count; ++n) | ||
| 912 | { | ||
| 913 | if(info.FileSys.equalsIC(known_virtual_fs[n])) | ||
| 914 | { | ||
| 915 | volType = Volume::Volume_Virtual; | ||
| 916 | break; | ||
| 917 | } | ||
| 918 | } | ||
| 919 | if(volType != Volume::Volume_Unknown) break; // skip further tests | ||
| 920 | |||
| 921 | for(size_t n = 0; n < known_network_fs_count; ++n) | ||
| 922 | { | ||
| 923 | if(info.FileSys.equalsIC(known_network_fs[n])) | ||
| 924 | { | ||
| 925 | volType = Volume::Volume_Network; | ||
| 926 | break; | ||
| 927 | } | ||
| 928 | } | ||
| 929 | if(volType != Volume::Volume_Unknown) break; // skip further tests | ||
| 930 | |||
| 931 | |||
| 932 | if(info.DeviceName.beginsWith("/dev/")) | ||
| 933 | { | ||
| 934 | // seems to be a real device | ||
| 935 | Map<String, String> labels = loadDiskLabels(); | ||
| 936 | Map<String, String>::iterator l(labels.get(info.DeviceName)); | ||
| 937 | if(l != labels.end()) | ||
| 938 | { | ||
| 939 | String disp(l->second); | ||
| 940 | disp << " (" << dispName << ")"; | ||
| 941 | dispName.swap(disp); | ||
| 942 | } | ||
| 943 | |||
| 944 | StrToken devName = info.DeviceName.subString(5); | ||
| 945 | Array<String> paths; | ||
| 946 | File::findChildren("/sys/class/block", devName, paths, false); | ||
| 947 | if(!paths.empty()) | ||
| 948 | { | ||
| 949 | // it is a block device | ||
| 950 | StrToken basePath(paths[0]); | ||
| 951 | |||
| 952 | |||
| 953 | // if this is a sub-partiation | ||
| 954 | String dataPartition = getPathContent(File::buildPath(basePath, "partition")); | ||
| 955 | dataPartition.trim(); | ||
| 956 | if(!dataPartition.empty()) | ||
| 957 | { | ||
| 958 | if(basePath.endsWith(dataPartition)) | ||
| 959 | { | ||
| 960 | StrToken blockPath = basePath.left(basePath.size() - dataPartition.size()); | ||
| 961 | |||
| 962 | // all block devices should have a dev-entry, | ||
| 963 | String dataDev = getPathContent(File::buildPath(blockPath, "dev")); | ||
| 964 | if(!dataDev.empty()) | ||
| 965 | { | ||
| 966 | // there exists a parent-block-device for our partition block device | ||
| 967 | basePath = blockPath; | ||
| 968 | } | ||
| 969 | } | ||
| 970 | } | ||
| 971 | |||
| 972 | String dataRemovable = getPathContent(File::buildPath(basePath, "removable")); | ||
| 973 | dataRemovable.trim(); | ||
| 974 | if(dataRemovable == "1") | ||
| 975 | { | ||
| 976 | String dataType = getPathContent(File::buildPath(basePath, "device/type")); | ||
| 977 | dataType.trim(); | ||
| 978 | if(dataType == "5") | ||
| 979 | { | ||
| 980 | //CD / DVD usually have this type | ||
| 981 | volType = Volume::Volume_RemovableROM; | ||
| 982 | } | ||
| 983 | else | ||
| 984 | { | ||
| 985 | volType = Volume::Volume_Removable; | ||
| 986 | } | ||
| 987 | } | ||
| 988 | else | ||
| 989 | { | ||
| 990 | volType = Volume::Volume_FixedDisk; | ||
| 991 | } | ||
| 992 | } | ||
| 993 | } | ||
| 994 | } while(0); | ||
| 995 | |||
| 996 | return Volume(info.MountPoint, info.MountPoint, dispName, StrToken(), | ||
| 997 | info.DeviceName, info.DeviceName, totalSize, freeSize, true, volType); | ||
| 998 | } | ||
| 999 | */ | ||
| 1000 | |||
| 1001 | 34 | static gate_bool_t get_parent_dev_path(char const* devname, gate_size_t devname_size, char* buffer, gate_size_t buffersize) | |
| 1002 | { | ||
| 1003 | char block_dev_path[1024]; | ||
| 1004 | char partition_path[1024]; | ||
| 1005 | char part_num[128]; | ||
| 1006 | gate_string_t part_path; | ||
| 1007 | gate_size_t len_path; | ||
| 1008 | gate_size_t len; | ||
| 1009 | gate_result_t result; | ||
| 1010 | |||
| 1011 | 34 | len_path = gate_file_build_path(block_dev_path, sizeof(block_dev_path), "/sys/class/block", 16, devname, devname_size); | |
| 1012 | 34 | len = gate_file_build_path(partition_path, sizeof(partition_path), block_dev_path, len_path, "partition", 9); | |
| 1013 | 34 | part_path.str = partition_path; | |
| 1014 | 34 | part_path.length = len; | |
| 1015 | 34 | part_path.buffer = NULL; | |
| 1016 |
1/2✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
|
34 | if (GATE_RESULT_OK == gate_file_exists(&part_path)) |
| 1017 | { | ||
| 1018 | 34 | len = sizeof(part_num) - 1; | |
| 1019 | 34 | result = gate_file_get_content_buffer(&part_path, &part_num[1], &len); | |
| 1020 |
1/2✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
|
34 | if (GATE_SUCCEEDED(result)) |
| 1021 | { | ||
| 1022 | 34 | part_num[0] = 'p'; | |
| 1023 | 34 | ++len; | |
| 1024 |
1/2✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
|
34 | if (part_num[len - 1] == '\n') |
| 1025 | { | ||
| 1026 | 34 | --len; | |
| 1027 | 34 | part_num[len] = 0; | |
| 1028 | } | ||
| 1029 | 34 | part_num[len] = 0; | |
| 1030 | |||
| 1031 |
1/2✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
|
34 | if (gate_str_ends_with(devname, devname_size, &part_num[1], len - 1)) |
| 1032 | { | ||
| 1033 | 34 | part_path.length = gate_file_build_path(buffer, buffersize, "/dev", 4, devname, devname_size - (len - 1)); | |
| 1034 | 34 | part_path.str = buffer; | |
| 1035 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 34 times.
|
34 | if (GATE_RESULT_OK == gate_file_exists(&part_path)) |
| 1036 | { | ||
| 1037 | ✗ | return true; | |
| 1038 | } | ||
| 1039 | 34 | part_path.length = gate_file_build_path(buffer, buffersize, "/dev", 4, devname, devname_size - len); | |
| 1040 | 34 | part_path.str = buffer; | |
| 1041 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 34 times.
|
34 | if (GATE_RESULT_OK == gate_file_exists(&part_path)) |
| 1042 | { | ||
| 1043 | ✗ | return true; | |
| 1044 | } | ||
| 1045 | } | ||
| 1046 | } | ||
| 1047 | } | ||
| 1048 | 34 | return false; | |
| 1049 | } | ||
| 1050 | 34 | static gate_uint32_t get_volume_type(char const* devname, gate_size_t devname_size) | |
| 1051 | { | ||
| 1052 | char block_dev_path[1024]; | ||
| 1053 | char removable_path[1024]; | ||
| 1054 | char type_path[1024]; | ||
| 1055 | 34 | char removable_num[128] = GATE_INIT_EMPTY; | |
| 1056 | 34 | char type_token[128] = GATE_INIT_EMPTY; | |
| 1057 | gate_size_t len_block; | ||
| 1058 | gate_size_t len; | ||
| 1059 | gate_string_t path; | ||
| 1060 | gate_result_t result; | ||
| 1061 | 34 | len_block = gate_file_build_path(block_dev_path, sizeof(block_dev_path), "/sys/class/block", 16, devname, devname_size); | |
| 1062 | 34 | len = gate_file_build_path(removable_path, sizeof(removable_path), block_dev_path, len_block, "removable", 9); | |
| 1063 | 34 | path.str = removable_path; | |
| 1064 | 34 | path.length = len; | |
| 1065 | 34 | path.buffer = NULL; | |
| 1066 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 34 times.
|
34 | if (GATE_RESULT_OK == gate_file_exists(&path)) |
| 1067 | { | ||
| 1068 | ✗ | len = sizeof(removable_num); | |
| 1069 | ✗ | result = gate_file_get_content_buffer(&path, removable_num, &len); | |
| 1070 | ✗ | if (GATE_SUCCEEDED(result)) | |
| 1071 | { | ||
| 1072 | ✗ | if (removable_num[0] == '1') | |
| 1073 | { | ||
| 1074 | ✗ | path.length = gate_file_build_path(type_path, sizeof(type_path), block_dev_path, len_block, "device/type", 11); | |
| 1075 | ✗ | path.str = type_path; | |
| 1076 | ✗ | if (GATE_RESULT_OK == gate_file_exists(&path)) | |
| 1077 | { | ||
| 1078 | ✗ | len = sizeof(type_token); | |
| 1079 | ✗ | result = gate_file_get_content_buffer(&path, type_token, &len); | |
| 1080 | ✗ | if (GATE_SUCCEEDED(result)) | |
| 1081 | { | ||
| 1082 | ✗ | if (type_token[0] == '5') | |
| 1083 | { | ||
| 1084 | ✗ | return GATE_STORAGEVOLUME_TYPE_REMOVABLEROM; | |
| 1085 | } | ||
| 1086 | } | ||
| 1087 | } | ||
| 1088 | ✗ | return GATE_STORAGEVOLUME_TYPE_REMOVABLEDRIVE; | |
| 1089 | } | ||
| 1090 | } | ||
| 1091 | } | ||
| 1092 | 34 | return GATE_STORAGEVOLUME_TYPE_FIXEDDRIVE; | |
| 1093 | } | ||
| 1094 | |||
| 1095 | 16 | gate_result_t gate_storagevolume_enum(gate_storagevolume_enum_callback_t callback, void* user_param) | |
| 1096 | { | ||
| 1097 | static gate_string_t procfs_mount_path = { "/proc/mounts", 12, NULL }; | ||
| 1098 | 16 | gate_result_t ret = GATE_RESULT_FAILED; | |
| 1099 | char mount_buffer[65536]; | ||
| 1100 | 16 | char line[4096] = GATE_INIT_EMPTY; | |
| 1101 | 16 | gate_size_t mount_buffer_used = sizeof(mount_buffer); | |
| 1102 | 16 | char const* ptr_buffer = &mount_buffer[0]; | |
| 1103 | gate_size_t ptr_buffer_len; | ||
| 1104 | gate_size_t len_parsed; | ||
| 1105 | gate_size_t line_len; | ||
| 1106 | gate_storagevolume_t volume; | ||
| 1107 | char volume_path[1024]; | ||
| 1108 | char mount_path[1024]; | ||
| 1109 | struct statfs fs_stats; | ||
| 1110 | gate_size_t pos; | ||
| 1111 | |||
| 1112 | do | ||
| 1113 | { | ||
| 1114 | 16 | ret = gate_file_get_content_buffer(&procfs_mount_path, mount_buffer, &mount_buffer_used); | |
| 1115 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
|
16 | GATE_BREAK_IF_FAILED(ret); |
| 1116 | |||
| 1117 | 16 | ptr_buffer_len = mount_buffer_used; | |
| 1118 |
2/2✓ Branch 0 taken 156 times.
✓ Branch 1 taken 1 times.
|
157 | while (ptr_buffer_len > 0) |
| 1119 | { | ||
| 1120 | 156 | line_len = sizeof(line) - 1; | |
| 1121 | 156 | len_parsed = gate_str_parse_line(ptr_buffer, ptr_buffer_len, line, &line_len); | |
| 1122 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 156 times.
|
156 | if (len_parsed == 0) |
| 1123 | { | ||
| 1124 | ✗ | break; | |
| 1125 | } | ||
| 1126 | 156 | line[line_len] = 0; | |
| 1127 | |||
| 1128 | 156 | gate_mem_clear(&volume, sizeof(volume)); | |
| 1129 | |||
| 1130 | 156 | sscanf(line, "%s %s %s %s", &volume_path[0], &mount_path[0], &volume.fsname[0], &volume.name[0]); | |
| 1131 | 156 | ptr_buffer += len_parsed; | |
| 1132 | 156 | ptr_buffer_len -= len_parsed; | |
| 1133 | |||
| 1134 | 156 | gate_text_c_unescape_str(mount_path, gate_str_length(mount_path), volume.path, sizeof(volume.path)); | |
| 1135 | |||
| 1136 | 156 | pos = gate_str_char_pos_last(volume_path, gate_str_length(volume_path), '/'); | |
| 1137 |
2/2✓ Branch 0 taken 38 times.
✓ Branch 1 taken 118 times.
|
156 | if (pos != GATE_STR_NPOS) |
| 1138 | { | ||
| 1139 | 76 | gate_str_print_text(volume.devicename, sizeof(volume.devicename), | |
| 1140 | 38 | &volume_path[pos + 1], gate_str_length(&volume_path[pos + 1])); | |
| 1141 | } | ||
| 1142 | else | ||
| 1143 | { | ||
| 1144 | 118 | gate_str_print_text(volume.devicename, sizeof(volume.devicename), | |
| 1145 | volume_path, gate_str_length(volume_path)); | ||
| 1146 | } | ||
| 1147 | |||
| 1148 | 156 | gate_str_print_text(volume.uid, sizeof(volume.uid), volume.path, gate_str_length(volume.path)); | |
| 1149 | 156 | gate_str_print_text(volume.name, sizeof(volume.name), volume.path, gate_str_length(volume.path)); | |
| 1150 | |||
| 1151 |
1/2✓ Branch 1 taken 156 times.
✗ Branch 2 not taken.
|
156 | if (0 == statfs(volume.path, &fs_stats)) |
| 1152 | { | ||
| 1153 | 156 | volume.size = (gate_uint64_t)fs_stats.f_blocks * (gate_uint64_t)fs_stats.f_bsize; | |
| 1154 | 156 | volume.sizefree = (gate_uint64_t)fs_stats.f_bfree * (gate_uint64_t)fs_stats.f_bsize; | |
| 1155 | 156 | volume.sizeused = volume.size - volume.sizefree; | |
| 1156 | } | ||
| 1157 | |||
| 1158 | |||
| 1159 |
2/2✓ Branch 2 taken 89 times.
✓ Branch 3 taken 67 times.
|
156 | if (is_in_string_list(known_internal_fs, sizeof(known_internal_fs) / sizeof(known_internal_fs[0]), |
| 1160 | volume.fsname, gate_str_length(volume.fsname))) | ||
| 1161 | { | ||
| 1162 | 89 | volume.volumetype = GATE_STORAGEVOLUME_TYPE_SYSTEMPRIVATE; | |
| 1163 | 89 | continue; | |
| 1164 | } | ||
| 1165 |
2/2✓ Branch 2 taken 17 times.
✓ Branch 3 taken 50 times.
|
67 | if (start_with_in_string_list(known_internal_fs_paths, |
| 1166 | sizeof(known_internal_fs_paths) / sizeof(known_internal_fs_paths[0]), | ||
| 1167 | volume.path, gate_str_length(volume.path))) | ||
| 1168 | { | ||
| 1169 | 17 | volume.volumetype = GATE_STORAGEVOLUME_TYPE_SYSTEMPRIVATE; | |
| 1170 | 17 | continue; | |
| 1171 | } | ||
| 1172 | |||
| 1173 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 50 times.
|
50 | if (is_in_string_list(known_virtual_fs, sizeof(known_virtual_fs) / sizeof(known_virtual_fs[0]), |
| 1174 | volume.fsname, gate_str_length(volume.fsname))) | ||
| 1175 | { | ||
| 1176 | ✗ | volume.volumetype = GATE_STORAGEVOLUME_TYPE_SYSTEM; | |
| 1177 | } | ||
| 1178 | |||
| 1179 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 50 times.
|
50 | if (is_in_string_list(known_network_fs, sizeof(known_network_fs) / sizeof(known_network_fs[0]), |
| 1180 | volume.fsname, gate_str_length(volume.fsname))) | ||
| 1181 | { | ||
| 1182 | ✗ | volume.volumetype = GATE_STORAGEVOLUME_TYPE_NETWORKDRIVE; | |
| 1183 | } | ||
| 1184 | |||
| 1185 |
2/2✓ Branch 1 taken 34 times.
✓ Branch 2 taken 16 times.
|
50 | if (gate_str_compare(volume_path, 5, "/dev/", 5) == 0) |
| 1186 | { | ||
| 1187 | 34 | get_parent_dev_path(&volume_path[5], gate_str_length(&volume_path[5]), | |
| 1188 | volume.devicepath, sizeof(volume.devicepath)); | ||
| 1189 | 34 | volume.volumetype = get_volume_type(&volume_path[5], gate_str_length(&volume_path[5])); | |
| 1190 | } | ||
| 1191 | else | ||
| 1192 | { | ||
| 1193 | } | ||
| 1194 | |||
| 1195 |
2/2✓ Branch 1 taken 15 times.
✓ Branch 2 taken 35 times.
|
50 | if (!callback(&volume, user_param)) |
| 1196 | { | ||
| 1197 | 15 | break; | |
| 1198 | } | ||
| 1199 | } | ||
| 1200 | } while (0); | ||
| 1201 | |||
| 1202 | 16 | return ret; | |
| 1203 | } | ||
| 1204 | ✗ | gate_result_t gate_storagevolume_openstream(gate_storagevolume_t const* volume, gate_enumint_t open_flags, gate_controlstream_t** stream) | |
| 1205 | { | ||
| 1206 | ✗ | gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED; | |
| 1207 | |||
| 1208 | ✗ | return ret; | |
| 1209 | } | ||
| 1210 | |||
| 1211 | |||
| 1212 | #endif /* defined(GATE_SYSTEM_STORAGEVOLUMES_POSIX_IMPL) */ | ||
| 1213 | |||
| 1214 | |||
| 1215 | |||
| 1216 | #if defined(GATE_SYSTEM_STORAGEVOLUMES_NO_IMPL) | ||
| 1217 | |||
| 1218 | gate_result_t gate_storagevolume_enum(gate_storagevolume_enum_callback_t callback, void* user_param) | ||
| 1219 | { | ||
| 1220 | (void)callback; | ||
| 1221 | (void)user_param; | ||
| 1222 | return GATE_RESULT_NOTIMPLEMENTED; | ||
| 1223 | } | ||
| 1224 | gate_result_t gate_storagevolume_openstream(gate_storagevolume_t const* drive, gate_enumint_t open_flags, gate_controlstream_t** stream) | ||
| 1225 | { | ||
| 1226 | (void)drive; | ||
| 1227 | (void)open_flags; | ||
| 1228 | (void)stream; | ||
| 1229 | return GATE_RESULT_NOTIMPLEMENTED; | ||
| 1230 | } | ||
| 1231 | |||
| 1232 | |||
| 1233 | #endif /* GATE_SYSTEM_STORAGEVOLUMES_NO_IMPL */ | ||
| 1234 | |||
| 1235 |