GCC Code Coverage Report


Directory: src/gate/
File: src/gate/system/storagedrives.c
Date: 2025-09-14 13:10:38
Exec Total Coverage
Lines: 0 243 0.0%
Functions: 0 23 0.0%
Branches: 0 103 0.0%

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 static gate_bool_t gate_storagedrive_find_callback(gate_storagedrive_t const* drive, void* user_param)
53 {
54 struct gate_storagedrive_find_param* param = (struct gate_storagedrive_find_param*)user_param;
55 gate_size_t length;
56 switch (param->field_type)
57 {
58 case GATE_STORAGEDRIVE_PATH:
59 {
60 length = gate_str_length(drive->path);
61 if ((length > 0) && (0 == gate_str_compare_ic(drive->path, length, param->field->str, param->field->length)))
62 {
63 gate_mem_copy(param->drive, drive, sizeof(gate_storagedrive_t));
64 param->found = true;
65 return false;
66 }
67 }
68 case GATE_STORAGEDRIVE_UID:
69 {
70 length = gate_str_length(drive->uid);
71 if ((length > 0) && (0 == gate_str_compare_ic(drive->uid, length, param->field->str, param->field->length)))
72 {
73 gate_mem_copy(param->drive, drive, sizeof(gate_storagedrive_t));
74 param->found = true;
75 return false;
76 }
77 }
78 case GATE_STORAGEDRIVE_NAME:
79 {
80 length = gate_str_length(drive->name);
81 if ((length > 0) && (0 == gate_str_compare_ic(drive->name, length, param->field->str, param->field->length)))
82 {
83 gate_mem_copy(param->drive, drive, sizeof(gate_storagedrive_t));
84 param->found = true;
85 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 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 param.field = field;
108 param.field_type = field_type;
109 param.drive = drive;
110 param.found = false;
111
112 gate_storagedrive_enum(GATE_STORAGEDRIVE_TYPE_ALL, &gate_storagedrive_find_callback, &param);
113
114 if (param.found)
115 {
116 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 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 gate_size_t bytes_received = destbuffersize - 1;
1353 gate_result_t result;
1354 gate_size_t pos;
1355
1356 if (subpath == NULL)
1357 {
1358 pathlen = gate_str_print_text(path, sizeof(path), basepath, gate_str_length(basepath));
1359 }
1360 else
1361 {
1362 pathlen = gate_file_build_path(path, sizeof(path), basepath, gate_str_length(basepath), subpath, gate_str_length(subpath));
1363 }
1364 gate_string_create_static_len(&filepath, path, pathlen);
1365 result = gate_file_get_content_buffer(&filepath, destbuffer, &bytes_received);
1366 if (GATE_SUCCEEDED(result))
1367 {
1368 pos = gate_str_char_pos(destbuffer, bytes_received, '\n', 0);
1369 if (pos != GATE_STR_NPOS)
1370 {
1371 bytes_received = pos;
1372 }
1373 destbuffer[bytes_received] = 0;
1374 return bytes_received;
1375 }
1376 else
1377 {
1378 destbuffer[0] = 0;
1379 return 0;
1380 }
1381 }
1382
1383 static gate_bool_t gate_storagedrive_enum_cb(gate_file_entry_t const* entry, void* userparam)
1384 {
1385 struct gate_storagedrive_enum_param* dispatcher = (struct gate_storagedrive_enum_param*)userparam;
1386 gate_bool_t ret = true;
1387 gate_string_t subdir = GATE_STRING_INIT_EMPTY;
1388 gate_storagedrive_t drive;
1389 char subpath[4096];
1390 char type[512];
1391 char blocks[512];
1392 char removable[16] = GATE_INIT_EMPTY;
1393 char read_only[16] = GATE_INIT_EMPTY;
1394 gate_size_t name_len;
1395 gate_size_t prod_len;
1396 gate_size_t vend_len;
1397 gate_size_t type_len;
1398 gate_size_t block_len;
1399 gate_size_t dev_len;
1400 gate_size_t removable_len;
1401 gate_size_t read_only_len;
1402 gate_strbuilder_t name_builder;
1403 gate_size_t path_len = gate_str_length(entry->path);
1404 gate_size_t ndx;
1405 gate_uint32_t index_factor;
1406 struct stat filestat;
1407
1408 subdir.str = subpath;
1409 subdir.length = gate_file_build_path(subpath, sizeof(subpath), entry->path, path_len, "device", 6);
1410 if (GATE_SUCCEEDED(gate_file_dir_exists(&subdir)))
1411 {
1412 /* storage block device */
1413 gate_mem_clear(&drive, sizeof(drive));
1414 drive.drivetype = GATE_STORAGEDRIVE_TYPE_STANDARD;
1415 gate_str_print_text(drive.path, sizeof(drive.path), subdir.str, subdir.length);
1416
1417 name_len = read_file_line(drive.name, sizeof(drive.name), entry->path, "device/model");
1418 prod_len = read_file_line(drive.productname, sizeof(drive.productname), entry->path, "device/name");
1419 vend_len = read_file_line(drive.vendor, sizeof(drive.vendor), entry->path, "device/vendor");
1420 type_len = read_file_line(type, sizeof(type), entry->path, "device/type");
1421 block_len = read_file_line(blocks, sizeof(blocks), entry->path, "size");
1422 removable_len = read_file_line(removable, sizeof(removable), entry->path, "removable");
1423 read_only_len = read_file_line(read_only, sizeof(read_only), entry->path, "ro");
1424
1425 gate_strbuilder_create_static(&name_builder, drive.name, sizeof(drive.name), name_len);
1426
1427 if (name_len == 0)
1428 {
1429 if (prod_len > 0)
1430 {
1431 name_len = gate_strbuilder_append_text(&name_builder, drive.productname, prod_len);
1432 }
1433 else if (vend_len > 0)
1434 {
1435 name_len = gate_strbuilder_append_text(&name_builder, drive.vendor, vend_len);
1436 }
1437 name_len = gate_str_print_text(drive.name, sizeof(drive.name), drive.productname, prod_len);
1438 }
1439
1440 if (gate_str_compare(removable, removable_len, "1", 1) == 0)
1441 {
1442 drive.drivetype = GATE_STORAGEDRIVE_TYPE_REMOVABLE;
1443 }
1444 if (gate_str_compare(type, type_len, "SD", 2) == 0)
1445 {
1446 gate_strbuilder_append_cstr(&name_builder, " (MMC/SD)");
1447 }
1448 else if (gate_str_compare(type, type_len, "5", 1) == 0)
1449 {
1450 gate_strbuilder_append_cstr(&name_builder, " (CD/DVD/BR-ROM)");
1451 drive.drivetype = GATE_STORAGEDRIVE_TYPE_ROM;
1452 }
1453
1454 drive.blockcount = 0;
1455 gate_str_parse_uint64(blocks, block_len, &drive.blockcount);
1456 drive.blocksize = 512;
1457 drive.size = drive.blockcount * drive.blocksize;
1458 gate_str_print_text(drive.uid, sizeof(drive.uid), entry->path, path_len);
1459
1460 dev_len = gate_str_length(entry->name);
1461 gate_file_build_path(drive.devicepath, sizeof(drive.devicepath), "/dev/", 5, entry->name, dev_len);
1462
1463 if (0 == stat(drive.devicepath, &filestat))
1464 {
1465 if (0 != (filestat.st_mode & (S_IFBLK | S_IFCHR)))
1466 {
1467 if (dev_len <= 4)
1468 {
1469 drive.deviceindex = 0;
1470 index_factor = 1;
1471 for (ndx = 0; ndx < dev_len; ++ndx)
1472 {
1473 drive.deviceindex += ((gate_uint32_t)entry->name[dev_len - ndx - 1]) * index_factor;
1474 index_factor *= 256;
1475 }
1476 }
1477 }
1478 else
1479 {
1480 drive.devicepath[0] = 0;
1481 }
1482 }
1483 else
1484 {
1485 drive.devicepath[0] = 0;
1486 }
1487
1488 if ((dispatcher->drivetype == GATE_STORAGEDRIVE_TYPE_ALL) || ((dispatcher->drivetype & drive.drivetype) != 0))
1489 {
1490 ret = dispatcher->callback(&drive, dispatcher->user_param);
1491 }
1492 else
1493 {
1494 ret = true;
1495 }
1496 }
1497 return ret;
1498 }
1499
1500
1501 gate_result_t gate_storagedrive_enum(gate_enumint_t drivetype, gate_storagedrive_enum_callback_t callback, void* user_param)
1502 {
1503 gate_result_t ret = GATE_RESULT_FAILED;
1504 static gate_string_t const sysfs_path = { "/sys/block", 10, NULL };
1505 struct gate_storagedrive_enum_param dispatcher;
1506 dispatcher.callback = callback;
1507 dispatcher.user_param = user_param;
1508 dispatcher.drivetype = drivetype;
1509
1510 ret = gate_file_list(&sysfs_path, &gate_storagedrive_enum_cb, &dispatcher);
1511
1512 return ret;
1513 }
1514
1515
1516
1517 static void drivestream_release(void* thisptr);
1518 static int drivestream_retain(void* thisptr);
1519 static char const* drivestream_get_interface_name(void* thisptr);
1520
1521 static gate_result_t drivestream_read(void* thisptr, char* buffer, gate_size_t bufferlength, gate_size_t* returned);
1522 static gate_result_t drivestream_peek(void* thisptr, char* buffer, gate_size_t bufferlength, gate_size_t* returned);
1523 static gate_result_t drivestream_write(void* thisptr, char const* buffer, gate_size_t bufferlength, gate_size_t* written);
1524 static gate_result_t drivestream_flush(void* thisptr);
1525
1526 static gate_result_t drivestream_get_resource(void* thisptr, gate_enumint_t resource_type, gate_uintptr_t* resource);
1527
1528 static gate_result_t drivestream_can_read(void* thisptr, gate_bool_t* return_value);
1529 static gate_result_t drivestream_can_write(void* thisptr, gate_bool_t* return_value);
1530 static gate_result_t drivestream_get_size(void* thisptr, gate_int64_t* return_value);
1531 static gate_result_t drivestream_get_available(void* thisptr, gate_int64_t* return_value);
1532 static gate_result_t drivestream_seek(void* thisptr, gate_int64_t position, gate_enumint_t origin, gate_int64_t* final_position);
1533 static gate_result_t drivestream_reset(void* thisptr);
1534 static gate_result_t drivestream_close(void* thisptr, gate_enumint_t close_type);
1535
1536 static GATE_INTERFACE_VTBL(gate_controlstream) gate_drivestream_vtbl;
1537 static void gate_init_drivestream_vtbl()
1538 {
1539 if (!gate_drivestream_vtbl.get_interface_name)
1540 {
1541 GATE_INTERFACE_VTBL(gate_controlstream) const local_vtbl =
1542 {
1543 &drivestream_get_interface_name,
1544 &drivestream_release,
1545 &drivestream_retain,
1546
1547 &drivestream_read,
1548 &drivestream_peek,
1549 &drivestream_write,
1550 &drivestream_flush,
1551
1552 &drivestream_get_resource,
1553
1554 &drivestream_can_read,
1555 &drivestream_can_write,
1556 &drivestream_get_size,
1557 &drivestream_get_available,
1558 &drivestream_seek,
1559 &drivestream_reset,
1560 &drivestream_close,
1561 };
1562 gate_drivestream_vtbl = local_vtbl;
1563 }
1564 }
1565
1566 typedef struct gate_drivestream_class
1567 {
1568 GATE_INTERFACE_VTBL(gate_controlstream) const* vtbl;
1569
1570 gate_atomic_int_t ref_counter;
1571 gate_bool_t writeaccess;
1572 gate_size_t locked_handle_count;
1573
1574 gate_platform_stream_buffer_t block_stream;
1575 } gate_drivestream_t;
1576
1577
1578 gate_result_t gate_storagedrive_openstream(gate_storagedrive_t const* drive, gate_enumint_t open_flags, gate_controlstream_t** stream)
1579 {
1580 gate_result_t ret;
1581 gate_drivestream_t* drivestream = NULL;
1582 gate_bool_t writable;
1583
1584 int fd = -1;
1585 int o_flags;
1586
1587 do
1588 {
1589 if ((drive == NULL) || (stream == NULL))
1590 {
1591 ret = GATE_RESULT_INVALIDARG;
1592 break;
1593 }
1594
1595 if (open_flags == GATE_STREAM_OPEN_READ)
1596 {
1597 o_flags = O_RDONLY;
1598 writable = false;
1599 }
1600 else if (open_flags == GATE_STREAM_OPEN_WRITE)
1601 {
1602 o_flags = O_WRONLY;
1603 writable = true;
1604 }
1605 else
1606 {
1607 ret = GATE_RESULT_INVALIDARG;
1608 break;
1609 }
1610
1611 fd = gate_posix_open(drive->devicepath, o_flags, 0);
1612 if (fd == -1)
1613 {
1614 ret = gate_platform_print_last_error(NULL, 0);
1615 break;
1616 }
1617
1618 drivestream = gate_mem_alloc(sizeof(gate_drivestream_t) + (gate_size_t)drive->blocksize);
1619 if (drivestream == NULL)
1620 {
1621 ret = GATE_RESULT_OUTOFMEMORY;
1622 break;
1623 }
1624
1625 gate_init_drivestream_vtbl();
1626 drivestream->vtbl = &gate_drivestream_vtbl;
1627 gate_atomic_int_init(&drivestream->ref_counter, 1);
1628 drivestream->writeaccess = writable;
1629
1630 gate_platform_stream_buffer_init(&drivestream->block_stream, (gate_platform_stream_t)(gate_intptr_t)fd,
1631 (gate_int64_t)drive->size, 0, (gate_size_t)drive->blocksize);
1632
1633 fd = -1;
1634 *stream = (gate_controlstream_t*)drivestream;
1635 drivestream = NULL;
1636 ret = GATE_RESULT_OK;
1637 } while (0);
1638
1639 if (GATE_FAILED(ret))
1640 {
1641 if (fd != -1)
1642 {
1643 gate_posix_close(fd);
1644 }
1645 if (drivestream != NULL)
1646 {
1647 gate_mem_dealloc(drivestream);
1648 }
1649 }
1650 return ret;
1651 }
1652
1653 static void drivestream_release(void* thisptr)
1654 {
1655 gate_drivestream_t* stream = (gate_drivestream_t*)thisptr;
1656
1657 if (0 == gate_atomic_int_dec(&stream->ref_counter))
1658 {
1659 gate_platform_stream_close(&stream->block_stream.stream);
1660
1661 gate_mem_dealloc(thisptr);
1662 }
1663 }
1664 static int drivestream_retain(void* thisptr)
1665 {
1666 gate_drivestream_t* stream = (gate_drivestream_t*)thisptr;
1667 return gate_atomic_int_inc(&stream->ref_counter);
1668 }
1669 static char const* drivestream_get_interface_name(void* thisptr)
1670 {
1671 (void)thisptr;
1672 return GATE_INTERFACE_NAME_CONTROLSTREAM;
1673 }
1674
1675 static gate_result_t drivestream_read(void* thisptr, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
1676 {
1677 gate_drivestream_t* stream = (gate_drivestream_t*)thisptr;
1678 gate_result_t ret = GATE_RESULT_FAILED;
1679
1680 do
1681 {
1682 if (stream->writeaccess)
1683 {
1684 ret = GATE_RESULT_INVALIDSTATE;
1685 break;
1686 }
1687 if ((bufferlength == 0) || (buffer == NULL))
1688 {
1689 ret = GATE_RESULT_INVALIDARG;
1690 break;
1691 }
1692
1693 ret = gate_platform_stream_buffer_read(&stream->block_stream, buffer, bufferlength, returned);
1694 } while (0);
1695
1696 return ret;
1697 }
1698 static gate_result_t drivestream_peek(void* thisptr, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
1699 {
1700 (void)thisptr;
1701 (void)buffer;
1702 (void)bufferlength;
1703 (void)returned;
1704 return GATE_RESULT_NOTSUPPORTED;
1705 }
1706 static gate_result_t drivestream_write(void* thisptr, char const* buffer, gate_size_t bufferlength, gate_size_t* written)
1707 {
1708 gate_drivestream_t* stream = (gate_drivestream_t*)thisptr;
1709 gate_result_t ret = GATE_RESULT_FAILED;
1710
1711 do
1712 {
1713 if (!stream->writeaccess)
1714 {
1715 ret = GATE_RESULT_INVALIDSTATE;
1716 break;
1717 }
1718
1719 if ((bufferlength == 0) || (buffer == NULL))
1720 {
1721 ret = GATE_RESULT_INVALIDARG;
1722 break;
1723 }
1724
1725 ret = gate_platform_stream_buffer_write(&stream->block_stream, buffer, bufferlength, written);
1726 } while (0);
1727
1728 return ret;
1729 }
1730 static gate_result_t drivestream_flush(void* thisptr)
1731 {
1732 gate_result_t ret = GATE_RESULT_OK;
1733 gate_drivestream_t* stream = (gate_drivestream_t*)thisptr;
1734 if (-1 == fsync((int)(gate_intptr_t)stream->block_stream.stream))
1735 {
1736 ret = GATE_RESULT_FAILED;
1737 }
1738 return ret;
1739 }
1740
1741 static gate_result_t drivestream_get_resource(void* thisptr, gate_enumint_t resource_type, gate_uintptr_t* resource)
1742 {
1743 gate_drivestream_t* stream = (gate_drivestream_t*)thisptr;
1744 (void)resource_type;
1745 *resource = (gate_uintptr_t)(void*)stream->block_stream.stream;
1746 return GATE_RESULT_OK;
1747 }
1748
1749 static gate_result_t drivestream_can_read(void* thisptr, gate_bool_t* return_value)
1750 {
1751 gate_result_t ret = GATE_RESULT_OK;
1752 gate_drivestream_t* stream = (gate_drivestream_t*)thisptr;
1753 if (return_value)
1754 {
1755 *return_value = stream->writeaccess ? false : true;
1756 }
1757 return ret;
1758 }
1759 static gate_result_t drivestream_can_write(void* thisptr, gate_bool_t* return_value)
1760 {
1761 gate_result_t ret = GATE_RESULT_OK;
1762 gate_drivestream_t* stream = (gate_drivestream_t*)thisptr;
1763 if (return_value)
1764 {
1765 *return_value = stream->writeaccess ? true : false;
1766 }
1767 return ret;
1768 }
1769 static gate_result_t drivestream_get_size(void* thisptr, gate_int64_t* return_value)
1770 {
1771 gate_result_t ret = GATE_RESULT_OK;
1772 gate_drivestream_t* stream = (gate_drivestream_t*)thisptr;
1773 if (return_value)
1774 {
1775 *return_value = (gate_int64_t)stream->block_stream.total_size;
1776 }
1777 return ret;
1778 }
1779 static gate_result_t drivestream_get_available(void* thisptr, gate_int64_t* return_value)
1780 {
1781 gate_result_t ret = GATE_RESULT_OK;
1782 gate_drivestream_t* stream = (gate_drivestream_t*)thisptr;
1783 if (return_value)
1784 {
1785 *return_value = (gate_int64_t)stream->block_stream.total_size - (gate_int64_t)stream->block_stream.position;
1786 }
1787 return ret;
1788 }
1789 static gate_result_t drivestream_seek(void* thisptr, gate_int64_t position, gate_enumint_t origin, gate_int64_t* final_position)
1790 {
1791 gate_drivestream_t* stream = (gate_drivestream_t*)thisptr;
1792 int stream_origin;
1793 switch (origin)
1794 {
1795 case GATE_STREAM_SEEK_BEGIN:
1796 stream_origin = GATE_PLATFORM_STREAM_ORIGIN_BEGIN;
1797 break;
1798 case GATE_STREAM_SEEK_CURRENT:
1799 stream_origin = GATE_PLATFORM_STREAM_ORIGIN_CURRENT;
1800 break;
1801 case GATE_STREAM_SEEK_END:
1802 stream_origin = GATE_PLATFORM_STREAM_ORIGIN_END;
1803 break;
1804 default:
1805 return GATE_RESULT_INVALIDARG;
1806 }
1807
1808 return gate_platform_stream_buffer_seek(&stream->block_stream, position, stream_origin, final_position);
1809 }
1810 static gate_result_t drivestream_reset(void* thisptr)
1811 {
1812 (void)thisptr;
1813 return GATE_RESULT_NOTIMPLEMENTED;
1814 }
1815 static gate_result_t drivestream_close(void* thisptr, gate_enumint_t close_type)
1816 {
1817 (void)thisptr;
1818 (void)close_type;
1819 return GATE_RESULT_NOTIMPLEMENTED;
1820 }
1821
1822 gate_result_t gate_storagedrive_queryattribs(gate_storagedrive_t const* drive, gate_enumint_t attrib_type,
1823 gate_storagedrive_attribs_callback_t callback, void* user_param)
1824 {
1825 GATE_UNUSED_ARG(drive);
1826 GATE_UNUSED_ARG(attrib_type);
1827 GATE_UNUSED_ARG(callback);
1828 GATE_UNUSED_ARG(user_param);
1829 return GATE_RESULT_NOTIMPLEMENTED;
1830 }
1831
1832 #endif /* defined(GATE_SYSTEM_STORAGEDRIVES_POSIX_IMPL) */
1833
1834
1835 #if defined(GATE_SYSTEM_STORAGEDRIVES_DOS_IMPL)
1836
1837 #include "gate/platforms.h"
1838
1839 typedef struct bios_chs_class
1840 {
1841 unsigned cylinder; /* 0 - last-cyl or amount of cyls (geometry) */
1842 unsigned head; /* 0 - last-head or amount of heads (geometry) */
1843 unsigned sector; /* 0 - last-sector or amount of sectors (geometry) */
1844 } bios_chs_t;
1845
1846 static void lba_2_chs(gate_uint64_t lba_input, bios_chs_t const* geometry, bios_chs_t* ptr_output)
1847 {
1848 gate_uint64_t sector;
1849 gate_uint64_t head;
1850 gate_uint64_t cyl;
1851
1852 sector = lba_input % (gate_uint64_t)geometry->sector;
1853 cyl = lba_input / (gate_uint64_t)geometry->sector;
1854 if (geometry->head > 1)
1855 {
1856 head = cyl % (gate_uint64_t)geometry->head;
1857 cyl = cyl / (gate_uint64_t)geometry->head;
1858 }
1859 else
1860 {
1861 head = 0;
1862 }
1863 ptr_output->cylinder = (unsigned)cyl;
1864 ptr_output->head = (unsigned)head;
1865 ptr_output->sector = (unsigned)sector;
1866 }
1867
1868 /*
1869 static void chs_2_lba(bios_chs_t* ptr_input, bios_chs_t const* geometry, gate_uint64_t* ptr_output)
1870 {
1871 gate_uint64_t sectors_per_cyl = (gate_uint64_t)geometry->sector * (gate_uint64_t)geometry->head;
1872 gate_uint64_t lba = (gate_uint64_t)ptr_input->cylinder * sectors_per_cyl;
1873 lba += (gate_uint64_t)ptr_input->head * (gate_uint64_t)geometry->sector;
1874 lba += (gate_uint64_t)ptr_input->sector;
1875 *ptr_output = lba;
1876 }
1877 */
1878
1879 static unsigned bios_reset_disk(unsigned char drive_index)
1880 {
1881 gate_dos_gpregs_t gpregs = GATE_INIT_EMPTY;
1882 gpregs.a.h = 0x00;
1883 gpregs.d.l = drive_index;
1884 gate_dos_intr(0x13, &gpregs, NULL);
1885 if (GATE_FLAG_ENABLED(gpregs.flags, gate_dos_cpuflags_CF))
1886 {
1887 /* error */
1888 return 1;
1889 }
1890 /* success */
1891 return 0;
1892 }
1893
1894 static unsigned bios_access_disk_sectors(unsigned char drive_index, bios_chs_t const* ptr_chs, gate_bool_t write_access, void* ptr_buffer)
1895 {
1896 unsigned const max_try_count = write_access ? 2 : 3;
1897 unsigned try_counter;
1898 gate_bool_t error_mode = false;
1899 gate_dos_gpregs_t gpregs = GATE_INIT_EMPTY;
1900 gate_dos_memregs_t memregs = GATE_INIT_EMPTY;
1901
1902 /* retry read on errors is recommended
1903 * see: https://stanislavs.org/helppc/int_13-2.html
1904 */
1905 for (try_counter = 0; try_counter < max_try_count; ++try_counter)
1906 {
1907 if (error_mode)
1908 {
1909 bios_reset_disk(drive_index);
1910 error_mode = false;
1911 }
1912
1913 gpregs.a.h = write_access ? 0x03 : 0x02;
1914 gpregs.a.l = 1;
1915 gpregs.c.h = ptr_chs->cylinder & 0xff;
1916 gpregs.c.l = (gate_uint8_t)((ptr_chs->cylinder >> 2) & 0xc0) | (gate_uint8_t)((ptr_chs->sector + 1) & 0x3f);
1917 gpregs.d.h = (gate_uint8_t)(ptr_chs->head & 0xff);
1918 gpregs.d.l = drive_index;
1919 memregs.es = gate_dos_farptr_seg(ptr_buffer);
1920 gpregs.b.x = gate_dos_farptr_off(ptr_buffer);
1921 gpregs.flags = 0;
1922 gate_dos_intr(0x13, &gpregs, &memregs);
1923
1924 if (GATE_FLAG_ENABLED(gpregs.flags, gate_dos_cpuflags_CF))
1925 {
1926 /* error */
1927 error_mode = true;
1928 }
1929 else
1930 {
1931 /* success */
1932 break;
1933 }
1934 }
1935
1936 if (GATE_FLAG_ENABLED(gpregs.flags, gate_dos_cpuflags_CF))
1937 {
1938 /* error */
1939 gate_mem_clear(&gpregs, sizeof(gpregs));
1940 gpregs.a.h = 0x01;
1941 gpregs.d.l = drive_index;
1942 gate_dos_intr(0x13, &gpregs, NULL);
1943 return gpregs.a.h;
1944 }
1945
1946 /* success */
1947 return 0;
1948 }
1949
1950 static gate_bool_t bios_get_driveinfo(unsigned char drive_index, bios_chs_t* ptr_chs, gate_storagedrive_t* ptr_drive)
1951 {
1952 gate_dos_gpregs_t gpregs = GATE_INIT_EMPTY;
1953 gate_dos_memregs_t memregs = GATE_INIT_EMPTY;
1954 bios_chs_t chs = GATE_INIT_EMPTY;
1955 int result;
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 result = 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 ret = GATE_RESULT_OK;
2203 }
2204
2205 if (bufferlength > 0)
2206 {
2207 /* still something in the input buffer: */
2208 if (bufferlength < self->block_size)
2209 {
2210 /* not a full sector, but we can internally buffer, what we got */
2211 gate_mem_copy(self->buffer, buffer, bufferlength);
2212 self->buffer_pos = bufferlength;
2213 processed += bufferlength;
2214 ret = GATE_RESULT_OK;
2215 }
2216 else
2217 {
2218 /* we can write a whole sector, let's do it */
2219 lba_2_chs(self->block_offset, &self->geometry, &chs);
2220 result = bios_access_disk_sectors(self->drive_index, &chs, true, (void*)buffer);
2221 if (result != 0)
2222 {
2223 /* return state of previous operation (or default-ERROR if no operation was performed) */
2224 break;
2225 }
2226 ++self->block_offset;
2227 processed += self->block_size;
2228 ret = GATE_RESULT_OK;
2229 }
2230 }
2231 if (written)
2232 {
2233 *written = processed;
2234 }
2235 } while (0);
2236 return ret;
2237 }
2238 static gate_result_t sd_flush(void* obj)
2239 {
2240 gate_result_t ret = GATE_RESULT_FAILED;
2241 sd_stream_t* self = (sd_stream_t*)obj;
2242 bios_chs_t chs;
2243 unsigned result;
2244
2245 do
2246 {
2247 if (!self->write_access)
2248 {
2249 ret = GATE_RESULT_INVALIDSTATE;
2250 break;
2251 }
2252
2253 if (self->buffer_pos != 0)
2254 {
2255 lba_2_chs(self->block_offset, &self->geometry, &chs);
2256 result = bios_access_disk_sectors(self->drive_index, &chs, true, &self->buffer[0]);
2257 if (result != 0)
2258 {
2259 ret = GATE_RESULT_FAILED;
2260 break;
2261 }
2262 ++self->block_offset;
2263 self->buffer_pos = 0;
2264 }
2265 ret = GATE_RESULT_OK;
2266 } while (0);
2267
2268 return ret;
2269 }
2270
2271 static gate_result_t sd_get_resource(void* obj, gate_enumint_t resource_type, gate_uintptr_t* resource)
2272 {
2273 sd_stream_t* self = (sd_stream_t*)obj;
2274 GATE_UNUSED_ARG(resource_type);
2275 if (resource)
2276 {
2277 *resource = self->drive_index;
2278 }
2279 return GATE_RESULT_OK;
2280 }
2281
2282 static gate_result_t sd_can_read(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_can_write(void* obj, gate_bool_t* return_value)
2293 {
2294 sd_stream_t* self = (sd_stream_t*)obj;
2295 if (return_value)
2296 {
2297 *return_value = self->write_access;
2298 }
2299 return GATE_RESULT_OK;
2300 }
2301
2302 static gate_result_t sd_get_size(void* obj, gate_int64_t* return_value)
2303 {
2304 sd_stream_t* self = (sd_stream_t*)obj;
2305 if (return_value)
2306 {
2307 *return_value = (gate_int64_t)self->block_count * (gate_int64_t)self->block_size;
2308 }
2309 return GATE_RESULT_OK;
2310 }
2311
2312 static gate_result_t sd_get_available(void* obj, gate_int64_t* return_value)
2313 {
2314 sd_stream_t* self = (sd_stream_t*)obj;
2315 gate_int64_t total = (gate_int64_t)self->block_count * (gate_int64_t)self->block_size;
2316 gate_int64_t pos = (gate_int64_t)self->block_offset * (gate_int64_t)self->block_size;
2317 if (self->write_access)
2318 {
2319 pos += self->buffer_pos;
2320 }
2321 else
2322 {
2323 pos += (self->block_size - self->buffer_pos);
2324 }
2325 if (return_value)
2326 {
2327 *return_value = total - pos;
2328 }
2329 return GATE_RESULT_OK;
2330 }
2331
2332 static gate_result_t sd_seek(void* obj, gate_int64_t position, gate_enumint_t origin, gate_int64_t* final_position)
2333 {
2334 gate_result_t ret = GATE_RESULT_FAILED;
2335 sd_stream_t* self = (sd_stream_t*)obj;
2336 gate_int64_t pos;
2337 gate_bool_t need_update = false;
2338 do
2339 {
2340 /* TODO: Seek inside blocks, currently everything is block-aligned */
2341 switch (origin)
2342 {
2343 case GATE_STREAM_SEEK_BEGIN:
2344 {
2345 pos = position;
2346 need_update = true;
2347 break;
2348 }
2349 case GATE_STREAM_SEEK_CURRENT:
2350 {
2351 pos = (gate_int64_t)self->block_offset * (gate_int64_t)self->block_size + position;
2352 need_update = (position != 0);
2353 break;
2354 }
2355 case GATE_STREAM_SEEK_END:
2356 {
2357 pos = (gate_int64_t)self->block_count * (gate_int64_t)self->block_size + position;
2358 need_update = (position != 0);
2359 break;
2360 }
2361 default:
2362 {
2363 ret = GATE_RESULT_INVALIDARG;
2364 break;
2365 }
2366 }
2367 if (need_update)
2368 {
2369 if (pos < 0) pos = 0;
2370 self->block_offset = (gate_uint64_t)pos % (gate_uint64_t)self->block_size;
2371 self->buffer_pos = self->write_access ? 0 : self->block_size;
2372 pos = (gate_int64_t)self->block_offset * (gate_int64_t)self->block_size;
2373 }
2374 if (final_position)
2375 {
2376 *final_position = pos;
2377 }
2378 ret = GATE_RESULT_OK;
2379 } while (0);
2380
2381 return ret;
2382 }
2383
2384 static gate_result_t sd_reset(void* obj)
2385 {
2386 sd_stream_t* self = (sd_stream_t*)obj;
2387 self->block_offset = 0;
2388 self->buffer_pos = self->write_access ? 0 : self->block_size;
2389 return GATE_RESULT_OK;
2390 }
2391
2392 static gate_result_t sd_close(void* obj, gate_enumint_t close_type)
2393 {
2394 sd_stream_t* self = (sd_stream_t*)obj;
2395 GATE_UNUSED_ARG(self);
2396 GATE_UNUSED_ARG(close_type);
2397 /* TODO: introduce a close-flag */
2398 return GATE_RESULT_OK;
2399 }
2400
2401 static GATE_INTERFACE_VTBL(gate_controlstream) sd_vtbl;
2402
2403 static void gate_storagedrive_stream_init_vtbl()
2404 {
2405 if (sd_vtbl.get_interface_name == NULL)
2406 {
2407 GATE_INTERFACE_VTBL(gate_controlstream) const local_vtbl = {
2408 &sd_get_interface_name,
2409 &sd_release,
2410 &sd_retain,
2411
2412 &sd_read,
2413 &sd_peek,
2414 &sd_write,
2415 &sd_flush,
2416
2417 &sd_get_resource,
2418
2419 &sd_can_read,
2420 &sd_can_write,
2421 &sd_get_size,
2422 &sd_get_available,
2423 &sd_seek,
2424 &sd_reset,
2425 &sd_close
2426 };
2427
2428 sd_vtbl = local_vtbl;
2429 }
2430 }
2431
2432
2433 gate_result_t gate_storagedrive_openstream(gate_storagedrive_t const* drive, gate_enumint_t open_flags, gate_controlstream_t** stream)
2434 {
2435 gate_result_t ret = GATE_RESULT_FAILED;
2436 sd_stream_t* ptr_sd = NULL;
2437 bios_chs_t chs;
2438
2439 do
2440 {
2441 ptr_sd = (sd_stream_t*)gate_mem_alloc(sizeof(sd_stream_t));
2442 if (ptr_sd == NULL)
2443 {
2444 ret = GATE_RESULT_FAILED;
2445 break;
2446 }
2447
2448 gate_mem_clear(ptr_sd, sizeof(sd_stream_t));
2449 gate_storagedrive_stream_init_vtbl();
2450 ptr_sd->vtbl = &sd_vtbl;
2451 gate_atomic_int_init(&ptr_sd->ref_counter, 1);
2452 ptr_sd->drive_index = (unsigned char)drive->deviceindex;
2453 bios_get_driveinfo(ptr_sd->drive_index, &chs, NULL);
2454 gate_mem_copy(&ptr_sd->geometry, &chs, sizeof(chs));
2455 ptr_sd->block_offset = 0;
2456 ptr_sd->block_count = (gate_uint64_t)chs.cylinder * (gate_uint64_t)chs.head * (gate_uint64_t)chs.sector;
2457 ptr_sd->block_size = 512;
2458 if (open_flags == GATE_STREAM_OPEN_READ)
2459 {
2460 ptr_sd->write_access = false;
2461 ptr_sd->buffer_pos = ptr_sd->block_size;
2462 }
2463 else if (open_flags == GATE_STREAM_OPEN_WRITE)
2464 {
2465 ptr_sd->write_access = true;
2466 ptr_sd->buffer_pos = 0;
2467 }
2468 else
2469 {
2470 ret = GATE_RESULT_INVALIDARG;
2471 break;
2472 }
2473
2474 bios_reset_disk(ptr_sd->drive_index);
2475
2476 if (stream)
2477 {
2478 *stream = (gate_controlstream_t*)ptr_sd;
2479 ptr_sd = NULL;
2480 }
2481 ret = GATE_RESULT_OK;
2482 } while (0);
2483
2484 if (ptr_sd)
2485 {
2486 gate_object_release(ptr_sd);
2487 }
2488
2489 return ret;
2490 }
2491
2492 gate_result_t gate_storagedrive_queryattribs(gate_storagedrive_t const* drive, gate_enumint_t attrib_type,
2493 gate_storagedrive_attribs_callback_t callback, void* user_param)
2494 {
2495 GATE_UNUSED_ARG(drive);
2496 GATE_UNUSED_ARG(attrib_type);
2497 GATE_UNUSED_ARG(callback);
2498 GATE_UNUSED_ARG(user_param);
2499 return GATE_RESULT_NOTIMPLEMENTED;
2500 }
2501
2502 #endif
2503
2504
2505 #if defined(GATE_SYSTEM_STORAGEDRIVES_NO_IMPL)
2506
2507 gate_result_t gate_storagedrive_enum(gate_enumint_t drivetype, gate_storagedrive_enum_callback_t callback, void* user_param)
2508 {
2509 GATE_UNUSED_ARG(drivetype);
2510 GATE_UNUSED_ARG(callback);
2511 GATE_UNUSED_ARG(user_param);
2512 return GATE_RESULT_NOTIMPLEMENTED;
2513 }
2514
2515 gate_result_t gate_storagedrive_openstream(gate_storagedrive_t const* drive, gate_enumint_t open_flags, gate_controlstream_t** stream)
2516 {
2517 GATE_UNUSED_ARG(drive);
2518 GATE_UNUSED_ARG(open_flags);
2519 GATE_UNUSED_ARG(stream);
2520 return GATE_RESULT_NOTIMPLEMENTED;
2521 }
2522
2523 gate_result_t gate_storagedrive_queryattribs(gate_storagedrive_t const* drive, gate_enumint_t attrib_type,
2524 gate_storagedrive_attribs_callback_t callback, void* user_param)
2525 {
2526 GATE_UNUSED_ARG(drive);
2527 GATE_UNUSED_ARG(attrib_type);
2528 GATE_UNUSED_ARG(callback);
2529 GATE_UNUSED_ARG(user_param);
2530 return GATE_RESULT_NOTIMPLEMENTED;
2531 }
2532
2533
2534 #endif /* GATE_SYSTEM_STORAGEDRIVES_NO_IMPL */
2535
2536