GCC Code Coverage Report


Directory: src/gate/
File: src/gate/system/storagevolumes.c
Date: 2025-09-14 13:10:38
Exec Total Coverage
Lines: 0 145 0.0%
Functions: 0 9 0.0%
Branches: 0 68 0.0%

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 static gate_bool_t gate_storagevolume_find_callback(gate_storagevolume_t const* volume, void* user_param)
84 {
85 struct gate_storagevolume_find_param* param = (struct gate_storagevolume_find_param*)user_param;
86 gate_bool_t is_matching = false;
87 switch (param->field_type)
88 {
89 case GATE_STORAGEVOLUME_PATH:
90 {
91 is_matching = 0 == gate_str_compare(param->field_value->str, param->field_value->length,
92 volume->path, gate_str_length(volume->path));
93 break;
94 }
95 case GATE_STORAGEVOLUME_UID:
96 {
97 is_matching = 0 == gate_str_compare(param->field_value->str, param->field_value->length,
98 volume->uid, gate_str_length(volume->uid));
99 break;
100 }
101 case GATE_STORAGEVOLUME_NAME:
102 {
103 is_matching = 0 == gate_str_compare(param->field_value->str, param->field_value->length,
104 volume->name, gate_str_length(volume->name));
105 break;
106 }
107 }
108
109 if (is_matching)
110 {
111 param->found = true;
112 gate_mem_copy(param->target_volume, volume, sizeof(gate_storagevolume_t));
113 return false; /* cancel enumeration */
114 }
115 else
116 {
117 return true; /* continue enumeration */
118 }
119 }
120
121 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 param.field_type = field_type;
125 param.field_value = field;
126 param.found = false;
127 param.target_volume = volume;
128
129 return gate_storagevolume_enum(&gate_storagevolume_find_callback, &param);
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, &sectorsPerCluster, &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 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 for (ndx = 0; ndx != list_count; ++ndx)
799 {
800 if (gate_str_compare_ic(name, namelen, str_list[ndx], gate_str_length(str_list[ndx])) == 0)
801 {
802 return true;
803 }
804 }
805 return false;
806 }
807
808 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 for (ndx = 0; ndx != list_count; ++ndx)
813 {
814 if (gate_str_starts_with_ic(name, namelen, str_list[ndx], gate_str_length(str_list[ndx])))
815 {
816 return true;
817 }
818 }
819 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 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 len_path = gate_file_build_path(block_dev_path, sizeof(block_dev_path), "/sys/class/block", 16, devname, devname_size);
1012 len = gate_file_build_path(partition_path, sizeof(partition_path), block_dev_path, len_path, "partition", 9);
1013 part_path.str = partition_path;
1014 part_path.length = len;
1015 part_path.buffer = NULL;
1016 if (GATE_RESULT_OK == gate_file_exists(&part_path))
1017 {
1018 len = sizeof(part_num) - 1;
1019 result = gate_file_get_content_buffer(&part_path, &part_num[1], &len);
1020 if (GATE_SUCCEEDED(result))
1021 {
1022 part_num[0] = 'p';
1023 ++len;
1024 if (part_num[len - 1] == '\n')
1025 {
1026 --len;
1027 part_num[len] = 0;
1028 }
1029 part_num[len] = 0;
1030
1031 if (gate_str_ends_with(devname, devname_size, &part_num[1], len - 1))
1032 {
1033 part_path.length = gate_file_build_path(buffer, buffersize, "/dev", 4, devname, devname_size - (len - 1));
1034 part_path.str = buffer;
1035 if (GATE_RESULT_OK == gate_file_exists(&part_path))
1036 {
1037 return true;
1038 }
1039 part_path.length = gate_file_build_path(buffer, buffersize, "/dev", 4, devname, devname_size - len);
1040 part_path.str = buffer;
1041 if (GATE_RESULT_OK == gate_file_exists(&part_path))
1042 {
1043 return true;
1044 }
1045 }
1046 }
1047 }
1048 return false;
1049 }
1050 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 char removable_num[128] = GATE_INIT_EMPTY;
1056 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 len_block = gate_file_build_path(block_dev_path, sizeof(block_dev_path), "/sys/class/block", 16, devname, devname_size);
1062 len = gate_file_build_path(removable_path, sizeof(removable_path), block_dev_path, len_block, "removable", 9);
1063 path.str = removable_path;
1064 path.length = len;
1065 path.buffer = NULL;
1066 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 return GATE_STORAGEVOLUME_TYPE_FIXEDDRIVE;
1093 }
1094
1095 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 gate_result_t ret = GATE_RESULT_FAILED;
1099 char mount_buffer[65536];
1100 char line[4096] = GATE_INIT_EMPTY;
1101 gate_size_t mount_buffer_used = sizeof(mount_buffer);
1102 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 ret = gate_file_get_content_buffer(&procfs_mount_path, mount_buffer, &mount_buffer_used);
1115 GATE_BREAK_IF_FAILED(ret);
1116
1117 ptr_buffer_len = mount_buffer_used;
1118 while (ptr_buffer_len > 0)
1119 {
1120 line_len = sizeof(line) - 1;
1121 len_parsed = gate_str_parse_line(ptr_buffer, ptr_buffer_len, line, &line_len);
1122 if (len_parsed == 0)
1123 {
1124 break;
1125 }
1126 line[line_len] = 0;
1127
1128 gate_mem_clear(&volume, sizeof(volume));
1129
1130 sscanf(line, "%s %s %s %s", &volume_path[0], &mount_path[0], &volume.fsname[0], &volume.name[0]);
1131 ptr_buffer += len_parsed;
1132 ptr_buffer_len -= len_parsed;
1133
1134 gate_text_c_unescape_str(mount_path, gate_str_length(mount_path), volume.path, sizeof(volume.path));
1135
1136 pos = gate_str_char_pos_last(volume_path, gate_str_length(volume_path), '/');
1137 if (pos != GATE_STR_NPOS)
1138 {
1139 gate_str_print_text(volume.devicename, sizeof(volume.devicename),
1140 &volume_path[pos + 1], gate_str_length(&volume_path[pos + 1]));
1141 }
1142 else
1143 {
1144 gate_str_print_text(volume.devicename, sizeof(volume.devicename),
1145 volume_path, gate_str_length(volume_path));
1146 }
1147
1148 gate_str_print_text(volume.uid, sizeof(volume.uid), volume.path, gate_str_length(volume.path));
1149 gate_str_print_text(volume.name, sizeof(volume.name), volume.path, gate_str_length(volume.path));
1150
1151 if (0 == statfs(volume.path, &fs_stats))
1152 {
1153 volume.size = (gate_uint64_t)fs_stats.f_blocks * (gate_uint64_t)fs_stats.f_bsize;
1154 volume.sizefree = (gate_uint64_t)fs_stats.f_bfree * (gate_uint64_t)fs_stats.f_bsize;
1155 volume.sizeused = volume.size - volume.sizefree;
1156 }
1157
1158
1159 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 volume.volumetype = GATE_STORAGEVOLUME_TYPE_SYSTEMPRIVATE;
1163 continue;
1164 }
1165 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 volume.volumetype = GATE_STORAGEVOLUME_TYPE_SYSTEMPRIVATE;
1170 continue;
1171 }
1172
1173 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 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 if (gate_str_compare(volume_path, 5, "/dev/", 5) == 0)
1186 {
1187 get_parent_dev_path(&volume_path[5], gate_str_length(&volume_path[5]),
1188 volume.devicepath, sizeof(volume.devicepath));
1189 volume.volumetype = get_volume_type(&volume_path[5], gate_str_length(&volume_path[5]));
1190 }
1191 else
1192 {
1193 }
1194
1195 if (!callback(&volume, user_param))
1196 {
1197 break;
1198 }
1199 }
1200 } while (0);
1201
1202 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