GCC Code Coverage Report


Directory: src/gate/
File: src/gate/system/storagedrives.c
Date: 2025-12-12 23:40:09
Exec Total Coverage
Lines: 85 243 35.0%
Functions: 5 23 21.7%
Branches: 22 103 21.4%

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