GCC Code Coverage Report


Directory: src/gate/
File: src/gate/system/storagedrives.c
Date: 2026-05-04 21:11:01
Exec Total Coverage
Lines: 90 243 37.0%
Functions: 5 23 21.7%
Branches: 29 105 27.6%

Line Branch Exec Source
1 /* GATE PROJECT LICENSE:
2 +----------------------------------------------------------------------------+
3 | Copyright (c) 2018-2026, Stefan Meislinger <sm@opengate.at> |
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/storagedrives.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_STORAGEDRIVES_WINAPI_IMPL 1
35 #elif defined(GATE_SYS_POSIX)
36 # define GATE_SYSTEM_STORAGEDRIVES_POSIX_IMPL 1
37 #elif defined(GATE_SYS_DOS)
38 # define GATE_SYSTEM_STORAGEDRIVES_DOS_IMPL 1
39 #else
40 # define GATE_SYSTEM_STORAGEDRIVES_NO_IMPL 1
41 #endif
42
43
44 struct gate_storagedrive_find_param
45 {
46 gate_string_t const* field;
47 gate_uint32_t field_type;
48 gate_storagedrive_t* drive;
49 gate_bool_t found;
50 };
51
52 9 static gate_bool_t GATE_CALL gate_storagedrive_find_callback(gate_storagedrive_t const* drive, void* user_param)
53 {
54 9 struct gate_storagedrive_find_param* const param = (struct gate_storagedrive_find_param*)user_param;
55 9 gate_bool_t match = false;
56
57
3/5
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
9 switch (param->field_type)
58 {
59 3 case GATE_STORAGEDRIVE_PATH:
60 {
61 3 gate_size_t const length = gate_str_length(drive->path);
62
3/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 1 times.
3 match = ((length > 0) && (0 == gate_str_compare_ic(drive->path, length, param->field->str, param->field->length)));
63 3 break;
64 }
65 3 case GATE_STORAGEDRIVE_UID:
66 {
67 3 gate_size_t const length = gate_str_length(drive->uid);
68
3/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 1 times.
3 match = ((length > 0) && (0 == gate_str_compare_ic(drive->uid, length, param->field->str, param->field->length)));
69 3 break;
70 }
71 3 case GATE_STORAGEDRIVE_NAME:
72 {
73 3 gate_size_t const length = gate_str_length(drive->name);
74
3/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 1 times.
3 match = ((length > 0) && (0 == gate_str_compare_ic(drive->name, length, param->field->str, param->field->length)));
75 3 break;
76 }
77 case GATE_STORAGEDRIVE_DEVICEPATH:
78 {
79 gate_size_t const length = gate_str_length(drive->devicepath);
80 match = ((length > 0) && (0 == gate_str_compare_ic(drive->devicepath, length, param->field->str, param->field->length)));
81 break;
82 }
83 }
84
85
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 3 times.
9 if (match)
86 {
87 6 gate_mem_copy(param->drive, drive, sizeof(gate_storagedrive_t));
88 6 param->found = true;
89 6 return false;
90 }
91 3 return true;
92
93 }
94
95 6 gate_result_t gate_storagedrive_find(gate_string_t const* field, gate_uint32_t field_type, gate_storagedrive_t* drive)
96 {
97 struct gate_storagedrive_find_param param;
98 6 param.field = field;
99 6 param.field_type = field_type;
100 6 param.drive = drive;
101 6 param.found = false;
102
103 6 gate_storagedrive_enum(GATE_STORAGEDRIVE_TYPE_ALL, &gate_storagedrive_find_callback, &param);
104
105
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (param.found)
106 {
107 6 return GATE_RESULT_OK;
108 }
109 return GATE_RESULT_NOMATCH;
110 }
111
112
113
114
115 #if defined(GATE_SYSTEM_STORAGEDRIVES_WINAPI_IMPL)
116
117 #include "gate/platforms.h"
118 #include "gate/debugging.h"
119 #include "gate/system/storagevolumes.h"
120
121 #if defined(GATE_SYS_WINCE)
122
123 gate_result_t gate_storagedrive_enum(gate_enumint_t drivetype, gate_storagedrive_enum_callback_t callback, void* user_param)
124 {
125 GATE_UNUSED_ARG(drivetype);
126 GATE_UNUSED_ARG(callback);
127 GATE_UNUSED_ARG(user_param);
128 return GATE_RESULT_NOTSUPPORTED;
129 }
130 gate_result_t gate_storagedrive_openstream(gate_storagedrive_t const* drive, gate_enumint_t open_flags, gate_controlstream_t** stream)
131 {
132 GATE_UNUSED_ARG(drive);
133 GATE_UNUSED_ARG(open_flags);
134 GATE_UNUSED_ARG(stream);
135 return GATE_RESULT_NOTSUPPORTED;
136 }
137
138 gate_result_t gate_storagedrive_queryattribs(gate_storagedrive_t const* drive, gate_enumint_t attrib_type,
139 gate_storagedrive_attribs_callback_t callback, void* user_param)
140 {
141 GATE_UNUSED_ARG(drive);
142 GATE_UNUSED_ARG(attrib_type);
143 GATE_UNUSED_ARG(callback);
144 GATE_UNUSED_ARG(user_param);
145 return GATE_RESULT_NOTSUPPORTED;
146 }
147
148 #else /* defined(GATE_SYS_WINCE) */
149
150 #include "gate/system/platform/storage_winapi.h"
151
152 /*#include <setupapi.h>*/
153
154
155 static const GUID gate_GUID_DEVINTERFACE_DISK = { 0x53f56307L, 0xb6bf, 0x11d0, { 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b } };
156 static const GUID gate_GUID_DEVINTERFACE_CDROM = { 0x53f56308L, 0xb6bf, 0x11d0, { 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b } };
157 static const GUID gate_GUID_DEVINTERFACE_FLOPPY = { 0x53f56311L, 0xb6bf, 0x11d0, { 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b } };
158
159
160
161 struct gate_storagedrive_device_enum_param
162 {
163 gate_storagedrive_enum_callback_t callback;
164 void* user_param;
165 };
166
167 static gate_bool_t gate_storagedrive_load_geometry(HANDLE hdevice, gate_storagedrive_t* ptr_drive)
168 {
169 BYTE buffer[8192 + 4096];
170 GATE_DISK_GEOMETRY_EX* ptrgeometry = (GATE_DISK_GEOMETRY_EX*)&buffer[0];
171 DWORD reqsize = 0;
172
173 if (FALSE != DeviceIoControl(hdevice, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, 0, ptrgeometry, sizeof(buffer), &reqsize, NULL))
174 {
175 ptr_drive->blockcount = (gate_uint64_t)ptrgeometry->Geometry.Cylinders.QuadPart
176 * (gate_uint64_t)ptrgeometry->Geometry.TracksPerCylinder
177 * (gate_uint64_t)ptrgeometry->Geometry.SectorsPerTrack
178 ;
179 ptr_drive->blocksize = (gate_uint64_t)ptrgeometry->Geometry.BytesPerSector;
180 ptr_drive->size = (gate_uint64_t)ptrgeometry->DiskSize.QuadPart;
181 return true;
182 }
183 else if (FALSE != DeviceIoControl(hdevice, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, ptrgeometry, sizeof(buffer), &reqsize, NULL))
184 {
185 ptr_drive->blockcount = (gate_uint64_t)ptrgeometry->Geometry.Cylinders.QuadPart
186 * (gate_uint64_t)ptrgeometry->Geometry.TracksPerCylinder
187 * (gate_uint64_t)ptrgeometry->Geometry.SectorsPerTrack
188 ;
189 ptr_drive->blocksize = (gate_uint64_t)ptrgeometry->Geometry.BytesPerSector;
190 ptr_drive->size = ptr_drive->blockcount * ptr_drive->blocksize;
191 return true;
192 }
193 return false;
194 }
195
196 static gate_bool_t gate_storagedrive_load_device_properties(HANDLE hdevice, gate_storagedrive_t* ptr_drive)
197 {
198 BYTE buffer[8192 + 4096];
199 DWORD reqsize = 0;
200 GATE_STORAGE_DEVICE_DESCRIPTOR* storedescr;
201 GATE_STORAGE_PROPERTY_QUERY propquery;
202
203 gate_mem_clear(buffer, sizeof(buffer));
204 storedescr = (GATE_STORAGE_DEVICE_DESCRIPTOR*)&buffer[0];
205 storedescr->Size = sizeof(buffer);
206
207 propquery.PropertyId = GateStorageDeviceProperty;
208 propquery.QueryType = GatePropertyStandardQuery;
209 propquery.AdditionalParameters[0] = 0;
210
211 if (FALSE != DeviceIoControl(hdevice, IOCTL_STORAGE_QUERY_PROPERTY, &propquery, sizeof(propquery), storedescr, (DWORD)storedescr->Size, &reqsize, NULL))
212 {
213 if (storedescr->SerialNumberOffset > 0)
214 {
215 if (storedescr->SerialNumberOffset < storedescr->Size)
216 {
217 gate_str_print_text(ptr_drive->serial, sizeof(ptr_drive->serial),
218 (char const*)&buffer[storedescr->SerialNumberOffset],
219 gate_str_length((char const*)&buffer[storedescr->SerialNumberOffset]));
220 }
221 }
222 if (storedescr->VendorIdOffset)
223 {
224 if (storedescr->VendorIdOffset < storedescr->Size)
225 {
226 gate_str_print_text(ptr_drive->vendor, sizeof(ptr_drive->vendor),
227 (char const*)&buffer[storedescr->VendorIdOffset],
228 gate_str_length((char const*)&buffer[storedescr->VendorIdOffset]));
229 }
230 }
231 if (storedescr->ProductIdOffset)
232 {
233 if (storedescr->ProductIdOffset < storedescr->Size)
234 {
235 gate_str_print_text(ptr_drive->productname, sizeof(ptr_drive->productname),
236 (char const*)&buffer[storedescr->ProductIdOffset],
237 gate_str_length((char const*)&buffer[storedescr->ProductIdOffset]));
238 }
239 }
240 return true;
241 }
242 return false;
243 }
244
245
246 static gate_bool_t gate_storagedrive_device_enum_standard_cb(LPCTSTR device_path, LPCTSTR friendly_name, void* user_param)
247 {
248 struct gate_storagedrive_device_enum_param* param = (struct gate_storagedrive_device_enum_param*)user_param;
249 gate_size_t len;
250 gate_storagedrive_t drive = GATE_INIT_EMPTY;
251 HANDLE hdisk;
252 DWORD reqsize = 0;
253 GATE_STORAGE_DEVICE_NUMBER storedevnum;
254
255 do
256 {
257 drive.drivetype = GATE_STORAGEDRIVE_TYPE_STANDARD;
258 len = gate_win32_winstr_length(device_path);
259 gate_win32_winstr_2_utf8(device_path, len, &drive.path[0], sizeof(drive.path));
260 gate_win32_winstr_2_utf8(device_path, len, &drive.devicepath[0], sizeof(drive.devicepath));
261 gate_win32_winstr_2_utf8(friendly_name, gate_win32_winstr_length(friendly_name), &drive.name[0], sizeof(drive.name));
262
263 hdisk = gate_win32_createfile(device_path, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, OPEN_EXISTING, 0, 0, NULL);
264 /* hdisk = CreateFile(device_path, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); */
265 if (INVALID_HANDLE_VALUE == hdisk)
266 {
267 continue;
268 }
269
270 if (DeviceIoControl(hdisk, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &storedevnum, sizeof(storedevnum), &reqsize, NULL))
271 {
272 gate_str_print_text(drive.uid, sizeof(drive.uid), "\\\\.\\PhysicalDrive", 17);
273 gate_str_print_uint32(&drive.uid[17], sizeof(drive.uid) - 17, storedevnum.DeviceNumber);
274 drive.deviceindex = (gate_uint32_t)storedevnum.DeviceNumber;
275 }
276
277 gate_storagedrive_load_geometry(hdisk, &drive);
278
279 gate_storagedrive_load_device_properties(hdisk, &drive);
280
281 } while (0);
282
283 gate_win32_closehandle(hdisk);
284
285 if (param->callback != NULL)
286 {
287 return param->callback(&drive, param->user_param);
288 }
289 else
290 {
291 return true;
292 }
293 }
294
295 static gate_bool_t gate_storagedrive_device_enum_cdrom_cb(LPCTSTR device_path, LPCTSTR friendly_name, void* user_param)
296 {
297 struct gate_storagedrive_device_enum_param* param = (struct gate_storagedrive_device_enum_param*)user_param;
298 gate_size_t len;
299 gate_storagedrive_t drive = GATE_INIT_EMPTY;
300 HANDLE hdisk;
301 DWORD reqsize = 0;
302 GATE_STORAGE_DEVICE_NUMBER storedevnum;
303
304 do
305 {
306 drive.drivetype = GATE_STORAGEDRIVE_TYPE_ROM;
307 len = gate_win32_winstr_length(device_path);
308 gate_win32_winstr_2_utf8(device_path, len, &drive.path[0], sizeof(drive.path));
309 gate_win32_winstr_2_utf8(device_path, len, &drive.devicepath[0], sizeof(drive.devicepath));
310 gate_win32_winstr_2_utf8(friendly_name, gate_win32_winstr_length(friendly_name), &drive.name[0], sizeof(drive.name));
311
312 hdisk = gate_win32_createfile(device_path, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, OPEN_EXISTING, 0, 0, NULL);
313 /* hdisk = CreateFile(device_path, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); */
314 if (INVALID_HANDLE_VALUE == hdisk)
315 {
316 continue;
317 }
318
319 if (DeviceIoControl(hdisk, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &storedevnum, sizeof(storedevnum), &reqsize, NULL))
320 {
321 gate_str_print_text(drive.uid, sizeof(drive.uid), "\\\\.\\CdRom", 9);
322 gate_str_print_uint32(&drive.uid[9], sizeof(drive.uid) - 9, storedevnum.DeviceNumber);
323 drive.deviceindex = (gate_uint32_t)storedevnum.DeviceNumber;
324 }
325
326 gate_storagedrive_load_geometry(hdisk, &drive);
327
328 gate_storagedrive_load_device_properties(hdisk, &drive);
329
330 } while (0);
331
332 gate_win32_closehandle(hdisk);
333
334 if (param->callback != NULL)
335 {
336 return param->callback(&drive, param->user_param);
337 }
338 else
339 {
340 return true;
341 }
342 }
343
344 static gate_bool_t gate_storagedrive_device_enum_floppy_cb(LPCTSTR device_path, LPCTSTR friendly_name, void* user_param)
345 {
346 struct gate_storagedrive_device_enum_param* param = (struct gate_storagedrive_device_enum_param*)user_param;
347 gate_size_t len;
348 gate_storagedrive_t drive = GATE_INIT_EMPTY;
349 HANDLE hdisk;
350 /*
351 DWORD reqsize = 0;
352 GATE_STORAGE_DEVICE_NUMBER storedevnum;
353 */
354
355 do
356 {
357 drive.drivetype = GATE_STORAGEDRIVE_TYPE_REMOVABLE;
358 len = gate_win32_winstr_length(device_path);
359 gate_win32_winstr_2_utf8(device_path, len, &drive.path[0], sizeof(drive.path));
360 gate_win32_winstr_2_utf8(device_path, len, &drive.devicepath[0], sizeof(drive.devicepath));
361 gate_win32_winstr_2_utf8(device_path, len, &drive.uid[0], sizeof(drive.uid));
362 gate_win32_winstr_2_utf8(friendly_name, gate_win32_winstr_length(friendly_name), &drive.name[0], sizeof(drive.name));
363
364 hdisk = gate_win32_createfile(device_path, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, OPEN_EXISTING, 0, 0, NULL);
365 /* hdisk = CreateFile(device_path, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); */
366 if (INVALID_HANDLE_VALUE == hdisk)
367 {
368 continue;
369 }
370
371 /*
372 if(DeviceIoControl(hdisk, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &storedevnum, sizeof(storedevnum), &reqsize, NULL))
373 {
374 gate_str_print_text(drive.uid, sizeof(drive.uid), "\\\\.\\Floppy", 10);
375 gate_str_print_uint32(&drive.uid[10], sizeof(drive.uid) - 10, storedevnum.DeviceNumber);
376 drive.deviceindex = (gate_uint32_t)storedevnum.DeviceNumber;
377 }
378 */
379
380 gate_storagedrive_load_geometry(hdisk, &drive);
381
382 gate_storagedrive_load_device_properties(hdisk, &drive);
383
384 } while (0);
385
386 gate_win32_closehandle(hdisk);
387
388 if (param->callback != NULL)
389 {
390 return param->callback(&drive, param->user_param);
391 }
392 else
393 {
394 return true;
395 }
396 }
397
398
399 gate_result_t gate_storagedrive_enum(gate_enumint_t drivetype, gate_storagedrive_enum_callback_t callback, void* user_param)
400 {
401 gate_result_t ret = GATE_RESULT_NOMATCH;
402
403 struct gate_storagedrive_device_enum_param param;
404
405 do
406 {
407 param.callback = callback;
408 param.user_param = user_param;
409
410 if ((drivetype == GATE_STORAGEDRIVE_TYPE_ALL) || GATE_FLAG_ENABLED(drivetype, GATE_STORAGEDRIVE_TYPE_STANDARD))
411 {
412 ret = gate_win32_device_enum(&gate_GUID_DEVINTERFACE_DISK, &gate_storagedrive_device_enum_standard_cb, &param);
413 GATE_BREAK_IF_FAILED(ret);
414 }
415
416 if ((drivetype == GATE_STORAGEDRIVE_TYPE_ALL) || GATE_FLAG_ENABLED(drivetype, GATE_STORAGEDRIVE_TYPE_ROM))
417 {
418 ret = gate_win32_device_enum(&gate_GUID_DEVINTERFACE_CDROM, &gate_storagedrive_device_enum_cdrom_cb, &param);
419 GATE_BREAK_IF_FAILED(ret);
420 }
421
422 if ((drivetype == GATE_STORAGEDRIVE_TYPE_ALL) || GATE_FLAG_ENABLED(drivetype, GATE_STORAGEDRIVE_TYPE_REMOVABLE))
423 {
424 ret = gate_win32_device_enum(&gate_GUID_DEVINTERFACE_FLOPPY, &gate_storagedrive_device_enum_floppy_cb, &param);
425 GATE_BREAK_IF_FAILED(ret);
426 }
427
428 } while (0);
429
430 return ret;
431 }
432
433
434
435 static void drivestream_release(void* thisptr);
436 static int drivestream_retain(void* thisptr);
437 static char const* drivestream_get_interface_name(void* thisptr);
438
439 static gate_result_t drivestream_read(void* thisptr, char* buffer, gate_size_t bufferlength, gate_size_t* returned);
440 static gate_result_t drivestream_peek(void* thisptr, char* buffer, gate_size_t bufferlength, gate_size_t* returned);
441 static gate_result_t drivestream_write(void* thisptr, char const* buffer, gate_size_t bufferlength, gate_size_t* written);
442 static gate_result_t drivestream_flush(void* thisptr);
443
444 static gate_result_t drivestream_get_resource(void* thisptr, gate_enumint_t resource_type, gate_uintptr_t* resource);
445
446 static gate_result_t drivestream_can_read(void* thisptr, gate_bool_t* return_value);
447 static gate_result_t drivestream_can_write(void* thisptr, gate_bool_t* return_value);
448 static gate_result_t drivestream_get_size(void* thisptr, gate_int64_t* return_value);
449 static gate_result_t drivestream_get_available(void* thisptr, gate_int64_t* return_value);
450 static gate_result_t drivestream_seek(void* thisptr, gate_int64_t position, gate_enumint_t origin, gate_int64_t* final_position);
451 static gate_result_t drivestream_reset(void* thisptr);
452 static gate_result_t drivestream_close(void* thisptr, gate_enumint_t close_type);
453
454 static GATE_INTERFACE_VTBL(gate_controlstream) gate_drivestream_vtbl;
455 static void gate_init_drivestream_vtbl()
456 {
457 if (!gate_drivestream_vtbl.get_interface_name)
458 {
459 GATE_INTERFACE_VTBL(gate_controlstream) const local_vtbl =
460 {
461 &drivestream_get_interface_name,
462 &drivestream_release,
463 &drivestream_retain,
464
465 &drivestream_read,
466 &drivestream_peek,
467 &drivestream_write,
468 &drivestream_flush,
469
470 &drivestream_get_resource,
471
472 &drivestream_can_read,
473 &drivestream_can_write,
474 &drivestream_get_size,
475 &drivestream_get_available,
476 &drivestream_seek,
477 &drivestream_reset,
478 &drivestream_close
479 };
480 gate_drivestream_vtbl = local_vtbl;
481 }
482 }
483 typedef struct gate_drivestream_class
484 {
485 GATE_INTERFACE_VTBL(gate_controlstream) const* vtbl;
486
487 gate_atomic_int_t ref_counter;
488 gate_bool_t writeaccess;
489 gate_size_t locked_handle_count;
490 HANDLE locked_handles[128];
491 char devicepath[256];
492
493 gate_platform_stream_buffer_t block_stream;
494 } gate_drivestream_t;
495
496 static gate_bool_t gate_storagedrive_volume_cb(gate_storagevolume_t const* volume, void* user_param)
497 {
498 gate_drivestream_t* drivestream = (gate_drivestream_t*)user_param;
499 HANDLE handle;
500 TCHAR volume_uid[128];
501 gate_size_t len;
502 DWORD bytesreturned;
503 BOOL succeeded;
504
505 if (drivestream->locked_handle_count < (sizeof(drivestream->locked_handles) / sizeof(drivestream->locked_handles[0])))
506 {
507 if (gate_str_comp(drivestream->devicepath, volume->devicepath) == 0)
508 {
509 /* this volume is part of the desired drive */
510 len = gate_win32_utf8_2_winstr(volume->uid, gate_str_length(volume->uid), volume_uid, sizeof(volume_uid) / sizeof(volume_uid[0]));
511 if (len != 0)
512 {
513 handle = gate_win32_createfile(volume_uid, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, OPEN_EXISTING, 0, 0, NULL);
514 /*handle = CreateFile(volume_uid, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);*/
515 if (INVALID_HANDLE_VALUE != handle)
516 {
517 succeeded = DeviceIoControl(handle, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &bytesreturned, NULL);
518 if (succeeded)
519 {
520 drivestream->locked_handles[drivestream->locked_handle_count] = handle;
521 ++drivestream->locked_handle_count;
522 succeeded = DeviceIoControl(handle, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0, &bytesreturned, NULL);
523 }
524 else
525 {
526 CloseHandle(handle);
527 }
528 }
529 }
530 }
531 }
532 return true;
533 }
534
535 gate_result_t gate_storagedrive_openstream(gate_storagedrive_t const* drive, gate_enumint_t open_flags, gate_controlstream_t** stream)
536 {
537 gate_result_t ret;
538 gate_drivestream_t* drivestream = NULL;
539 gate_bool_t writable;
540 TCHAR devpath[1024];
541 DWORD dwaccess;
542 DWORD dwshare = (FILE_SHARE_READ | FILE_SHARE_WRITE);
543 DWORD dwflags = 0;
544 HANDLE hdrive = INVALID_HANDLE_VALUE;
545 gate_size_t ndx;
546
547 do
548 {
549 if ((drive == NULL) || (stream == NULL))
550 {
551 ret = GATE_RESULT_INVALIDARG;
552 break;
553 }
554
555 if (GATE_FLAG_ENABLED(open_flags, GATE_STREAM_OPEN_WRITE))
556 {
557 writable = true;
558 dwaccess = GENERIC_WRITE;
559 dwflags = (FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH);
560 }
561 else if (GATE_FLAG_ENABLED(open_flags, GATE_STREAM_OPEN_READ))
562 {
563 writable = false;
564 dwaccess = GENERIC_READ;
565 dwflags = FILE_FLAG_SEQUENTIAL_SCAN;
566 }
567 else
568 {
569 ret = GATE_RESULT_INVALIDARG;
570 break;
571 }
572
573 ndx = gate_win32_utf8_2_winstr(drive->uid, gate_str_length(drive->uid), devpath, sizeof(devpath) / sizeof(devpath[0]));
574 if (ndx == 0)
575 {
576 ret = GATE_RESULT_INVALIDARG;
577 }
578
579 drivestream = gate_mem_alloc(sizeof(gate_drivestream_t) + (gate_size_t)drive->blocksize);
580 if (drivestream == NULL)
581 {
582 ret = GATE_RESULT_OUTOFMEMORY;
583 break;
584 }
585
586 gate_init_drivestream_vtbl();
587 drivestream->vtbl = &gate_drivestream_vtbl;
588 gate_atomic_int_init(&drivestream->ref_counter, 1);
589 drivestream->writeaccess = writable;
590 drivestream->locked_handle_count = 0;
591 gate_str_print_text(drivestream->devicepath, sizeof(drivestream->devicepath), drive->uid, gate_str_length(drive->uid));
592
593 gate_storagevolume_enum(&gate_storagedrive_volume_cb, drivestream);
594
595 hdrive = gate_win32_createfile(devpath, dwaccess, dwshare, OPEN_EXISTING, 0, dwflags, NULL);
596 if (hdrive == INVALID_HANDLE_VALUE)
597 {
598 gate_win32_print_lasterror(&ret, NULL, 0);
599 break;
600 }
601
602 gate_platform_stream_buffer_init(&drivestream->block_stream, (gate_platform_stream_t)hdrive,
603 (gate_int64_t)drive->size, 0, (gate_size_t)drive->blocksize);
604
605 hdrive = INVALID_HANDLE_VALUE;
606 *stream = (gate_controlstream_t*)drivestream;
607 drivestream = NULL;
608 ret = GATE_RESULT_OK;
609 } while (0);
610
611 if (GATE_FAILED(ret))
612 {
613 gate_win32_closehandle(hdrive);
614 if (drivestream != NULL)
615 {
616 for (ndx = 0; ndx != drivestream->locked_handle_count; ++ndx)
617 {
618 gate_win32_closehandle(drivestream->locked_handles[ndx]);
619 }
620
621 gate_mem_dealloc(drivestream);
622 }
623
624 }
625
626
627 return ret;
628 }
629
630 static void drivestream_release(void* thisptr)
631 {
632 gate_drivestream_t* stream = (gate_drivestream_t*)thisptr;
633 gate_size_t ndx;
634
635 if (0 == gate_atomic_int_dec(&stream->ref_counter))
636 {
637 for (ndx = 0; ndx != stream->locked_handle_count; ++ndx)
638 {
639 CloseHandle(stream->locked_handles[ndx]);
640 }
641
642 gate_platform_stream_close(&stream->block_stream.stream);
643
644 gate_mem_dealloc(thisptr);
645 }
646 }
647 static int drivestream_retain(void* thisptr)
648 {
649 gate_drivestream_t* stream = (gate_drivestream_t*)thisptr;
650 return gate_atomic_int_inc(&stream->ref_counter);
651 }
652 static char const* drivestream_get_interface_name(void* thisptr)
653 {
654 GATE_UNUSED_ARG(thisptr);
655 return GATE_INTERFACE_NAME_CONTROLSTREAM;
656 }
657
658 static gate_result_t drivestream_read(void* thisptr, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
659 {
660 gate_drivestream_t* stream = (gate_drivestream_t*)thisptr;
661 gate_result_t ret = GATE_RESULT_FAILED;
662
663 do
664 {
665 if (stream->writeaccess)
666 {
667 ret = GATE_RESULT_INVALIDSTATE;
668 break;
669 }
670 if ((bufferlength == 0) || (buffer == NULL))
671 {
672 ret = GATE_RESULT_INVALIDARG;
673 break;
674 }
675
676 ret = gate_platform_stream_buffer_read(&stream->block_stream, buffer, bufferlength, returned);
677 } while (0);
678
679 return ret;
680 }
681 static gate_result_t drivestream_peek(void* thisptr, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
682 {
683 GATE_UNUSED_ARG(thisptr);
684 GATE_UNUSED_ARG(buffer);
685 GATE_UNUSED_ARG(bufferlength);
686 GATE_UNUSED_ARG(returned);
687 return GATE_RESULT_NOTSUPPORTED;
688 }
689 static gate_result_t drivestream_write(void* thisptr, char const* buffer, gate_size_t bufferlength, gate_size_t* written)
690 {
691 gate_drivestream_t* stream = (gate_drivestream_t*)thisptr;
692 gate_result_t ret = GATE_RESULT_FAILED;
693
694 do
695 {
696 if (!stream->writeaccess)
697 {
698 ret = GATE_RESULT_INVALIDSTATE;
699 break;
700 }
701
702 if ((bufferlength == 0) || (buffer == NULL))
703 {
704 ret = GATE_RESULT_INVALIDARG;
705 break;
706 }
707
708 ret = gate_platform_stream_buffer_write(&stream->block_stream, buffer, bufferlength, written);
709 } while (0);
710
711 return ret;
712 }
713 static gate_result_t drivestream_flush(void* thisptr)
714 {
715 gate_result_t ret = GATE_RESULT_OK;
716 gate_drivestream_t* stream = (gate_drivestream_t*)thisptr;
717 if (FALSE == gate_win32_flushfilebuffers(stream->block_stream.stream))
718 {
719 ret = GATE_RESULT_FAILED;
720 }
721 return ret;
722 }
723
724 static gate_result_t drivestream_get_resource(void* thisptr, gate_enumint_t resource_type, gate_uintptr_t* resource)
725 {
726 gate_drivestream_t* stream = (gate_drivestream_t*)thisptr;
727 GATE_UNUSED_ARG(resource_type);
728 *resource = (gate_uintptr_t)(void*)stream->block_stream.stream;
729 return GATE_RESULT_OK;
730 }
731
732 static gate_result_t drivestream_can_read(void* thisptr, gate_bool_t* return_value)
733 {
734 gate_result_t ret = GATE_RESULT_OK;
735 gate_drivestream_t* stream = (gate_drivestream_t*)thisptr;
736 if (return_value)
737 {
738 *return_value = stream->writeaccess ? false : true;
739 }
740 return ret;
741 }
742 static gate_result_t drivestream_can_write(void* thisptr, gate_bool_t* return_value)
743 {
744 gate_result_t ret = GATE_RESULT_OK;
745 gate_drivestream_t* stream = (gate_drivestream_t*)thisptr;
746 if (return_value)
747 {
748 *return_value = stream->writeaccess ? true : false;
749 }
750 return ret;
751 }
752 static gate_result_t drivestream_get_size(void* thisptr, gate_int64_t* return_value)
753 {
754 gate_result_t ret = GATE_RESULT_OK;
755 gate_drivestream_t* stream = (gate_drivestream_t*)thisptr;
756 if (return_value)
757 {
758 *return_value = (gate_int64_t)stream->block_stream.total_size;
759 }
760 return ret;
761 }
762 static gate_result_t drivestream_get_available(void* thisptr, gate_int64_t* return_value)
763 {
764 gate_result_t ret = GATE_RESULT_OK;
765 gate_drivestream_t* stream = (gate_drivestream_t*)thisptr;
766 if (return_value)
767 {
768 *return_value = (gate_int64_t)stream->block_stream.total_size - (gate_int64_t)stream->block_stream.position;
769 }
770 return ret;
771 }
772 static gate_result_t drivestream_seek(void* thisptr, gate_int64_t position, gate_enumint_t origin, gate_int64_t* final_position)
773 {
774 gate_drivestream_t* stream = (gate_drivestream_t*)thisptr;
775 int stream_origin;
776 switch (origin)
777 {
778 case GATE_STREAM_SEEK_BEGIN:
779 stream_origin = GATE_PLATFORM_STREAM_ORIGIN_BEGIN;
780 break;
781 case GATE_STREAM_SEEK_CURRENT:
782 stream_origin = GATE_PLATFORM_STREAM_ORIGIN_CURRENT;
783 break;
784 case GATE_STREAM_SEEK_END:
785 stream_origin = GATE_PLATFORM_STREAM_ORIGIN_END;
786 break;
787 default:
788 return GATE_RESULT_INVALIDARG;
789 }
790
791 return gate_platform_stream_buffer_seek(&stream->block_stream, position, stream_origin, final_position);
792 }
793 static gate_result_t drivestream_reset(void* thisptr)
794 {
795 GATE_UNUSED_ARG(thisptr);
796 return GATE_RESULT_NOTIMPLEMENTED;
797 }
798 static gate_result_t drivestream_close(void* thisptr, gate_enumint_t close_type)
799 {
800 GATE_UNUSED_ARG(thisptr);
801 GATE_UNUSED_ARG(close_type);
802 return GATE_RESULT_NOTIMPLEMENTED;
803 }
804
805 #ifndef DRIVE_HEAD_REG
806 # define DRIVE_HEAD_REG 0xA0
807 #endif
808
809
810 #include "gate/struct_pack_begin.h"
811 GATE_STRUCT_PACK_BEGIN(_GATE_IDEREGS)
812 {
813 BYTE bFeaturesReg;
814 BYTE bSectorCountReg;
815 BYTE bSectorNumberReg;
816 BYTE bCylLowReg;
817 BYTE bCylHighReg;
818 BYTE bDriveHeadReg;
819 BYTE bCommandReg;
820 BYTE bReserved;
821 } GATE_STRUCT_PACK_END;
822 #include "gate/struct_pack_end.h"
823 typedef struct _GATE_IDEREGS GATE_IDEREGS;
824
825
826 #include "gate/struct_pack_begin.h"
827 GATE_STRUCT_PACK_BEGIN(_GATE_SENDCMDINPARAMS)
828 {
829 DWORD cBufferSize;
830 GATE_IDEREGS irDriveRegs;
831 BYTE bDriveNumber;
832 BYTE bReserved[3];
833 DWORD dwReserved[4];
834 BYTE bBuffer[1];
835 } GATE_STRUCT_PACK_END;
836 #include "gate/struct_pack_end.h"
837 typedef struct _GATE_SENDCMDINPARAMS GATE_SENDCMDINPARAMS;
838
839
840 #include "gate/struct_pack_begin.h"
841 GATE_STRUCT_PACK_BEGIN(_GATE_DRIVERSTATUS)
842 {
843 BYTE bDriverError; // Error code from driver,
844 // or 0 if no error.
845 BYTE bIDEError; // Contents of IDE Error register.
846 // Only valid when bDriverError
847 // is SMART_IDE_ERROR.
848 BYTE bReserved[2]; // Reserved for future expansion.
849 DWORD dwReserved[2]; // Reserved for future expansion.
850 } GATE_STRUCT_PACK_END;
851 #include "gate/struct_pack_end.h"
852 typedef struct _GATE_DRIVERSTATUS GATE_DRIVERSTATUS;
853
854
855 #include "gate/struct_pack_begin.h"
856 GATE_STRUCT_PACK_BEGIN(_GATE_SENDCMDOUTPARAMS)
857 {
858 DWORD cBufferSize;
859 GATE_DRIVERSTATUS DriverStatus;
860 BYTE bBuffer[1];
861 } GATE_STRUCT_PACK_END;
862 #include "gate/struct_pack_end.h"
863 typedef struct _GATE_SENDCMDOUTPARAMS GATE_SENDCMDOUTPARAMS;
864
865
866 #include "gate/struct_pack_begin.h"
867 GATE_STRUCT_PACK_BEGIN(_GATE_GETVERSIONINPARAMS)
868 {
869 BYTE bVersion; // Binary driver version.
870 BYTE bRevision; // Binary driver revision.
871 BYTE bReserved; // Not used.
872 BYTE bIDEDeviceMap; // Bit map of IDE devices.
873 DWORD fCapabilities; // Bit mask of driver capabilities.
874 DWORD dwReserved[4]; // For future use.
875 } GATE_STRUCT_PACK_END;
876 #include "gate/struct_pack_end.h"
877 typedef struct _GATE_GETVERSIONINPARAMS GATE_GETVERSIONINPARAMS;
878
879
880
881 #ifndef ENABLE_SMART
882 #define ENABLE_SMART 0xD8
883 #endif
884
885 #ifndef SMART_CYL_LOW
886 #define SMART_CYL_LOW 0x4F
887 #endif
888
889 #ifndef SMART_CYL_HI
890 #define SMART_CYL_HI 0xC2
891 #endif
892
893 #ifndef SMART_CMD
894 #define SMART_CMD 0xB0
895 #endif
896
897 #ifndef READ_THRESHOLDS
898 #define READ_THRESHOLDS 0xD1
899 #endif
900
901 #ifndef READ_THRESHOLD_BUFFER_SIZE
902 #define READ_THRESHOLD_BUFFER_SIZE 512
903 #endif
904
905 #ifndef CAP_SMART_CMD
906 #define CAP_SMART_CMD 4
907 #endif
908
909 #ifndef SMART_SEND_DRIVE_COMMAND
910 #define SMART_SEND_DRIVE_COMMAND CTL_CODE(IOCTL_DISK_BASE, 0x0021, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
911 #endif
912
913 #ifndef SMART_GET_VERSION
914 #define SMART_GET_VERSION CTL_CODE(IOCTL_DISK_BASE, 0x0020, METHOD_BUFFERED, FILE_READ_ACCESS)
915 #endif
916
917 #ifndef SMART_RCV_DRIVE_DATA
918 #define SMART_RCV_DRIVE_DATA CTL_CODE(IOCTL_DISK_BASE, 0x0022, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
919 #endif
920
921
922 static gate_bool_t smart_enabled(HANDLE device, gate_uint8_t physical_drive_num)
923 {
924 static char const* const FuncName = "DiskDriveImpl::smart_is_enabled";
925 GATE_SENDCMDINPARAMS inparams = { 0 };
926 GATE_SENDCMDOUTPARAMS outparams = { 0 };
927 DWORD dwRet = 0;
928
929 inparams.cBufferSize = 0;
930 inparams.bDriveNumber = physical_drive_num;
931 inparams.irDriveRegs.bFeaturesReg = ENABLE_SMART;
932 inparams.irDriveRegs.bSectorCountReg = 1;
933 inparams.irDriveRegs.bSectorNumberReg = 1;
934 inparams.irDriveRegs.bCylLowReg = SMART_CYL_LOW;
935 inparams.irDriveRegs.bCylHighReg = SMART_CYL_HI;
936 inparams.irDriveRegs.bDriveHeadReg = DRIVE_HEAD_REG;
937 inparams.irDriveRegs.bCommandReg = SMART_CMD;
938
939 if (!DeviceIoControl(device, SMART_SEND_DRIVE_COMMAND, &inparams, sizeof(inparams), &outparams, sizeof(outparams), &dwRet, NULL))
940 {
941 return false;
942 }
943 return true;
944 }
945
946
947 #ifndef READ_ATTRIBUTE_BUFFER_SIZE
948 #define READ_ATTRIBUTE_BUFFER_SIZE 512
949 #endif
950
951 typedef struct
952 {
953 BYTE bDriverError;
954 BYTE bIDEStatus;
955 BYTE bReserved[2];
956 DWORD dwReserved[2];
957 } GATE_ST_DRIVERSTAT;
958
959 typedef struct
960 {
961 DWORD cBufferSize;
962 GATE_ST_DRIVERSTAT DriverStatus;
963 BYTE bBuffer[READ_ATTRIBUTE_BUFFER_SIZE];
964 } GATE_ST_ATAOUTPARAM;
965
966 typedef struct _GATE_SMART_THRESHOLD
967 {
968 BYTE Id;
969 BYTE Value;
970 BYTE Reserved[10];
971 } GATE_SMART_THRESHOLD;
972
973 #ifndef READ_ATTRIBUTES
974 #define READ_ATTRIBUTES 0xD0
975 #endif
976
977 #define INDEX_ATTRIB_INDEX 0
978 #define INDEX_ATTRIB_UNKNOWN1 1
979 #define INDEX_ATTRIB_UNKNOWN2 2
980 #define INDEX_ATTRIB_VALUE 3
981 #define INDEX_ATTRIB_WORST 4
982 #define INDEX_ATTRIB_RAW 5
983
984
985 typedef struct gate_smart_entry_class
986 {
987 gate_uint8_t id;
988 gate_uint8_t value;
989 gate_uint8_t worst;
990 gate_uint8_t threshold;
991 gate_uint64_t raw;
992 } gate_smart_entry_t;
993
994 typedef struct gate_smart_description_mapping_class
995 {
996 gate_uint8_t id;
997 gate_int8_t direction;
998 char const* description;
999 } gate_smart_description_mapping_t;
1000
1001 static gate_bool_t smart_resolve_description(gate_uint8_t id, char const** ptr_description, gate_int8_t* ptr_direction)
1002 {
1003 static gate_smart_description_mapping_t const smart_id_mappings[] = {
1004 { 0x01, -1, "Read Error Rate" },
1005 { 0x02, +1, "Throughput Performance" },
1006 { 0x03, -1, "Spin-Up Time" },
1007 { 0x04, 0, "Start/Stop Count" },
1008 { 0x05, -1, "Reallocated Sectors Count" },
1009 { 0x06, 0, "Read Channel Margin" },
1010 { 0x07, 0, "Seek Error Rate" },
1011 { 0x08, +1, "Seek Time Performance" },
1012 { 0x09, 0, "Power-On Hours (POH)" },
1013 { 0x0A, -1, "Spin Retry Count" },
1014 { 0x0B, -1, "Recalibration Retries" }, // or Calibration Retry Count" },
1015 { 0x0C, 0, "Power Cycle Count" },
1016 { 0x0D, -1, "Soft Read Error Rate" },
1017 { 0xAA, 0, "Available Reserved Space" },
1018 { 0xAB, 0, "SSD Program Fail Count" },
1019 { 0xAC, 0, "SSD Erase Fail Count" },
1020 { 0xAD, 0, "SSD Wear Leveling Count" },
1021 { 0xAE, 0, "Unexpected power loss count" },
1022 { 0xAF, 0, "Power Loss Protection Failure" },
1023 { 0xB0, 0, "Erase Fail Count" },
1024 { 0xB1, 0, "Wear Range Delta" },
1025 { 0xB3, 0, "Used Reserved Block Count Total" },
1026 { 0xB4, 0, "Unused Reserved Block Count Total" },
1027 { 0xB5, -1, "Program Fail Count Total or Non-4K Aligned Access Count" },
1028 { 0xB6, 0, "Erase Fail Count" },
1029 { 0xB7, -1, "SATA Downshift Error Count" },
1030 { 0xB8, -1, "End-to-End error / IOEDC" },
1031 { 0xB9, 0, "Head Stability" },
1032 { 0xBA, 0, "Induced Op-Vibration Detection" },
1033 { 0xBB, -1, "Reported Uncorrectable Errors" },
1034 { 0xBC, -1, "Command Timeout" },
1035 { 0xBD, -1, "High Fly Writes" },
1036 { 0xBE, -1, "Airflow Temperature" }, // (WDC) resp. Airflow Temperature Celsius (HP)" },
1037 { 0xBE, +1, "Temperature Difference from 100" },
1038 { 0xBF, -1, "G-sense Error Rate" },
1039 { 0xC0, -1, "Power-off Retract Count" }, // or Emergency Retract Cycle Count (Fujitsu)[22]" },
1040 { 0xC1, -1, "Load Cycle Count" }, // or Load/Unload Cycle Count (Fujitsu)" },
1041 { 0xC2, -1, "Temperature" }, // resp. Temperature Celsius" },
1042 { 0xC3, 0, "Hardware ECC Recovered" },
1043 { 0xC4, -1, "Reallocation Event Count" },
1044 { 0xC5, -1, "Current Pending Sector Count" },
1045 { 0xC6, -1, "Uncorrectable Sector Count" }, // or Offline Uncorrectable or Off-Line Scan Uncorrectable Sector Count[22]" },
1046 { 0xC7, -1, "UltraDMA CRC Error Count" },
1047 { 0xC8, -1, "Multi-Zone Error Rate [29]" },
1048 { 0xC8, -1, "Write Error Rate (Fujitsu)" },
1049 { 0xC9, -1, "Soft Read Error Rate" }, // or TA Counter Detected" },
1050 { 0xCA, -1, "Data Address Mark errors" }, // or TA Counter Increased" },
1051 { 0xCB, -1, "Run Out Cancel" },
1052 { 0xCC, -1, "Soft ECC Correction" },
1053 { 0xCD, -1, "Thermal Asperity Rate (TAR)" },
1054 { 0xCE, 0, "Flying Height" },
1055 { 0xCF, -1, "Spin High Current" },
1056 { 0xD0, 0, "Spin Buzz" },
1057 { 0xD1, 0, "Offline Seek Performance" },
1058 { 0xD2, 0, "Vibration During Write" },
1059 { 0xD3, 0, "Vibration During Write" },
1060 { 0xD4, 0, "Shock During Write" },
1061 { 0xDC, -1, "Disk Shift" },
1062 { 0xDD, -1, "G-Sense Error Rate" },
1063 { 0xDE, 0, "Loaded Hours" },
1064 { 0xDF, 0, "Load/Unload Retry Count" },
1065 { 0xE0, -1, "Load Friction" },
1066 { 0xE1, -1, "Load/Unload Cycle Count" },
1067 { 0xE2, 0, "Load 'In'-time" },
1068 { 0xE3, -1, "Torque Amplification Count" },
1069 { 0xE4, -1, "Power-Off Retract Cycle" },
1070 { 0xE6, 0, "GMR Head Amplitude" },
1071 { 0xE6, +1, "Drive Life Protection Status" },
1072 { 0xE7, -1, "Temperature" },
1073 { 0xE7, +1, "SSD Life Left" },
1074 { 0xE8, 0, "Endurance Remaining" },
1075 { 0xE8, 0, "Available Reserved Space" },
1076 { 0xE9, 0, "Power-On Hours" },
1077 { 0xE9, 0, "Media Wearout Indicator" },
1078 { 0xEA, 0, "Average erase count AND Maximum Erase Count" },
1079 { 0xEB, 0, "Good Block Count AND System(Free) Block Count" },
1080 { 0xF0, 0, "Head Flying Hours" },
1081 { 0xF0, 0, "Transfer Error Rate (Fujitsu)" },
1082 { 0xF1, 0, "Total LBAs Written" },
1083 { 0xF2, 0, "Total LBAs Read" },
1084 { 0xF3, 0, "Total LBAs Written Expanded" },
1085 { 0xF4, 0, "Total LBAs Read Expanded" },
1086 { 0xF6, 0, "Total Host Sector Writes" },
1087 { 0xF7, 0, "Host Program Page Count" },
1088 { 0xF8, 0, "Background Program Page Count" },
1089 { 0xF9, 0, "NAND Writes (1GiB)" },
1090 { 0xFA, -1, "Read Error Retry Rate" },
1091 { 0xFB, 0, "Minimum Spares Remaining" },
1092 { 0xFC, 0, "Newly Added Bad Flash Block" },
1093 { 0xFE, -1, "Free Fall Protection" }
1094 };
1095 static gate_size_t const smart_id_mappings_count = sizeof(smart_id_mappings) / sizeof(smart_id_mappings[0]);
1096 gate_size_t ndx;
1097 for (ndx = 0; ndx != smart_id_mappings_count; ++ndx)
1098 {
1099 if (id == smart_id_mappings[ndx].id)
1100 {
1101 if (ptr_description)
1102 {
1103 *ptr_description = smart_id_mappings[ndx].description;
1104 }
1105 if (ptr_direction)
1106 {
1107 *ptr_direction = smart_id_mappings[ndx].direction;
1108 }
1109 return true;
1110 }
1111 }
1112 return false;
1113 }
1114
1115
1116
1117 static gate_result_t gate_storagedrive_queryattribs_smart(gate_storagedrive_t const* drive, gate_storagedrive_attribs_callback_t callback, void* user_param)
1118 {
1119 gate_result_t ret = GATE_RESULT_FAILED;
1120 GATE_GETVERSIONINPARAMS versionparams = GATE_INIT_EMPTY;
1121 GATE_SENDCMDINPARAMS inparams = GATE_INIT_EMPTY;
1122 GATE_ST_ATAOUTPARAM outparams = GATE_INIT_EMPTY;
1123 TCHAR device_path[GATE_MAX_FILEPATH_LENGTH] = GATE_INIT_EMPTY;
1124 DWORD dwRetLen = 0;
1125
1126 HANDLE physical_disk_handle = INVALID_HANDLE_VALUE;
1127 BYTE physical_disk_num = (BYTE)drive->deviceindex;
1128 BYTE n;
1129 gate_int8_t direction;
1130 BYTE* ptr;
1131 gate_size_t ndx;
1132 GATE_SMART_THRESHOLD* ptr_threshold;
1133 gate_smart_entry_t smart_entries[30] = GATE_INIT_EMPTY;
1134 static gate_size_t const smart_entries_max = 30;
1135 gate_size_t smart_entries_used = 0;
1136 gate_smart_entry_t* ptr_smart_entry;
1137 gate_int64_t cb_values[6];
1138 char const* cb_texts[1];
1139 char tmp_buffer[8];
1140
1141 do
1142 {
1143 gate_win32_utf8_2_winstr(
1144 drive->devicepath, gate_str_length_max(drive->devicepath, sizeof(drive->devicepath)),
1145 device_path, sizeof(device_path) / sizeof(device_path[0]));
1146 physical_disk_handle = gate_win32_createfile(device_path,
1147 GENERIC_READ | GENERIC_WRITE,
1148 FILE_SHARE_READ | FILE_SHARE_WRITE,
1149 OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, 0, NULL);
1150 if (INVALID_HANDLE_VALUE == physical_disk_handle)
1151 {
1152 ret = GATE_RESULT_NOTAVAILABLE;
1153 break;
1154 }
1155
1156 if (!DeviceIoControl(physical_disk_handle, SMART_GET_VERSION, NULL, 0, &versionparams, sizeof(versionparams), &dwRetLen, NULL))
1157 {
1158 ret = GATE_RESULT_NOTSUPPORTED;
1159 break;
1160 }
1161 if (!GATE_FLAG_ENABLED(versionparams.fCapabilities, CAP_SMART_CMD))
1162 {
1163 ret = GATE_RESULT_NOTSUPPORTED;
1164 break;
1165 }
1166 if (!smart_enabled(physical_disk_handle, physical_disk_num))
1167 {
1168 ret = GATE_RESULT_NOTSUPPORTED;
1169 break;
1170 }
1171
1172 /* read SMART values */
1173
1174 inparams.cBufferSize = READ_ATTRIBUTE_BUFFER_SIZE;
1175 inparams.bDriveNumber = physical_disk_num;
1176 inparams.irDriveRegs.bFeaturesReg = READ_ATTRIBUTES;
1177 inparams.irDriveRegs.bSectorCountReg = 1;
1178 inparams.irDriveRegs.bSectorNumberReg = 1;
1179 inparams.irDriveRegs.bCylLowReg = SMART_CYL_LOW;
1180 inparams.irDriveRegs.bCylHighReg = SMART_CYL_HI;
1181 inparams.irDriveRegs.bDriveHeadReg = DRIVE_HEAD_REG;
1182 inparams.irDriveRegs.bCommandReg = SMART_CMD;
1183 if (!DeviceIoControl(physical_disk_handle, SMART_RCV_DRIVE_DATA,
1184 &inparams, sizeof(inparams),
1185 &outparams, sizeof(outparams),
1186 &dwRetLen, NULL))
1187 {
1188 ret = GATE_RESULT_INVALIDINPUT;
1189 break;
1190 }
1191
1192 for (n = 0; n < smart_entries_max; ++n)
1193 {
1194 ptr = &outparams.bBuffer[2 + n * 12];
1195 if (ptr[INDEX_ATTRIB_INDEX] != 0)
1196 {
1197 ptr_smart_entry = &smart_entries[smart_entries_used];
1198 ptr_smart_entry->id = ptr[INDEX_ATTRIB_INDEX];
1199 ptr_smart_entry->value = ptr[INDEX_ATTRIB_VALUE];
1200 ptr_smart_entry->worst = ptr[INDEX_ATTRIB_WORST];
1201 ptr_smart_entry->threshold = 0;
1202 ptr_smart_entry->raw = (((gate_uint64_t)ptr[INDEX_ATTRIB_RAW + 0]))
1203 | (((gate_uint64_t)ptr[INDEX_ATTRIB_RAW + 1]) << 8)
1204 | (((gate_uint64_t)ptr[INDEX_ATTRIB_RAW + 2]) << 16)
1205 | (((gate_uint64_t)ptr[INDEX_ATTRIB_RAW + 3]) << 24)
1206 | (((gate_uint64_t)ptr[INDEX_ATTRIB_RAW + 4]) << 32)
1207 | (((gate_uint64_t)ptr[INDEX_ATTRIB_RAW + 5]) << 40);
1208 ++smart_entries_used;
1209 }
1210 }
1211
1212 /* read SMART threshold values */
1213 inparams.irDriveRegs.bFeaturesReg = READ_THRESHOLDS;
1214 inparams.cBufferSize = READ_THRESHOLD_BUFFER_SIZE;
1215 gate_mem_clear(&outparams, sizeof(outparams));
1216
1217 if (DeviceIoControl(physical_disk_handle, SMART_RCV_DRIVE_DATA, &inparams, sizeof(inparams),
1218 &outparams, sizeof(outparams),
1219 &dwRetLen, NULL))
1220 {
1221 for (n = 0; n < smart_entries_max; ++n)
1222 {
1223 ptr_threshold = (GATE_SMART_THRESHOLD*)&outparams.bBuffer[2 + n * 12];
1224 if (ptr_threshold->Id == 0)
1225 {
1226 continue;
1227 }
1228 if (ptr_threshold->Id == smart_entries[n].id)
1229 {
1230 ptr_smart_entry = &smart_entries[n];
1231 }
1232 else
1233 {
1234 /* smart thresholds are not coming in the same ID-order than before -> resolve by ID */
1235 ptr_smart_entry = NULL;
1236 for (ndx = 0; ndx < smart_entries_used; ++ndx)
1237 {
1238 if (ptr_threshold->Id == smart_entries[ndx].id)
1239 {
1240 ptr_smart_entry = &smart_entries[ndx];
1241 break;
1242 }
1243 }
1244 }
1245 if (ptr_smart_entry)
1246 {
1247 ptr_smart_entry->threshold = ptr_threshold->Value;
1248 }
1249 }
1250 }
1251
1252 /* send results to callback function */
1253 if (callback)
1254 {
1255 for (ndx = 0; ndx < smart_entries_used; ++ndx)
1256 {
1257 ptr_smart_entry = &smart_entries[ndx];
1258 direction = 0;
1259 if (!smart_resolve_description(ptr_smart_entry->id, &cb_texts[0], &direction))
1260 {
1261 direction = 0;
1262 tmp_buffer[0] = '#';
1263 gate_str_print_int16(&tmp_buffer[1], sizeof(tmp_buffer) - 1, ptr_smart_entry->id);
1264 cb_texts[0] = tmp_buffer;
1265 }
1266 cb_values[GATE_STORAGEDRIVE_ATTRIBINDEX_SMART_ID] = ptr_smart_entry->id;
1267 cb_values[GATE_STORAGEDRIVE_ATTRIBINDEX_SMART_VALUE] = ptr_smart_entry->value;
1268 cb_values[GATE_STORAGEDRIVE_ATTRIBINDEX_SMART_WORST] = ptr_smart_entry->worst;
1269 cb_values[GATE_STORAGEDRIVE_ATTRIBINDEX_SMART_RAW] = (gate_int64_t)ptr_smart_entry->raw;
1270 cb_values[GATE_STORAGEDRIVE_ATTRIBINDEX_SMART_THRESHOLD] = ptr_smart_entry->threshold;
1271 cb_values[GATE_STORAGEDRIVE_ATTRIBINDEX_SMART_DIRECTION] = direction;
1272 if (!callback(drive, GATE_STORAGEDRIVE_ATTRIBTYPE_SMART, cb_values, 6, cb_texts, 1, user_param))
1273 {
1274 break;
1275 }
1276 }
1277 }
1278 ret = GATE_RESULT_OK;
1279 } while (0);
1280
1281 if (physical_disk_handle != INVALID_HANDLE_VALUE)
1282 {
1283 gate_win32_closehandle(physical_disk_handle);
1284 }
1285 return ret;
1286 }
1287
1288 gate_result_t gate_storagedrive_queryattribs(gate_storagedrive_t const* drive, gate_enumint_t attrib_type,
1289 gate_storagedrive_attribs_callback_t callback, void* user_param)
1290 {
1291 gate_result_t ret = GATE_RESULT_FAILED;
1292 do
1293 {
1294 if (!drive || !callback)
1295 {
1296 ret = GATE_RESULT_INVALIDARG;
1297 break;
1298 }
1299 switch (attrib_type)
1300 {
1301 case GATE_STORAGEDRIVE_ATTRIBTYPE_SMART:
1302 {
1303 ret = gate_storagedrive_queryattribs_smart(drive, callback, user_param);
1304 break;
1305 }
1306 default:
1307 {
1308 ret = GATE_RESULT_NOTSUPPORTED;
1309 break;
1310 }
1311 }
1312 } while (0);
1313
1314 return ret;
1315 }
1316
1317 #endif /* !defined(GATE_SYS_WINCE) */
1318
1319 #endif /* defined(GATE_SYSTEM_STORAGEDRIVES_WINAPI_IMPL) */
1320
1321
1322
1323 #if defined(GATE_SYSTEM_STORAGEDRIVES_POSIX_IMPL)
1324
1325 #include "gate/files.h"
1326 #include "gate/platforms.h"
1327
1328 #include <sys/stat.h>
1329 #include <fcntl.h>
1330
1331 struct gate_storagedrive_enum_param
1332 {
1333 gate_storagedrive_enum_callback_t callback;
1334 void* user_param;
1335 gate_enumint_t drivetype;
1336 };
1337
1338 77 static gate_size_t read_file_line(char* destbuffer, gate_size_t destbuffersize, char const* basepath, char const* subpath)
1339 {
1340 char path[GATE_MAX_FILEPATH_LENGTH];
1341 gate_size_t pathlen;
1342 gate_string_t filepath;
1343 77 gate_size_t bytes_received = destbuffersize - 1;
1344 gate_result_t result;
1345 gate_size_t pos;
1346
1347
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 77 times.
77 if (subpath == NULL)
1348 {
1349 pathlen = gate_str_print_text(path, sizeof(path), basepath, gate_str_length(basepath));
1350 }
1351 else
1352 {
1353 77 pathlen = gate_file_build_path(path, sizeof(path), basepath, gate_str_length(basepath), subpath, gate_str_length(subpath));
1354 }
1355 77 gate_string_create_static_len(&filepath, path, pathlen);
1356 77 result = gate_file_get_content_buffer(&filepath, destbuffer, &bytes_received);
1357
2/2
✓ Branch 0 taken 66 times.
✓ Branch 1 taken 11 times.
77 if (GATE_SUCCEEDED(result))
1358 {
1359 66 pos = gate_str_char_pos(destbuffer, bytes_received, '\n', 0);
1360
1/2
✓ Branch 0 taken 66 times.
✗ Branch 1 not taken.
66 if (pos != GATE_STR_NPOS)
1361 {
1362 66 bytes_received = pos;
1363 }
1364 66 destbuffer[bytes_received] = 0;
1365 66 return bytes_received;
1366 }
1367 else
1368 {
1369 11 destbuffer[0] = 0;
1370 11 return 0;
1371 }
1372 }
1373
1374 46 static gate_bool_t gate_storagedrive_enum_cb(gate_file_entry_t const* entry, void* userparam)
1375 {
1376 46 struct gate_storagedrive_enum_param* dispatcher = (struct gate_storagedrive_enum_param*)userparam;
1377 46 gate_bool_t ret = true;
1378 46 gate_string_t subdir = GATE_STRING_INIT_EMPTY;
1379 46 gate_size_t path_len = gate_str_length(entry->path);
1380 char subpath[4096];
1381
1382 46 subdir.str = subpath;
1383 46 subdir.length = gate_file_build_path(subpath, sizeof(subpath), entry->path, path_len, "device", 6);
1384
2/2
✓ Branch 1 taken 11 times.
✓ Branch 2 taken 35 times.
46 if (GATE_SUCCEEDED(gate_file_dir_exists(&subdir)))
1385 {
1386
1387 char type[512];
1388 char blocks[512];
1389 11 char removable[16] = GATE_INIT_EMPTY;
1390 11 char read_only[16] = GATE_INIT_EMPTY;
1391 gate_size_t name_len;
1392 gate_size_t prod_len;
1393 gate_size_t vend_len;
1394 gate_size_t type_len;
1395 gate_size_t block_len;
1396 gate_size_t dev_len;
1397 gate_size_t removable_len;
1398 gate_size_t read_only_len;
1399 gate_strbuilder_t name_builder;
1400 gate_size_t ndx;
1401 struct stat filestat;
1402 gate_storagedrive_t drive;
1403
1404 /* storage block device */
1405 11 gate_mem_clear(&drive, sizeof(drive));
1406 11 drive.drivetype = GATE_STORAGEDRIVE_TYPE_STANDARD;
1407 11 gate_str_print_text(drive.path, sizeof(drive.path), subdir.str, subdir.length);
1408
1409 11 name_len = read_file_line(drive.name, sizeof(drive.name), entry->path, "device/model");
1410 11 prod_len = read_file_line(drive.productname, sizeof(drive.productname), entry->path, "device/name");
1411 11 vend_len = read_file_line(drive.vendor, sizeof(drive.vendor), entry->path, "device/vendor");
1412 11 type_len = read_file_line(type, sizeof(type), entry->path, "device/type");
1413 11 block_len = read_file_line(blocks, sizeof(blocks), entry->path, "size");
1414 11 removable_len = read_file_line(removable, sizeof(removable), entry->path, "removable");
1415 11 read_only_len = read_file_line(read_only, sizeof(read_only), entry->path, "ro");
1416
1417 11 gate_strbuilder_create_static(&name_builder, drive.name, sizeof(drive.name), name_len);
1418
1419
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (name_len == 0)
1420 {
1421 if (prod_len > 0)
1422 {
1423 gate_strbuilder_append_text(&name_builder, drive.productname, prod_len);
1424 }
1425 else if (vend_len > 0)
1426 {
1427 gate_strbuilder_append_text(&name_builder, drive.vendor, vend_len);
1428 }
1429 gate_str_print_text(drive.name, sizeof(drive.name), drive.productname, prod_len);
1430 }
1431
1432
2/2
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 4 times.
11 if (gate_str_compare(removable, removable_len, "1", 1) == 0)
1433 {
1434 7 drive.drivetype = GATE_STORAGEDRIVE_TYPE_REMOVABLE;
1435 }
1436
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
11 if (gate_str_compare(type, type_len, "SD", 2) == 0)
1437 {
1438 gate_strbuilder_append_cstr(&name_builder, " (MMC/SD)");
1439 }
1440
2/2
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 4 times.
11 else if (gate_str_compare(type, type_len, "5", 1) == 0)
1441 {
1442 7 gate_strbuilder_append_cstr(&name_builder, " (CD/DVD/BR-ROM)");
1443 7 drive.drivetype = GATE_STORAGEDRIVE_TYPE_ROM;
1444 }
1445
1446 11 drive.blockcount = 0;
1447 11 gate_str_parse_uint64(blocks, block_len, &drive.blockcount);
1448 11 drive.blocksize = 512;
1449 11 drive.size = drive.blockcount * drive.blocksize;
1450 11 gate_str_print_text(drive.uid, sizeof(drive.uid), entry->path, path_len);
1451
1452 11 dev_len = gate_str_length(entry->name);
1453 11 gate_file_build_path(drive.devicepath, sizeof(drive.devicepath), "/dev/", 5, entry->name, dev_len);
1454
1455
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
11 if (0 == stat(drive.devicepath, &filestat))
1456 {
1457 if (0 != (filestat.st_mode & (S_IFBLK | S_IFCHR)))
1458 {
1459 if (dev_len <= 4)
1460 {
1461 gate_uint32_t index_factor = 1;
1462 drive.deviceindex = 0;
1463 for (ndx = 0; ndx < dev_len; ++ndx)
1464 {
1465 drive.deviceindex += ((gate_uint32_t)entry->name[dev_len - ndx - 1]) * index_factor;
1466 index_factor *= 256;
1467 }
1468 }
1469 }
1470 else
1471 {
1472 drive.devicepath[0] = 0;
1473 }
1474 }
1475 else
1476 {
1477 11 drive.devicepath[0] = 0;
1478 }
1479
1480
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
11 if ((dispatcher->drivetype == GATE_STORAGEDRIVE_TYPE_ALL) || ((dispatcher->drivetype & drive.drivetype) != 0))
1481 {
1482 11 ret = dispatcher->callback(&drive, dispatcher->user_param);
1483 }
1484 else
1485 {
1486 ret = true;
1487 }
1488 }
1489 46 return ret;
1490 }
1491
1492
1493 7 gate_result_t gate_storagedrive_enum(gate_enumint_t drivetype, gate_storagedrive_enum_callback_t callback, void* user_param)
1494 {
1495 7 gate_result_t ret = GATE_RESULT_FAILED;
1496 static gate_string_t const sysfs_path = { "/sys/block", 10, NULL };
1497 struct gate_storagedrive_enum_param dispatcher;
1498 7 dispatcher.callback = callback;
1499 7 dispatcher.user_param = user_param;
1500 7 dispatcher.drivetype = drivetype;
1501
1502 7 ret = gate_file_list(&sysfs_path, &gate_storagedrive_enum_cb, &dispatcher);
1503
1504 7 return ret;
1505 }
1506
1507
1508
1509 static void drivestream_release(void* thisptr);
1510 static int drivestream_retain(void* thisptr);
1511 static char const* drivestream_get_interface_name(void* thisptr);
1512
1513 static gate_result_t drivestream_read(void* thisptr, char* buffer, gate_size_t bufferlength, gate_size_t* returned);
1514 static gate_result_t drivestream_peek(void* thisptr, char* buffer, gate_size_t bufferlength, gate_size_t* returned);
1515 static gate_result_t drivestream_write(void* thisptr, char const* buffer, gate_size_t bufferlength, gate_size_t* written);
1516 static gate_result_t drivestream_flush(void* thisptr);
1517
1518 static gate_result_t drivestream_get_resource(void* thisptr, gate_enumint_t resource_type, gate_uintptr_t* resource);
1519
1520 static gate_result_t drivestream_can_read(void* thisptr, gate_bool_t* return_value);
1521 static gate_result_t drivestream_can_write(void* thisptr, gate_bool_t* return_value);
1522 static gate_result_t drivestream_get_size(void* thisptr, gate_int64_t* return_value);
1523 static gate_result_t drivestream_get_available(void* thisptr, gate_int64_t* return_value);
1524 static gate_result_t drivestream_seek(void* thisptr, gate_int64_t position, gate_enumint_t origin, gate_int64_t* final_position);
1525 static gate_result_t drivestream_reset(void* thisptr);
1526 static gate_result_t drivestream_close(void* thisptr, gate_enumint_t close_type);
1527
1528 static GATE_INTERFACE_VTBL(gate_controlstream) gate_drivestream_vtbl;
1529 static void gate_init_drivestream_vtbl()
1530 {
1531 if (!gate_drivestream_vtbl.get_interface_name)
1532 {
1533 GATE_INTERFACE_VTBL(gate_controlstream) const local_vtbl =
1534 {
1535 &drivestream_get_interface_name,
1536 &drivestream_release,
1537 &drivestream_retain,
1538
1539 &drivestream_read,
1540 &drivestream_peek,
1541 &drivestream_write,
1542 &drivestream_flush,
1543
1544 &drivestream_get_resource,
1545
1546 &drivestream_can_read,
1547 &drivestream_can_write,
1548 &drivestream_get_size,
1549 &drivestream_get_available,
1550 &drivestream_seek,
1551 &drivestream_reset,
1552 &drivestream_close,
1553 };
1554 gate_drivestream_vtbl = local_vtbl;
1555 }
1556 }
1557
1558 typedef struct gate_drivestream_class
1559 {
1560 GATE_INTERFACE_VTBL(gate_controlstream) const* vtbl;
1561
1562 gate_atomic_int_t ref_counter;
1563 gate_bool_t writeaccess;
1564 gate_size_t locked_handle_count;
1565
1566 gate_platform_stream_buffer_t block_stream;
1567 } gate_drivestream_t;
1568
1569
1570 gate_result_t gate_storagedrive_openstream(gate_storagedrive_t const* drive, gate_enumint_t open_flags, gate_controlstream_t** stream)
1571 {
1572 gate_result_t ret;
1573 gate_drivestream_t* drivestream = NULL;
1574 gate_bool_t writable;
1575
1576 int fd = -1;
1577 int o_flags;
1578
1579 do
1580 {
1581 if ((drive == NULL) || (stream == NULL))
1582 {
1583 ret = GATE_RESULT_INVALIDARG;
1584 break;
1585 }
1586
1587 if (open_flags == GATE_STREAM_OPEN_READ)
1588 {
1589 o_flags = O_RDONLY;
1590 writable = false;
1591 }
1592 else if (open_flags == GATE_STREAM_OPEN_WRITE)
1593 {
1594 o_flags = O_WRONLY;
1595 writable = true;
1596 }
1597 else
1598 {
1599 ret = GATE_RESULT_INVALIDARG;
1600 break;
1601 }
1602
1603 fd = gate_posix_open(drive->devicepath, o_flags, 0);
1604 if (fd == -1)
1605 {
1606 ret = gate_platform_print_last_error(NULL, 0);
1607 break;
1608 }
1609
1610 drivestream = gate_mem_alloc(sizeof(gate_drivestream_t) + (gate_size_t)drive->blocksize);
1611 if (drivestream == NULL)
1612 {
1613 ret = GATE_RESULT_OUTOFMEMORY;
1614 break;
1615 }
1616
1617 gate_init_drivestream_vtbl();
1618 drivestream->vtbl = &gate_drivestream_vtbl;
1619 gate_atomic_int_init(&drivestream->ref_counter, 1);
1620 drivestream->writeaccess = writable;
1621
1622 gate_platform_stream_buffer_init(&drivestream->block_stream, (gate_platform_stream_t)(gate_intptr_t)fd,
1623 (gate_int64_t)drive->size, 0, (gate_size_t)drive->blocksize);
1624
1625 fd = -1;
1626 *stream = (gate_controlstream_t*)drivestream;
1627 drivestream = NULL;
1628 ret = GATE_RESULT_OK;
1629 } while (0);
1630
1631 if (GATE_FAILED(ret))
1632 {
1633 if (fd != -1)
1634 {
1635 gate_posix_close(fd);
1636 }
1637 if (drivestream != NULL)
1638 {
1639 gate_mem_dealloc(drivestream);
1640 }
1641 }
1642 return ret;
1643 }
1644
1645 static void drivestream_release(void* thisptr)
1646 {
1647 gate_drivestream_t* stream = (gate_drivestream_t*)thisptr;
1648
1649 if (0 == gate_atomic_int_dec(&stream->ref_counter))
1650 {
1651 gate_platform_stream_close(&stream->block_stream.stream);
1652
1653 gate_mem_dealloc(thisptr);
1654 }
1655 }
1656 static int drivestream_retain(void* thisptr)
1657 {
1658 gate_drivestream_t* stream = (gate_drivestream_t*)thisptr;
1659 return gate_atomic_int_inc(&stream->ref_counter);
1660 }
1661 static char const* drivestream_get_interface_name(void* thisptr)
1662 {
1663 (void)thisptr;
1664 return GATE_INTERFACE_NAME_CONTROLSTREAM;
1665 }
1666
1667 static gate_result_t drivestream_read(void* thisptr, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
1668 {
1669 gate_drivestream_t* stream = (gate_drivestream_t*)thisptr;
1670 gate_result_t ret = GATE_RESULT_FAILED;
1671
1672 do
1673 {
1674 if (stream->writeaccess)
1675 {
1676 ret = GATE_RESULT_INVALIDSTATE;
1677 break;
1678 }
1679 if ((bufferlength == 0) || (buffer == NULL))
1680 {
1681 ret = GATE_RESULT_INVALIDARG;
1682 break;
1683 }
1684
1685 ret = gate_platform_stream_buffer_read(&stream->block_stream, buffer, bufferlength, returned);
1686 } while (0);
1687
1688 return ret;
1689 }
1690 static gate_result_t drivestream_peek(void* thisptr, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
1691 {
1692 (void)thisptr;
1693 (void)buffer;
1694 (void)bufferlength;
1695 (void)returned;
1696 return GATE_RESULT_NOTSUPPORTED;
1697 }
1698 static gate_result_t drivestream_write(void* thisptr, char const* buffer, gate_size_t bufferlength, gate_size_t* written)
1699 {
1700 gate_drivestream_t* stream = (gate_drivestream_t*)thisptr;
1701 gate_result_t ret = GATE_RESULT_FAILED;
1702
1703 do
1704 {
1705 if (!stream->writeaccess)
1706 {
1707 ret = GATE_RESULT_INVALIDSTATE;
1708 break;
1709 }
1710
1711 if ((bufferlength == 0) || (buffer == NULL))
1712 {
1713 ret = GATE_RESULT_INVALIDARG;
1714 break;
1715 }
1716
1717 ret = gate_platform_stream_buffer_write(&stream->block_stream, buffer, bufferlength, written);
1718 } while (0);
1719
1720 return ret;
1721 }
1722 static gate_result_t drivestream_flush(void* thisptr)
1723 {
1724 gate_result_t ret = GATE_RESULT_OK;
1725 gate_drivestream_t* stream = (gate_drivestream_t*)thisptr;
1726 if (-1 == fsync((int)(gate_intptr_t)stream->block_stream.stream))
1727 {
1728 ret = GATE_RESULT_FAILED;
1729 }
1730 return ret;
1731 }
1732
1733 static gate_result_t drivestream_get_resource(void* thisptr, gate_enumint_t resource_type, gate_uintptr_t* resource)
1734 {
1735 gate_drivestream_t* stream = (gate_drivestream_t*)thisptr;
1736 (void)resource_type;
1737 *resource = (gate_uintptr_t)(void*)stream->block_stream.stream;
1738 return GATE_RESULT_OK;
1739 }
1740
1741 static gate_result_t drivestream_can_read(void* thisptr, gate_bool_t* return_value)
1742 {
1743 gate_result_t ret = GATE_RESULT_OK;
1744 gate_drivestream_t* stream = (gate_drivestream_t*)thisptr;
1745 if (return_value)
1746 {
1747 *return_value = stream->writeaccess ? false : true;
1748 }
1749 return ret;
1750 }
1751 static gate_result_t drivestream_can_write(void* thisptr, gate_bool_t* return_value)
1752 {
1753 gate_result_t ret = GATE_RESULT_OK;
1754 gate_drivestream_t* stream = (gate_drivestream_t*)thisptr;
1755 if (return_value)
1756 {
1757 *return_value = stream->writeaccess ? true : false;
1758 }
1759 return ret;
1760 }
1761 static gate_result_t drivestream_get_size(void* thisptr, gate_int64_t* return_value)
1762 {
1763 gate_result_t ret = GATE_RESULT_OK;
1764 gate_drivestream_t* stream = (gate_drivestream_t*)thisptr;
1765 if (return_value)
1766 {
1767 *return_value = (gate_int64_t)stream->block_stream.total_size;
1768 }
1769 return ret;
1770 }
1771 static gate_result_t drivestream_get_available(void* thisptr, gate_int64_t* return_value)
1772 {
1773 gate_result_t ret = GATE_RESULT_OK;
1774 gate_drivestream_t* stream = (gate_drivestream_t*)thisptr;
1775 if (return_value)
1776 {
1777 *return_value = (gate_int64_t)stream->block_stream.total_size - (gate_int64_t)stream->block_stream.position;
1778 }
1779 return ret;
1780 }
1781 static gate_result_t drivestream_seek(void* thisptr, gate_int64_t position, gate_enumint_t origin, gate_int64_t* final_position)
1782 {
1783 gate_drivestream_t* stream = (gate_drivestream_t*)thisptr;
1784 int stream_origin;
1785 switch (origin)
1786 {
1787 case GATE_STREAM_SEEK_BEGIN:
1788 stream_origin = GATE_PLATFORM_STREAM_ORIGIN_BEGIN;
1789 break;
1790 case GATE_STREAM_SEEK_CURRENT:
1791 stream_origin = GATE_PLATFORM_STREAM_ORIGIN_CURRENT;
1792 break;
1793 case GATE_STREAM_SEEK_END:
1794 stream_origin = GATE_PLATFORM_STREAM_ORIGIN_END;
1795 break;
1796 default:
1797 return GATE_RESULT_INVALIDARG;
1798 }
1799
1800 return gate_platform_stream_buffer_seek(&stream->block_stream, position, stream_origin, final_position);
1801 }
1802 static gate_result_t drivestream_reset(void* thisptr)
1803 {
1804 (void)thisptr;
1805 return GATE_RESULT_NOTIMPLEMENTED;
1806 }
1807 static gate_result_t drivestream_close(void* thisptr, gate_enumint_t close_type)
1808 {
1809 (void)thisptr;
1810 (void)close_type;
1811 return GATE_RESULT_NOTIMPLEMENTED;
1812 }
1813
1814 gate_result_t gate_storagedrive_queryattribs(gate_storagedrive_t const* drive, gate_enumint_t attrib_type,
1815 gate_storagedrive_attribs_callback_t callback, void* user_param)
1816 {
1817 GATE_UNUSED_ARG(drive);
1818 GATE_UNUSED_ARG(attrib_type);
1819 GATE_UNUSED_ARG(callback);
1820 GATE_UNUSED_ARG(user_param);
1821 return GATE_RESULT_NOTIMPLEMENTED;
1822 }
1823
1824 #endif /* defined(GATE_SYSTEM_STORAGEDRIVES_POSIX_IMPL) */
1825
1826
1827 #if defined(GATE_SYSTEM_STORAGEDRIVES_DOS_IMPL)
1828
1829 #include "gate/platforms.h"
1830
1831 typedef struct bios_chs_class
1832 {
1833 unsigned cylinder; /* 0 - last-cyl or amount of cyls (geometry) */
1834 unsigned head; /* 0 - last-head or amount of heads (geometry) */
1835 unsigned sector; /* 0 - last-sector or amount of sectors (geometry) */
1836 } bios_chs_t;
1837
1838 static void lba_2_chs(gate_uint64_t lba_input, bios_chs_t const* geometry, bios_chs_t* ptr_output)
1839 {
1840 gate_uint64_t sector;
1841 gate_uint64_t head;
1842 gate_uint64_t cyl;
1843
1844 sector = lba_input % (gate_uint64_t)geometry->sector;
1845 cyl = lba_input / (gate_uint64_t)geometry->sector;
1846 if (geometry->head > 1)
1847 {
1848 head = cyl % (gate_uint64_t)geometry->head;
1849 cyl = cyl / (gate_uint64_t)geometry->head;
1850 }
1851 else
1852 {
1853 head = 0;
1854 }
1855 ptr_output->cylinder = (unsigned)cyl;
1856 ptr_output->head = (unsigned)head;
1857 ptr_output->sector = (unsigned)sector;
1858 }
1859
1860 /*
1861 static void chs_2_lba(bios_chs_t* ptr_input, bios_chs_t const* geometry, gate_uint64_t* ptr_output)
1862 {
1863 gate_uint64_t sectors_per_cyl = (gate_uint64_t)geometry->sector * (gate_uint64_t)geometry->head;
1864 gate_uint64_t lba = (gate_uint64_t)ptr_input->cylinder * sectors_per_cyl;
1865 lba += (gate_uint64_t)ptr_input->head * (gate_uint64_t)geometry->sector;
1866 lba += (gate_uint64_t)ptr_input->sector;
1867 *ptr_output = lba;
1868 }
1869 */
1870
1871 static unsigned bios_reset_disk(unsigned char drive_index)
1872 {
1873 gate_dos_gpregs_t gpregs = GATE_INIT_EMPTY;
1874 gpregs.a.h = 0x00;
1875 gpregs.d.l = drive_index;
1876 gate_dos_intr(0x13, &gpregs, NULL);
1877 if (GATE_FLAG_ENABLED(gpregs.flags, gate_dos_cpuflags_CF))
1878 {
1879 /* error */
1880 return 1;
1881 }
1882 /* success */
1883 return 0;
1884 }
1885
1886 static unsigned bios_access_disk_sectors(unsigned char drive_index, bios_chs_t const* ptr_chs, gate_bool_t write_access, void* ptr_buffer)
1887 {
1888 unsigned const max_try_count = write_access ? 2 : 3;
1889 unsigned try_counter;
1890 gate_bool_t error_mode = false;
1891 gate_dos_gpregs_t gpregs = GATE_INIT_EMPTY;
1892 gate_dos_memregs_t memregs = GATE_INIT_EMPTY;
1893
1894 /* retry read on errors is recommended
1895 * see: https://stanislavs.org/helppc/int_13-2.html
1896 */
1897 for (try_counter = 0; try_counter < max_try_count; ++try_counter)
1898 {
1899 if (error_mode)
1900 {
1901 bios_reset_disk(drive_index);
1902 error_mode = false;
1903 }
1904
1905 gpregs.a.h = write_access ? 0x03 : 0x02;
1906 gpregs.a.l = 1;
1907 gpregs.c.h = ptr_chs->cylinder & 0xff;
1908 gpregs.c.l = (gate_uint8_t)((ptr_chs->cylinder >> 2) & 0xc0) | (gate_uint8_t)((ptr_chs->sector + 1) & 0x3f);
1909 gpregs.d.h = (gate_uint8_t)(ptr_chs->head & 0xff);
1910 gpregs.d.l = drive_index;
1911 memregs.es = gate_dos_farptr_seg(ptr_buffer);
1912 gpregs.b.x = gate_dos_farptr_off(ptr_buffer);
1913 gpregs.flags = 0;
1914 gate_dos_intr(0x13, &gpregs, &memregs);
1915
1916 if (GATE_FLAG_ENABLED(gpregs.flags, gate_dos_cpuflags_CF))
1917 {
1918 /* error */
1919 error_mode = true;
1920 }
1921 else
1922 {
1923 /* success */
1924 break;
1925 }
1926 }
1927
1928 if (GATE_FLAG_ENABLED(gpregs.flags, gate_dos_cpuflags_CF))
1929 {
1930 /* error */
1931 gate_mem_clear(&gpregs, sizeof(gpregs));
1932 gpregs.a.h = 0x01;
1933 gpregs.d.l = drive_index;
1934 gate_dos_intr(0x13, &gpregs, NULL);
1935 return gpregs.a.h;
1936 }
1937
1938 /* success */
1939 return 0;
1940 }
1941
1942 static gate_bool_t bios_get_driveinfo(unsigned char drive_index, bios_chs_t* ptr_chs, gate_storagedrive_t* ptr_drive)
1943 {
1944 gate_dos_gpregs_t gpregs = GATE_INIT_EMPTY;
1945 gate_dos_memregs_t memregs = GATE_INIT_EMPTY;
1946 bios_chs_t chs = GATE_INIT_EMPTY;
1947 char path_buffer[] = "drive00";
1948 gate_size_t path_buffer_len = 7;
1949
1950 gpregs.a.h = 0x08;
1951 gpregs.d.l = drive_index;
1952 gate_dos_intr(0x13, &gpregs, &memregs);
1953 if (GATE_FLAG_ENABLED(gpregs.flags, gate_dos_cpuflags_CF))
1954 {
1955 return false;
1956 }
1957
1958 chs.cylinder = (((gpregs.c.x & 0xc0) << 2) | ((gpregs.c.x & 0xff00) >> 8)) + 1;
1959 chs.head = gpregs.d.h + 1;
1960 chs.sector = gpregs.c.x & 0x3f;
1961
1962 if (ptr_chs)
1963 {
1964 gate_mem_copy(ptr_chs, &chs, sizeof(chs));
1965 }
1966
1967 if (ptr_drive)
1968 {
1969 gate_mem_clear(ptr_drive, sizeof(gate_storagedrive_t));
1970 ptr_drive->blockcount = (gate_uint32_t)chs.cylinder * (gate_uint32_t)chs.head * (gate_uint32_t)chs.sector;
1971 ptr_drive->blocksize = 512;
1972 ptr_drive->deviceindex = drive_index;
1973 ptr_drive->size = ptr_drive->blockcount * ptr_drive->blocksize;
1974
1975 gate_str_print_hex_byte(&path_buffer[path_buffer_len - 2], 2, drive_index, false);
1976
1977 gate_str_print_text(ptr_drive->devicepath, sizeof(ptr_drive->devicepath), path_buffer, path_buffer_len);
1978 gate_str_print_text(ptr_drive->name, sizeof(ptr_drive->name), path_buffer, path_buffer_len);
1979 gate_str_print_text(ptr_drive->path, sizeof(ptr_drive->path), path_buffer, path_buffer_len);
1980 gate_str_print_text(ptr_drive->uid, sizeof(ptr_drive->uid), path_buffer, path_buffer_len);
1981
1982 ptr_drive->drivetype = (drive_index < 0x80) ? GATE_STORAGEDRIVE_TYPE_REMOVABLE : GATE_STORAGEDRIVE_TYPE_STANDARD;
1983 ptr_drive->flags = 0;
1984
1985 gate_str_print_text(ptr_drive->productname, sizeof(ptr_drive->productname), "BIOS drive", 10);
1986 ptr_drive->serial[0] = 0;
1987 ptr_drive->vendor[0] = 0;
1988 }
1989 return true;
1990 }
1991
1992 gate_result_t gate_storagedrive_enum(gate_enumint_t drivetype, gate_storagedrive_enum_callback_t callback, void* user_param)
1993 {
1994 unsigned char ndx;
1995 gate_storagedrive_t drive;
1996 const gate_bool_t list_floppies = GATE_FLAG_ENABLED(drivetype, GATE_STORAGEDRIVE_TYPE_REMOVABLE) || (drivetype == GATE_STORAGEDRIVE_TYPE_ALL);
1997 const gate_bool_t list_harddisks = GATE_FLAG_ENABLED(drivetype, GATE_STORAGEDRIVE_TYPE_STANDARD) || (drivetype == GATE_STORAGEDRIVE_TYPE_ALL);
1998
1999 if (list_floppies)
2000 {
2001 for (ndx = 0; ndx < 4; ++ndx)
2002 {
2003 if (bios_get_driveinfo(ndx, NULL, &drive))
2004 {
2005 if (!callback(&drive, user_param))
2006 {
2007 return GATE_RESULT_OK;
2008 }
2009 }
2010 }
2011 }
2012
2013 if (list_harddisks)
2014 {
2015 for (ndx = 0x80; ndx < 0x90; ++ndx)
2016 {
2017 if (bios_get_driveinfo(ndx, NULL, &drive))
2018 {
2019 if (!callback(&drive, user_param))
2020 {
2021 return GATE_RESULT_OK;
2022 }
2023 }
2024 }
2025 }
2026
2027 return GATE_RESULT_OK;
2028 }
2029
2030
2031 typedef struct sd_stream_class
2032 {
2033 GATE_INTERFACE_VTBL(gate_controlstream) const* vtbl;
2034
2035 gate_atomic_int_t ref_counter;
2036 unsigned char drive_index;
2037 gate_bool_t write_access;
2038
2039 bios_chs_t geometry;
2040 gate_uint64_t block_count;
2041 gate_uint64_t block_offset;
2042 gate_size_t block_size;
2043
2044 gate_size_t buffer_pos; /* read: position in buffer[] where next read-transfer will start, write: amount of data already written to buffer */
2045 char buffer[512]; /* internal buffer holding last sector-read data, or data for next sector-write operation */
2046 } sd_stream_t;
2047
2048
2049 static char const* sd_get_interface_name(void* obj)
2050 {
2051 GATE_UNUSED_ARG(obj);
2052 return GATE_INTERFACE_NAME_CONTROLSTREAM;
2053 }
2054 static void sd_release(void* obj)
2055 {
2056 sd_stream_t* self = (sd_stream_t*)obj;
2057 if (gate_atomic_int_dec(&self->ref_counter) == 0)
2058 {
2059 gate_mem_dealloc(self);
2060 }
2061 }
2062 static int sd_retain(void* obj)
2063 {
2064 sd_stream_t* self = (sd_stream_t*)obj;
2065 return gate_atomic_int_inc(&self->ref_counter);
2066 }
2067
2068 static gate_result_t sd_peek(void* obj, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
2069 {
2070 gate_result_t ret = GATE_RESULT_FAILED;
2071 sd_stream_t* self = (sd_stream_t*)obj;
2072 bios_chs_t chs;
2073 unsigned result;
2074 gate_size_t available;
2075
2076 do
2077 {
2078 if (self->write_access)
2079 {
2080 ret = GATE_RESULT_INVALIDSTATE;
2081 break;
2082 }
2083 if (self->buffer_pos >= self->block_size)
2084 {
2085 if (self->block_offset >= self->block_count)
2086 {
2087 /* end of stream reached */
2088 if (returned)
2089 {
2090 *returned = 0;
2091 }
2092 ret = GATE_RESULT_OK;
2093 break;
2094 }
2095 lba_2_chs(self->block_offset, &self->geometry, &chs);
2096 result = bios_access_disk_sectors(self->drive_index, &chs, false, &self->buffer[0]);
2097 if (result != 0)
2098 {
2099 ret = GATE_RESULT_FAILED;
2100 break;
2101 }
2102 ++self->block_offset;
2103 self->buffer_pos = 0;
2104 }
2105 available = self->block_size - self->buffer_pos;
2106 if (bufferlength > available)
2107 {
2108 bufferlength = available;
2109 }
2110 gate_mem_copy(buffer, &self->buffer[self->buffer_pos], bufferlength);
2111 if (returned)
2112 {
2113 *returned = bufferlength;
2114 }
2115 ret = GATE_RESULT_OK;
2116 } while (0);
2117 return ret;
2118 }
2119
2120 static gate_result_t sd_read(void* obj, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
2121 {
2122 gate_result_t ret = GATE_RESULT_FAILED;
2123 sd_stream_t* self = (sd_stream_t*)obj;
2124 gate_size_t extracted = 0;
2125
2126 do
2127 {
2128 if (self->write_access)
2129 {
2130 ret = GATE_RESULT_INVALIDSTATE;
2131 break;
2132 }
2133 ret = sd_peek(obj, buffer, bufferlength, &extracted);
2134 GATE_BREAK_IF_FAILED(ret);
2135 self->buffer_pos += extracted;
2136 if (returned)
2137 {
2138 *returned = extracted;
2139 }
2140 } while (0);
2141 return ret;
2142 }
2143
2144 static gate_result_t sd_write(void* obj, char const* buffer, gate_size_t bufferlength, gate_size_t* written)
2145 {
2146 gate_result_t ret = GATE_RESULT_FAILED;
2147 sd_stream_t* self = (sd_stream_t*)obj;
2148 bios_chs_t chs;
2149 unsigned result;
2150 gate_size_t avail;
2151 gate_size_t bufferused;
2152 gate_size_t processed = 0;
2153
2154 do
2155 {
2156 if (!self->write_access)
2157 {
2158 ret = GATE_RESULT_INVALIDSTATE;
2159 break;
2160 }
2161
2162 if (self->buffer_pos != 0)
2163 {
2164 avail = self->block_size - self->buffer_pos;
2165 bufferused = bufferlength;
2166 if (bufferused > avail)
2167 {
2168 bufferused = avail;
2169 }
2170 gate_mem_copy(&self->buffer[self->buffer_pos], buffer, bufferused);
2171 self->buffer_pos += bufferused;
2172 processed = bufferused;
2173 buffer += processed;
2174 bufferlength -= processed;
2175 ret = GATE_RESULT_OK;
2176
2177 if (self->buffer_pos < self->block_size)
2178 {
2179 /* not enough data to fill a complete sector */
2180 break;
2181 }
2182
2183 lba_2_chs(self->block_offset, &self->geometry, &chs);
2184 result = bios_access_disk_sectors(self->drive_index, &chs, true, &self->buffer[0]);
2185 if (result != 0)
2186 {
2187 ret = GATE_RESULT_FAILED;
2188 break;
2189 }
2190 ++self->block_offset;
2191 self->buffer_pos = 0;
2192 gate_mem_clear(&self->buffer[0], self->block_size);
2193 }
2194
2195 if (bufferlength > 0)
2196 {
2197 /* still something in the input buffer: */
2198 if (bufferlength < self->block_size)
2199 {
2200 /* not a full sector, but we can internally buffer, what we got */
2201 gate_mem_copy(self->buffer, buffer, bufferlength);
2202 self->buffer_pos = bufferlength;
2203 processed += bufferlength;
2204 ret = GATE_RESULT_OK;
2205 }
2206 else
2207 {
2208 /* we can write a whole sector, let's do it */
2209 lba_2_chs(self->block_offset, &self->geometry, &chs);
2210 result = bios_access_disk_sectors(self->drive_index, &chs, true, (void*)buffer);
2211 if (result != 0)
2212 {
2213 /* return state of previous operation (or default-ERROR if no operation was performed) */
2214 break;
2215 }
2216 ++self->block_offset;
2217 processed += self->block_size;
2218 ret = GATE_RESULT_OK;
2219 }
2220 }
2221 if (written)
2222 {
2223 *written = processed;
2224 }
2225 } while (0);
2226 return ret;
2227 }
2228 static gate_result_t sd_flush(void* obj)
2229 {
2230 gate_result_t ret = GATE_RESULT_FAILED;
2231 sd_stream_t* self = (sd_stream_t*)obj;
2232 bios_chs_t chs;
2233 unsigned result;
2234
2235 do
2236 {
2237 if (!self->write_access)
2238 {
2239 ret = GATE_RESULT_INVALIDSTATE;
2240 break;
2241 }
2242
2243 if (self->buffer_pos != 0)
2244 {
2245 lba_2_chs(self->block_offset, &self->geometry, &chs);
2246 result = bios_access_disk_sectors(self->drive_index, &chs, true, &self->buffer[0]);
2247 if (result != 0)
2248 {
2249 ret = GATE_RESULT_FAILED;
2250 break;
2251 }
2252 ++self->block_offset;
2253 self->buffer_pos = 0;
2254 }
2255 ret = GATE_RESULT_OK;
2256 } while (0);
2257
2258 return ret;
2259 }
2260
2261 static gate_result_t sd_get_resource(void* obj, gate_enumint_t resource_type, gate_uintptr_t* resource)
2262 {
2263 sd_stream_t* self = (sd_stream_t*)obj;
2264 GATE_UNUSED_ARG(resource_type);
2265 if (resource)
2266 {
2267 *resource = self->drive_index;
2268 }
2269 return GATE_RESULT_OK;
2270 }
2271
2272 static gate_result_t sd_can_read(void* obj, gate_bool_t* return_value)
2273 {
2274 sd_stream_t* self = (sd_stream_t*)obj;
2275 if (return_value)
2276 {
2277 *return_value = !self->write_access;
2278 }
2279 return GATE_RESULT_OK;
2280 }
2281
2282 static gate_result_t sd_can_write(void* obj, gate_bool_t* return_value)
2283 {
2284 sd_stream_t* self = (sd_stream_t*)obj;
2285 if (return_value)
2286 {
2287 *return_value = self->write_access;
2288 }
2289 return GATE_RESULT_OK;
2290 }
2291
2292 static gate_result_t sd_get_size(void* obj, gate_int64_t* return_value)
2293 {
2294 sd_stream_t* self = (sd_stream_t*)obj;
2295 if (return_value)
2296 {
2297 *return_value = (gate_int64_t)self->block_count * (gate_int64_t)self->block_size;
2298 }
2299 return GATE_RESULT_OK;
2300 }
2301
2302 static gate_result_t sd_get_available(void* obj, gate_int64_t* return_value)
2303 {
2304 sd_stream_t* self = (sd_stream_t*)obj;
2305 gate_int64_t total = (gate_int64_t)self->block_count * (gate_int64_t)self->block_size;
2306 gate_int64_t pos = (gate_int64_t)self->block_offset * (gate_int64_t)self->block_size;
2307 if (self->write_access)
2308 {
2309 pos += self->buffer_pos;
2310 }
2311 else
2312 {
2313 pos += (self->block_size - self->buffer_pos);
2314 }
2315 if (return_value)
2316 {
2317 *return_value = total - pos;
2318 }
2319 return GATE_RESULT_OK;
2320 }
2321
2322 static gate_result_t sd_seek(void* obj, gate_int64_t position, gate_enumint_t origin, gate_int64_t* final_position)
2323 {
2324 gate_result_t ret = GATE_RESULT_FAILED;
2325 sd_stream_t* self = (sd_stream_t*)obj;
2326 gate_int64_t pos;
2327 gate_bool_t need_update = false;
2328 do
2329 {
2330 /* TODO: Seek inside blocks, currently everything is block-aligned */
2331 switch (origin)
2332 {
2333 case GATE_STREAM_SEEK_BEGIN:
2334 {
2335 pos = position;
2336 need_update = true;
2337 break;
2338 }
2339 case GATE_STREAM_SEEK_CURRENT:
2340 {
2341 pos = (gate_int64_t)self->block_offset * (gate_int64_t)self->block_size + position;
2342 need_update = (position != 0);
2343 break;
2344 }
2345 case GATE_STREAM_SEEK_END:
2346 {
2347 pos = (gate_int64_t)self->block_count * (gate_int64_t)self->block_size + position;
2348 need_update = (position != 0);
2349 break;
2350 }
2351 default:
2352 {
2353 ret = GATE_RESULT_INVALIDARG;
2354 break;
2355 }
2356 }
2357 if (need_update)
2358 {
2359 if (pos < 0) pos = 0;
2360 self->block_offset = (gate_uint64_t)pos % (gate_uint64_t)self->block_size;
2361 self->buffer_pos = self->write_access ? 0 : self->block_size;
2362 pos = (gate_int64_t)self->block_offset * (gate_int64_t)self->block_size;
2363 }
2364 if (final_position)
2365 {
2366 *final_position = pos;
2367 }
2368 ret = GATE_RESULT_OK;
2369 } while (0);
2370
2371 return ret;
2372 }
2373
2374 static gate_result_t sd_reset(void* obj)
2375 {
2376 sd_stream_t* self = (sd_stream_t*)obj;
2377 self->block_offset = 0;
2378 self->buffer_pos = self->write_access ? 0 : self->block_size;
2379 return GATE_RESULT_OK;
2380 }
2381
2382 static gate_result_t sd_close(void* obj, gate_enumint_t close_type)
2383 {
2384 sd_stream_t* self = (sd_stream_t*)obj;
2385 GATE_UNUSED_ARG(self);
2386 GATE_UNUSED_ARG(close_type);
2387 /* TODO: introduce a close-flag */
2388 return GATE_RESULT_OK;
2389 }
2390
2391 static GATE_INTERFACE_VTBL(gate_controlstream) sd_vtbl;
2392
2393 static void gate_storagedrive_stream_init_vtbl()
2394 {
2395 if (sd_vtbl.get_interface_name == NULL)
2396 {
2397 GATE_INTERFACE_VTBL(gate_controlstream) const local_vtbl = {
2398 &sd_get_interface_name,
2399 &sd_release,
2400 &sd_retain,
2401
2402 &sd_read,
2403 &sd_peek,
2404 &sd_write,
2405 &sd_flush,
2406
2407 &sd_get_resource,
2408
2409 &sd_can_read,
2410 &sd_can_write,
2411 &sd_get_size,
2412 &sd_get_available,
2413 &sd_seek,
2414 &sd_reset,
2415 &sd_close
2416 };
2417
2418 sd_vtbl = local_vtbl;
2419 }
2420 }
2421
2422
2423 gate_result_t gate_storagedrive_openstream(gate_storagedrive_t const* drive, gate_enumint_t open_flags, gate_controlstream_t** stream)
2424 {
2425 gate_result_t ret = GATE_RESULT_FAILED;
2426 sd_stream_t* ptr_sd = NULL;
2427 bios_chs_t chs;
2428
2429 do
2430 {
2431 ptr_sd = (sd_stream_t*)gate_mem_alloc(sizeof(sd_stream_t));
2432 if (ptr_sd == NULL)
2433 {
2434 ret = GATE_RESULT_FAILED;
2435 break;
2436 }
2437
2438 gate_mem_clear(ptr_sd, sizeof(sd_stream_t));
2439 gate_storagedrive_stream_init_vtbl();
2440 ptr_sd->vtbl = &sd_vtbl;
2441 gate_atomic_int_init(&ptr_sd->ref_counter, 1);
2442 ptr_sd->drive_index = (unsigned char)drive->deviceindex;
2443 bios_get_driveinfo(ptr_sd->drive_index, &chs, NULL);
2444 gate_mem_copy(&ptr_sd->geometry, &chs, sizeof(chs));
2445 ptr_sd->block_offset = 0;
2446 ptr_sd->block_count = (gate_uint64_t)chs.cylinder * (gate_uint64_t)chs.head * (gate_uint64_t)chs.sector;
2447 ptr_sd->block_size = 512;
2448 if (open_flags == GATE_STREAM_OPEN_READ)
2449 {
2450 ptr_sd->write_access = false;
2451 ptr_sd->buffer_pos = ptr_sd->block_size;
2452 }
2453 else if (open_flags == GATE_STREAM_OPEN_WRITE)
2454 {
2455 ptr_sd->write_access = true;
2456 ptr_sd->buffer_pos = 0;
2457 }
2458 else
2459 {
2460 ret = GATE_RESULT_INVALIDARG;
2461 break;
2462 }
2463
2464 bios_reset_disk(ptr_sd->drive_index);
2465
2466 if (stream)
2467 {
2468 *stream = (gate_controlstream_t*)ptr_sd;
2469 ptr_sd = NULL;
2470 }
2471 ret = GATE_RESULT_OK;
2472 } while (0);
2473
2474 if (ptr_sd)
2475 {
2476 gate_object_release(ptr_sd);
2477 }
2478
2479 return ret;
2480 }
2481
2482 gate_result_t gate_storagedrive_queryattribs(gate_storagedrive_t const* drive, gate_enumint_t attrib_type,
2483 gate_storagedrive_attribs_callback_t callback, void* user_param)
2484 {
2485 GATE_UNUSED_ARG(drive);
2486 GATE_UNUSED_ARG(attrib_type);
2487 GATE_UNUSED_ARG(callback);
2488 GATE_UNUSED_ARG(user_param);
2489 return GATE_RESULT_NOTIMPLEMENTED;
2490 }
2491
2492 #endif
2493
2494
2495 #if defined(GATE_SYSTEM_STORAGEDRIVES_NO_IMPL)
2496
2497 gate_result_t gate_storagedrive_enum(gate_enumint_t drivetype, gate_storagedrive_enum_callback_t callback, void* user_param)
2498 {
2499 GATE_UNUSED_ARG(drivetype);
2500 GATE_UNUSED_ARG(callback);
2501 GATE_UNUSED_ARG(user_param);
2502 return GATE_RESULT_NOTIMPLEMENTED;
2503 }
2504
2505 gate_result_t gate_storagedrive_openstream(gate_storagedrive_t const* drive, gate_enumint_t open_flags, gate_controlstream_t** stream)
2506 {
2507 GATE_UNUSED_ARG(drive);
2508 GATE_UNUSED_ARG(open_flags);
2509 GATE_UNUSED_ARG(stream);
2510 return GATE_RESULT_NOTIMPLEMENTED;
2511 }
2512
2513 gate_result_t gate_storagedrive_queryattribs(gate_storagedrive_t const* drive, gate_enumint_t attrib_type,
2514 gate_storagedrive_attribs_callback_t callback, void* user_param)
2515 {
2516 GATE_UNUSED_ARG(drive);
2517 GATE_UNUSED_ARG(attrib_type);
2518 GATE_UNUSED_ARG(callback);
2519 GATE_UNUSED_ARG(user_param);
2520 return GATE_RESULT_NOTIMPLEMENTED;
2521 }
2522
2523
2524 #endif /* GATE_SYSTEM_STORAGEDRIVES_NO_IMPL */
2525
2526