Correct PPTP server firewall rules chain.
[tomato/davidwu.git] / release / src / router / ntfs-3g / libntfs-3g / win32_io.c
blobed9fa5218eb349fef42451268aca14e59d1e5aa7
1 /*
2 * win32_io.c - A stdio-like disk I/O implementation for low-level disk access
3 * on Win32. Can access an NTFS volume while it is mounted.
4 * Originated from the Linux-NTFS project.
6 * Copyright (c) 2003-2004 Lode Leroy
7 * Copyright (c) 2003-2006 Anton Altaparmakov
8 * Copyright (c) 2004-2005 Yuval Fledel
10 * This program/include file is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program/include file is distributed in the hope that it will be
16 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
17 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program (in the main directory of the NTFS-3G
22 * distribution in the file COPYING); if not, write to the Free Software
23 * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #include "config.h"
28 #ifdef HAVE_WINDOWS_H
29 #include <windows.h>
30 #endif
31 #include <winioctl.h>
33 #ifdef HAVE_STDIO_H
34 #include <stdio.h>
35 #endif
36 #ifdef HAVE_CTYPE_H
37 #include <ctype.h>
38 #endif
39 #ifdef HAVE_ERRNO_H
40 #include <errno.h>
41 #endif
42 #ifdef HAVE_FCNTL_H
43 #include <fcntl.h>
44 #endif
46 /* Prevent volume.h from being be loaded, as it conflicts with winnt.h. */
47 #define _NTFS_VOLUME_H
48 struct ntfs_volume;
49 typedef struct ntfs_volume ntfs_volume;
51 #include "debug.h"
52 #include "types.h"
53 #include "device.h"
55 #ifndef MAX_PATH
56 #define MAX_PATH 1024
57 #endif
59 #ifndef NTFS_BLOCK_SIZE
60 #define NTFS_BLOCK_SIZE 512
61 #define NTFS_BLOCK_SIZE_BITS 9
62 #endif
64 #ifndef IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS
65 #define IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS 5636096
66 #endif
68 /* Windows 2k+ imports. */
69 typedef HANDLE (WINAPI *LPFN_FINDFIRSTVOLUME)(LPTSTR, DWORD);
70 typedef BOOL (WINAPI *LPFN_FINDNEXTVOLUME)(HANDLE, LPTSTR, DWORD);
71 typedef BOOL (WINAPI *LPFN_FINDVOLUMECLOSE)(HANDLE);
72 typedef BOOL (WINAPI *LPFN_SETFILEPOINTEREX)(HANDLE, LARGE_INTEGER,
73 PLARGE_INTEGER, DWORD);
75 static LPFN_FINDFIRSTVOLUME fnFindFirstVolume = NULL;
76 static LPFN_FINDNEXTVOLUME fnFindNextVolume = NULL;
77 static LPFN_FINDVOLUMECLOSE fnFindVolumeClose = NULL;
78 static LPFN_SETFILEPOINTEREX fnSetFilePointerEx = NULL;
80 #ifdef UNICODE
81 #define FNPOSTFIX "W"
82 #else
83 #define FNPOSTFIX "A"
84 #endif
86 /**
87 * struct win32_fd -
89 typedef struct {
90 HANDLE handle;
91 s64 pos; /* Logical current position on the volume. */
92 s64 part_start;
93 s64 part_length;
94 int part_hidden_sectors;
95 s64 geo_size, geo_cylinders;
96 DWORD geo_sectors, geo_heads;
97 HANDLE vol_handle;
98 } win32_fd;
101 * ntfs_w32error_to_errno - convert a win32 error code to the unix one
102 * @w32error: the win32 error code
104 * Limited to a relatively small but useful number of codes.
106 static int ntfs_w32error_to_errno(unsigned int w32error)
108 ntfs_log_trace("Converting w32error 0x%x.\n",w32error);
109 switch (w32error) {
110 case ERROR_INVALID_FUNCTION:
111 return EBADRQC;
112 case ERROR_FILE_NOT_FOUND:
113 case ERROR_PATH_NOT_FOUND:
114 case ERROR_INVALID_NAME:
115 return ENOENT;
116 case ERROR_TOO_MANY_OPEN_FILES:
117 return EMFILE;
118 case ERROR_ACCESS_DENIED:
119 return EACCES;
120 case ERROR_INVALID_HANDLE:
121 return EBADF;
122 case ERROR_NOT_ENOUGH_MEMORY:
123 return ENOMEM;
124 case ERROR_OUTOFMEMORY:
125 return ENOSPC;
126 case ERROR_INVALID_DRIVE:
127 case ERROR_BAD_UNIT:
128 return ENODEV;
129 case ERROR_WRITE_PROTECT:
130 return EROFS;
131 case ERROR_NOT_READY:
132 case ERROR_SHARING_VIOLATION:
133 return EBUSY;
134 case ERROR_BAD_COMMAND:
135 return EINVAL;
136 case ERROR_SEEK:
137 case ERROR_NEGATIVE_SEEK:
138 return ESPIPE;
139 case ERROR_NOT_SUPPORTED:
140 return EOPNOTSUPP;
141 case ERROR_BAD_NETPATH:
142 return ENOSHARE;
143 default:
144 /* generic message */
145 return ENOMSG;
150 * libntfs_SetFilePointerEx - emulation for SetFilePointerEx()
152 * We use this to emulate SetFilePointerEx() when it is not present. This can
153 * happen since SetFilePointerEx() only exists in Win2k+.
155 static BOOL WINAPI libntfs_SetFilePointerEx(HANDLE hFile,
156 LARGE_INTEGER liDistanceToMove,
157 PLARGE_INTEGER lpNewFilePointer, DWORD dwMoveMethod)
159 liDistanceToMove.LowPart = SetFilePointer(hFile,
160 liDistanceToMove.LowPart, &liDistanceToMove.HighPart,
161 dwMoveMethod);
162 if (liDistanceToMove.LowPart == INVALID_SET_FILE_POINTER &&
163 GetLastError() != NO_ERROR) {
164 if (lpNewFilePointer)
165 lpNewFilePointer->QuadPart = -1;
166 return FALSE;
168 if (lpNewFilePointer)
169 lpNewFilePointer->QuadPart = liDistanceToMove.QuadPart;
170 return TRUE;
174 * ntfs_device_win32_init_imports - initialize the function pointers
176 * The Find*Volume and SetFilePointerEx functions exist only on win2k+, as such
177 * we cannot just staticly import them.
179 * This function initializes the imports if the functions do exist and in the
180 * SetFilePointerEx case, we emulate the function ourselves if it is not
181 * present.
183 * Note: The values are cached, do be afraid to run it more than once.
185 static void ntfs_device_win32_init_imports(void)
187 HMODULE kernel32 = GetModuleHandle("kernel32");
188 if (!kernel32) {
189 errno = ntfs_w32error_to_errno(GetLastError());
190 ntfs_log_trace("kernel32.dll could not be imported.\n");
192 if (!fnSetFilePointerEx) {
193 if (kernel32)
194 fnSetFilePointerEx = (LPFN_SETFILEPOINTEREX)
195 GetProcAddress(kernel32,
196 "SetFilePointerEx");
198 * If we did not get kernel32.dll or it is not Win2k+, emulate
199 * SetFilePointerEx().
201 if (!fnSetFilePointerEx) {
202 ntfs_log_debug("SetFilePonterEx() not found in "
203 "kernel32.dll: Enabling emulation.\n");
204 fnSetFilePointerEx = libntfs_SetFilePointerEx;
207 /* Cannot do lookups if we could not get kernel32.dll... */
208 if (!kernel32)
209 return;
210 if (!fnFindFirstVolume)
211 fnFindFirstVolume = (LPFN_FINDFIRSTVOLUME)
212 GetProcAddress(kernel32, "FindFirstVolume"
213 FNPOSTFIX);
214 if (!fnFindNextVolume)
215 fnFindNextVolume = (LPFN_FINDNEXTVOLUME)
216 GetProcAddress(kernel32, "FindNextVolume"
217 FNPOSTFIX);
218 if (!fnFindVolumeClose)
219 fnFindVolumeClose = (LPFN_FINDVOLUMECLOSE)
220 GetProcAddress(kernel32, "FindVolumeClose");
224 * ntfs_device_unix_status_flags_to_win32 - convert unix->win32 open flags
225 * @flags: unix open status flags
227 * Supported flags are O_RDONLY, O_WRONLY and O_RDWR.
229 static __inline__ int ntfs_device_unix_status_flags_to_win32(int flags)
231 int win_mode;
233 switch (flags & O_ACCMODE) {
234 case O_RDONLY:
235 win_mode = FILE_READ_DATA;
236 break;
237 case O_WRONLY:
238 win_mode = FILE_WRITE_DATA;
239 break;
240 case O_RDWR:
241 win_mode = FILE_READ_DATA | FILE_WRITE_DATA;
242 break;
243 default:
244 /* error */
245 ntfs_log_trace("Unknown status flags.\n");
246 win_mode = 0;
248 return win_mode;
253 * ntfs_device_win32_simple_open_file - just open a file via win32 API
254 * @filename: name of the file to open
255 * @handle: pointer the a HANDLE in which to put the result
256 * @flags: unix open status flags
257 * @locking: will the function gain an exclusive lock on the file?
259 * Supported flags are O_RDONLY, O_WRONLY and O_RDWR.
261 * Return 0 if o.k.
262 * -1 if not, and errno set. In this case handle is trashed.
264 static int ntfs_device_win32_simple_open_file(const char *filename,
265 HANDLE *handle, int flags, BOOL locking)
267 *handle = CreateFile(filename,
268 ntfs_device_unix_status_flags_to_win32(flags),
269 locking ? 0 : (FILE_SHARE_WRITE | FILE_SHARE_READ),
270 NULL, OPEN_EXISTING, 0, NULL);
271 if (*handle == INVALID_HANDLE_VALUE) {
272 errno = ntfs_w32error_to_errno(GetLastError());
273 ntfs_log_trace("CreateFile(%s) failed.\n", filename);
274 return -1;
276 return 0;
280 * ntfs_device_win32_lock - lock the volume
281 * @handle: a win32 HANDLE for a volume to lock
283 * Locking a volume means no one can access its contents.
284 * Exiting the process automatically unlocks the volume, except in old NT4s.
286 * Return 0 if o.k.
287 * -1 if not, and errno set.
289 static int ntfs_device_win32_lock(HANDLE handle)
291 DWORD i;
293 if (!DeviceIoControl(handle, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &i,
294 NULL)) {
295 errno = ntfs_w32error_to_errno(GetLastError());
296 ntfs_log_trace("Couldn't lock volume.\n");
297 return -1;
299 ntfs_log_debug("Volume locked.\n");
300 return 0;
304 * ntfs_device_win32_unlock - unlock the volume
305 * @handle: the win32 HANDLE which the volume was locked with
307 * Return 0 if o.k.
308 * -1 if not, and errno set.
310 static int ntfs_device_win32_unlock(HANDLE handle)
312 DWORD i;
314 if (!DeviceIoControl(handle, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0, &i,
315 NULL)) {
316 errno = ntfs_w32error_to_errno(GetLastError());
317 ntfs_log_trace("Couldn't unlock volume.\n");
318 return -1;
320 ntfs_log_debug("Volume unlocked.\n");
321 return 0;
325 * ntfs_device_win32_dismount - dismount a volume
326 * @handle: a win32 HANDLE for a volume to dismount
328 * Dismounting means the system will refresh the volume in the first change it
329 * gets. Usefull after altering the file structures.
330 * The volume must be locked by the current process while dismounting.
331 * A side effect is that the volume is also unlocked, but you must not rely om
332 * this.
334 * Return 0 if o.k.
335 * -1 if not, and errno set.
337 static int ntfs_device_win32_dismount(HANDLE handle)
339 DWORD i;
341 if (!DeviceIoControl(handle, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0,
342 &i, NULL)) {
343 errno = ntfs_w32error_to_errno(GetLastError());
344 ntfs_log_trace("Couldn't dismount volume.\n");
345 return -1;
347 ntfs_log_debug("Volume dismounted.\n");
348 return 0;
352 * ntfs_device_win32_getsize - get file size via win32 API
353 * @handle: pointer the file HANDLE obtained via open
355 * Only works on ordinary files.
357 * Return The file size if o.k.
358 * -1 if not, and errno set.
360 static s64 ntfs_device_win32_getsize(HANDLE handle)
362 DWORD loword, hiword;
364 loword = GetFileSize(handle, &hiword);
365 if (loword == INVALID_FILE_SIZE) {
366 errno = ntfs_w32error_to_errno(GetLastError());
367 ntfs_log_trace("Couldn't get file size.\n");
368 return -1;
370 return ((s64)hiword << 32) + loword;
374 * ntfs_device_win32_getdisklength - get disk size via win32 API
375 * @handle: pointer the file HANDLE obtained via open
376 * @argp: pointer to result buffer
378 * Only works on PhysicalDriveX type handles.
380 * Return The disk size if o.k.
381 * -1 if not, and errno set.
383 static s64 ntfs_device_win32_getdisklength(HANDLE handle)
385 GET_LENGTH_INFORMATION buf;
386 DWORD i;
388 if (!DeviceIoControl(handle, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &buf,
389 sizeof(buf), &i, NULL)) {
390 errno = ntfs_w32error_to_errno(GetLastError());
391 ntfs_log_trace("Couldn't get disk length.\n");
392 return -1;
394 ntfs_log_debug("Disk length: %lld.\n", buf.Length.QuadPart);
395 return buf.Length.QuadPart;
399 * ntfs_device_win32_getntfssize - get NTFS volume size via win32 API
400 * @handle: pointer the file HANDLE obtained via open
401 * @argp: pointer to result buffer
403 * Only works on NTFS volume handles.
404 * An annoying bug in windows is that an NTFS volume does not occupy the entire
405 * partition, namely not the last sector (which holds the backup boot sector,
406 * and normally not interesting).
407 * Use this function to get the length of the accessible space through a given
408 * volume handle.
410 * Return The volume size if o.k.
411 * -1 if not, and errno set.
413 static s64 ntfs_device_win32_getntfssize(HANDLE handle)
415 s64 rvl;
416 #ifdef FSCTL_GET_NTFS_VOLUME_DATA
417 DWORD i;
418 NTFS_VOLUME_DATA_BUFFER buf;
420 if (!DeviceIoControl(handle, FSCTL_GET_NTFS_VOLUME_DATA, NULL, 0, &buf,
421 sizeof(buf), &i, NULL)) {
422 errno = ntfs_w32error_to_errno(GetLastError());
423 ntfs_log_trace("Couldn't get NTFS volume length.\n");
424 return -1;
426 rvl = buf.NumberSectors.QuadPart * buf.BytesPerSector;
427 ntfs_log_debug("NTFS volume length: 0x%llx.\n", (long long)rvl);
428 #else
429 errno = EINVAL;
430 rvl = -1;
431 #endif
432 return rvl;
436 * ntfs_device_win32_getgeo - get CHS information of a drive
437 * @handle: an open handle to the PhysicalDevice
438 * @fd: a win_fd structure that will be filled
440 * Return 0 if o.k.
441 * -1 if not, and errno set.
443 * In Windows NT+: fills size, sectors, and cylinders and sets heads to -1.
444 * In Windows XP+: fills size, sectors, cylinders, and heads.
446 * Note: In pre XP, this requires write permission, even though nothing is
447 * actually written.
449 * If fails, sets sectors, cylinders, heads, and size to -1.
451 static int ntfs_device_win32_getgeo(HANDLE handle, win32_fd *fd)
453 DWORD i;
454 BOOL rvl;
455 BYTE b[sizeof(DISK_GEOMETRY) + sizeof(DISK_PARTITION_INFO) +
456 sizeof(DISK_DETECTION_INFO) + 512];
458 rvl = DeviceIoControl(handle, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL,
459 0, &b, sizeof(b), &i, NULL);
460 if (rvl) {
461 ntfs_log_debug("GET_DRIVE_GEOMETRY_EX detected.\n");
462 DISK_DETECTION_INFO *ddi = (PDISK_DETECTION_INFO)
463 (((PBYTE)(&((PDISK_GEOMETRY_EX)b)->Data)) +
464 (((PDISK_PARTITION_INFO)
465 (&((PDISK_GEOMETRY_EX)b)->Data))->
466 SizeOfPartitionInfo));
467 fd->geo_cylinders = ((DISK_GEOMETRY*)&b)->Cylinders.QuadPart;
468 fd->geo_sectors = ((DISK_GEOMETRY*)&b)->SectorsPerTrack;
469 fd->geo_size = ((DISK_GEOMETRY_EX*)&b)->DiskSize.QuadPart;
470 switch (ddi->DetectionType) {
471 case DetectInt13:
472 fd->geo_cylinders = ddi->Int13.MaxCylinders;
473 fd->geo_sectors = ddi->Int13.SectorsPerTrack;
474 fd->geo_heads = ddi->Int13.MaxHeads;
475 return 0;
476 case DetectExInt13:
477 fd->geo_cylinders = ddi->ExInt13.ExCylinders;
478 fd->geo_sectors = ddi->ExInt13.ExSectorsPerTrack;
479 fd->geo_heads = ddi->ExInt13.ExHeads;
480 return 0;
481 case DetectNone:
482 default:
483 break;
485 } else
486 fd->geo_heads = -1;
487 rvl = DeviceIoControl(handle, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0,
488 &b, sizeof(b), &i, NULL);
489 if (rvl) {
490 ntfs_log_debug("GET_DRIVE_GEOMETRY detected.\n");
491 fd->geo_cylinders = ((DISK_GEOMETRY*)&b)->Cylinders.QuadPart;
492 fd->geo_sectors = ((DISK_GEOMETRY*)&b)->SectorsPerTrack;
493 fd->geo_size = fd->geo_cylinders * fd->geo_sectors *
494 ((DISK_GEOMETRY*)&b)->TracksPerCylinder *
495 ((DISK_GEOMETRY*)&b)->BytesPerSector;
496 return 0;
498 errno = ntfs_w32error_to_errno(GetLastError());
499 ntfs_log_trace("Couldn't retrieve disk geometry.\n");
500 fd->geo_cylinders = -1;
501 fd->geo_sectors = -1;
502 fd->geo_size = -1;
503 return -1;
507 * ntfs_device_win32_open_file - open a file via win32 API
508 * @filename: name of the file to open
509 * @fd: pointer to win32 file device in which to put the result
510 * @flags: unix open status flags
512 * Return 0 if o.k.
513 * -1 if not, and errno set.
515 static __inline__ int ntfs_device_win32_open_file(char *filename, win32_fd *fd,
516 int flags)
518 HANDLE handle;
520 if (ntfs_device_win32_simple_open_file(filename, &handle, flags,
521 FALSE)) {
522 /* open error */
523 return -1;
525 /* fill fd */
526 fd->handle = handle;
527 fd->part_start = 0;
528 fd->part_length = ntfs_device_win32_getsize(handle);
529 fd->pos = 0;
530 fd->part_hidden_sectors = -1;
531 fd->geo_size = -1; /* used as a marker that this is a file */
532 fd->vol_handle = INVALID_HANDLE_VALUE;
533 return 0;
537 * ntfs_device_win32_open_drive - open a drive via win32 API
538 * @drive_id: drive to open
539 * @fd: pointer to win32 file device in which to put the result
540 * @flags: unix open status flags
542 * return 0 if o.k.
543 * -1 if not, and errno set.
545 static __inline__ int ntfs_device_win32_open_drive(int drive_id, win32_fd *fd,
546 int flags)
548 HANDLE handle;
549 int err;
550 char filename[MAX_PATH];
552 sprintf(filename, "\\\\.\\PhysicalDrive%d", drive_id);
553 if ((err = ntfs_device_win32_simple_open_file(filename, &handle, flags,
554 TRUE))) {
555 /* open error */
556 return err;
558 /* store the drive geometry */
559 ntfs_device_win32_getgeo(handle, fd);
560 /* Just to be sure */
561 if (fd->geo_size == -1)
562 fd->geo_size = ntfs_device_win32_getdisklength(handle);
563 /* fill fd */
564 fd->handle = handle;
565 fd->part_start = 0;
566 fd->part_length = fd->geo_size;
567 fd->pos = 0;
568 fd->part_hidden_sectors = -1;
569 fd->vol_handle = INVALID_HANDLE_VALUE;
570 return 0;
574 * ntfs_device_win32_open_volume_for_partition - find and open a volume
576 * Windows NT/2k/XP handles volumes instead of partitions.
577 * This function gets the partition details and return an open volume handle.
578 * That volume is the one whose only physical location on disk is the described
579 * partition.
581 * The function required Windows 2k/XP, otherwise it fails (gracefully).
583 * Return success: a valid open volume handle.
584 * fail : INVALID_HANDLE_VALUE
586 static HANDLE ntfs_device_win32_open_volume_for_partition(unsigned int drive_id,
587 s64 part_offset, s64 part_length, int flags)
589 HANDLE vol_find_handle;
590 TCHAR vol_name[MAX_PATH];
592 /* Make sure all the required imports exist. */
593 if (!fnFindFirstVolume || !fnFindNextVolume || !fnFindVolumeClose) {
594 ntfs_log_trace("Required dll imports not found.\n");
595 return INVALID_HANDLE_VALUE;
597 /* Start iterating through volumes. */
598 ntfs_log_trace("Entering with drive_id=%d, part_offset=%lld, "
599 "path_length=%lld, flags=%d.\n", drive_id,
600 (unsigned long long)part_offset,
601 (unsigned long long)part_length, flags);
602 vol_find_handle = fnFindFirstVolume(vol_name, MAX_PATH);
603 /* If a valid handle could not be aquired, reply with "don't know". */
604 if (vol_find_handle == INVALID_HANDLE_VALUE) {
605 ntfs_log_trace("FindFirstVolume failed.\n");
606 return INVALID_HANDLE_VALUE;
608 do {
609 int vol_name_length;
610 HANDLE handle;
612 /* remove trailing '/' from vol_name */
613 #ifdef UNICODE
614 vol_name_length = wcslen(vol_name);
615 #else
616 vol_name_length = strlen(vol_name);
617 #endif
618 if (vol_name_length>0)
619 vol_name[vol_name_length-1]=0;
621 ntfs_log_debug("Processing %s.\n", vol_name);
622 /* open the file */
623 handle = CreateFile(vol_name,
624 ntfs_device_unix_status_flags_to_win32(flags),
625 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
626 OPEN_EXISTING, 0, NULL);
627 if (handle != INVALID_HANDLE_VALUE) {
628 DWORD bytesReturned;
629 #define EXTENTS_SIZE sizeof(VOLUME_DISK_EXTENTS) + 9 * sizeof(DISK_EXTENT)
630 char extents[EXTENTS_SIZE];
632 /* Check physical locations. */
633 if (DeviceIoControl(handle,
634 IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
635 NULL, 0, extents, EXTENTS_SIZE,
636 &bytesReturned, NULL)) {
637 if (((VOLUME_DISK_EXTENTS *)extents)->
638 NumberOfDiskExtents == 1) {
639 DISK_EXTENT *extent = &((
640 VOLUME_DISK_EXTENTS *)
641 extents)->Extents[0];
642 if ((extent->DiskNumber==drive_id) &&
643 (extent->StartingOffset.
644 QuadPart==part_offset)
645 && (extent->
646 ExtentLength.QuadPart
647 == part_length)) {
649 * Eureka! (Archimedes, 287 BC,
650 * "I have found it!")
652 fnFindVolumeClose(
653 vol_find_handle);
654 return handle;
658 } else
659 ntfs_log_trace("getExtents() Failed.\n");
660 } while (fnFindNextVolume(vol_find_handle, vol_name, MAX_PATH));
661 /* End of iteration through volumes. */
662 ntfs_log_trace("Closing, volume was not found.\n");
663 fnFindVolumeClose(vol_find_handle);
664 return INVALID_HANDLE_VALUE;
668 * ntfs_device_win32_find_partition - locates partition details by id.
669 * @handle: HANDLE to the PhysicalDrive
670 * @partition_id: the partition number to locate
671 * @part_offset: pointer to where to put the offset to the partition
672 * @part_length: pointer to where to put the length of the partition
673 * @hidden_sectors: pointer to where to put the hidden sectors
675 * This function requires an open PhysicalDrive handle and a partition_id.
676 * If a partition with the required id is found on the supplied device,
677 * the partition attributes are returned back.
679 * Returns: TRUE if found, and sets the output parameters.
680 * FALSE if not and errno is set to the error code.
682 static BOOL ntfs_device_win32_find_partition(HANDLE handle, DWORD partition_id,
683 s64 *part_offset, s64 *part_length, int *hidden_sectors)
685 DRIVE_LAYOUT_INFORMATION *drive_layout;
686 unsigned int err, buf_size, part_count;
687 DWORD i;
690 * There is no way to know the required buffer, so if the ioctl fails,
691 * try doubling the buffer size each time until the ioctl succeeds.
693 part_count = 8;
694 do {
695 buf_size = sizeof(DRIVE_LAYOUT_INFORMATION) +
696 part_count * sizeof(PARTITION_INFORMATION);
697 drive_layout = malloc(buf_size);
698 if (!drive_layout) {
699 errno = ENOMEM;
700 return FALSE;
702 if (DeviceIoControl(handle, IOCTL_DISK_GET_DRIVE_LAYOUT, NULL,
703 0, (BYTE*)drive_layout, buf_size, &i, NULL))
704 break;
705 err = GetLastError();
706 free(drive_layout);
707 if (err != ERROR_INSUFFICIENT_BUFFER) {
708 ntfs_log_trace("GetDriveLayout failed.\n");
709 errno = ntfs_w32error_to_errno(err);
710 return FALSE;
712 ntfs_log_debug("More than %u partitions.\n", part_count);
713 part_count <<= 1;
714 if (part_count > 512) {
715 ntfs_log_trace("GetDriveLayout failed: More than 512 "
716 "partitions?\n");
717 errno = ENOBUFS;
718 return FALSE;
720 } while (1);
721 for (i = 0; i < drive_layout->PartitionCount; i++) {
722 if (drive_layout->PartitionEntry[i].PartitionNumber ==
723 partition_id) {
724 *part_offset = drive_layout->PartitionEntry[i].
725 StartingOffset.QuadPart;
726 *part_length = drive_layout->PartitionEntry[i].
727 PartitionLength.QuadPart;
728 *hidden_sectors = drive_layout->PartitionEntry[i].
729 HiddenSectors;
730 free(drive_layout);
731 return TRUE;
734 free(drive_layout);
735 errno = ENOENT;
736 return FALSE;
740 * ntfs_device_win32_open_partition - open a partition via win32 API
741 * @drive_id: drive to open
742 * @partition_id: partition to open
743 * @fd: win32 file device to return
744 * @flags: unix open status flags
746 * Return 0 if o.k.
747 * -1 if not, and errno set.
749 * When fails, fd contents may have not been preserved.
751 static int ntfs_device_win32_open_partition(int drive_id,
752 unsigned int partition_id, win32_fd *fd, int flags)
754 s64 part_start, part_length;
755 HANDLE handle;
756 int err, hidden_sectors;
757 char drive_name[MAX_PATH];
759 sprintf(drive_name, "\\\\.\\PhysicalDrive%d", drive_id);
760 /* Open the entire device without locking, ask questions later */
761 if ((err = ntfs_device_win32_simple_open_file(drive_name, &handle,
762 flags, FALSE))) {
763 /* error */
764 return err;
766 if (ntfs_device_win32_find_partition(handle, partition_id, &part_start,
767 &part_length, &hidden_sectors)) {
768 s64 tmp;
769 HANDLE vol_handle = ntfs_device_win32_open_volume_for_partition(
770 drive_id, part_start, part_length, flags);
771 /* Store the drive geometry. */
772 ntfs_device_win32_getgeo(handle, fd);
773 fd->handle = handle;
774 fd->pos = 0;
775 fd->part_start = part_start;
776 fd->part_length = part_length;
777 fd->part_hidden_sectors = hidden_sectors;
778 tmp = ntfs_device_win32_getntfssize(vol_handle);
779 if (tmp > 0)
780 fd->geo_size = tmp;
781 else
782 fd->geo_size = fd->part_length;
783 if (vol_handle != INVALID_HANDLE_VALUE) {
784 if (((flags & O_RDWR) == O_RDWR) &&
785 ntfs_device_win32_lock(vol_handle)) {
786 CloseHandle(vol_handle);
787 CloseHandle(handle);
788 return -1;
790 fd->vol_handle = vol_handle;
791 } else {
792 if ((flags & O_RDWR) == O_RDWR) {
793 /* Access if read-write, no volume found. */
794 ntfs_log_trace("Partitions containing Spanned/"
795 "Mirrored volumes are not "
796 "supported in R/W status "
797 "yet.\n");
798 CloseHandle(handle);
799 errno = EOPNOTSUPP;
800 return -1;
802 fd->vol_handle = INVALID_HANDLE_VALUE;
804 return 0;
805 } else {
806 ntfs_log_debug("Partition %u not found on drive %d.\n",
807 partition_id, drive_id);
808 CloseHandle(handle);
809 errno = ENODEV;
810 return -1;
815 * ntfs_device_win32_open - open a device
816 * @dev: a pointer to the NTFS_DEVICE to open
817 * @flags: unix open status flags
819 * @dev->d_name must hold the device name, the rest is ignored.
820 * Supported flags are O_RDONLY, O_WRONLY and O_RDWR.
822 * If name is in format "(hd[0-9],[0-9])" then open a partition.
823 * If name is in format "(hd[0-9])" then open a volume.
824 * Otherwise open a file.
826 static int ntfs_device_win32_open(struct ntfs_device *dev, int flags)
828 int drive_id = 0, numparams;
829 unsigned int part = 0;
830 char drive_char;
831 win32_fd fd;
832 int err;
834 if (NDevOpen(dev)) {
835 errno = EBUSY;
836 return -1;
838 ntfs_device_win32_init_imports();
839 numparams = sscanf(dev->d_name, "/dev/hd%c%u", &drive_char, &part);
840 drive_id = toupper(drive_char) - 'A';
841 switch (numparams) {
842 case 0:
843 ntfs_log_debug("win32_open(%s) -> file.\n", dev->d_name);
844 err = ntfs_device_win32_open_file(dev->d_name, &fd, flags);
845 break;
846 case 1:
847 ntfs_log_debug("win32_open(%s) -> drive %d.\n", dev->d_name,
848 drive_id);
849 err = ntfs_device_win32_open_drive(drive_id, &fd, flags);
850 break;
851 case 2:
852 ntfs_log_debug("win32_open(%s) -> drive %d, part %u.\n",
853 dev->d_name, drive_id, part);
854 err = ntfs_device_win32_open_partition(drive_id, part, &fd,
855 flags);
856 break;
857 default:
858 ntfs_log_debug("win32_open(%s) -> unknwon file format.\n",
859 dev->d_name);
860 err = -1;
862 if (err)
863 return err;
864 ntfs_log_debug("win32_open(%s) -> %p, offset 0x%llx.\n", dev->d_name,
865 dev, fd.part_start);
866 /* Setup our read-only flag. */
867 if ((flags & O_RDWR) != O_RDWR)
868 NDevSetReadOnly(dev);
869 dev->d_private = malloc(sizeof(win32_fd));
870 memcpy(dev->d_private, &fd, sizeof(win32_fd));
871 NDevSetOpen(dev);
872 NDevClearDirty(dev);
873 return 0;
877 * ntfs_device_win32_seek - change current logical file position
878 * @dev: ntfs device obtained via ->open
879 * @offset: required offset from the whence anchor
880 * @whence: whence anchor specifying what @offset is relative to
882 * Return the new position on the volume on success and -1 on error with errno
883 * set to the error code.
885 * @whence may be one of the following:
886 * SEEK_SET - Offset is relative to file start.
887 * SEEK_CUR - Offset is relative to current position.
888 * SEEK_END - Offset is relative to end of file.
890 static s64 ntfs_device_win32_seek(struct ntfs_device *dev, s64 offset,
891 int whence)
893 s64 abs_ofs;
894 win32_fd *fd = (win32_fd *)dev->d_private;
896 ntfs_log_trace("seek offset = 0x%llx, whence = %d.\n", offset, whence);
897 switch (whence) {
898 case SEEK_SET:
899 abs_ofs = offset;
900 break;
901 case SEEK_CUR:
902 abs_ofs = fd->pos + offset;
903 break;
904 case SEEK_END:
905 /* End of partition != end of disk. */
906 if (fd->part_length == -1) {
907 ntfs_log_trace("Position relative to end of disk not "
908 "implemented.\n");
909 errno = EOPNOTSUPP;
910 return -1;
912 abs_ofs = fd->part_length + offset;
913 break;
914 default:
915 ntfs_log_trace("Wrong mode %d.\n", whence);
916 errno = EINVAL;
917 return -1;
919 if (abs_ofs < 0 || abs_ofs > fd->part_length) {
920 ntfs_log_trace("Seeking outsize seekable area.\n");
921 errno = EINVAL;
922 return -1;
924 fd->pos = abs_ofs;
925 return abs_ofs;
929 * ntfs_device_win32_pio - positioned low level i/o
930 * @fd: win32 device descriptor obtained via ->open
931 * @pos: at which position to do i/o from/to
932 * @count: how many bytes should be transfered
933 * @b: source/destination buffer
934 * @write: TRUE if write transfer and FALSE if read transfer
936 * On success returns the number of bytes transfered (can be < @count) and on
937 * error returns -1 and errno set. Transfer starts from position @pos on @fd.
939 * Notes:
940 * - @pos, @buf, and @count must be aligned to NTFS_BLOCK_SIZE.
941 * - When dealing with volumes, a single call must not span both volume
942 * and disk extents.
943 * - Does not use/set @fd->pos.
945 static s64 ntfs_device_win32_pio(win32_fd *fd, const s64 pos,
946 const s64 count, void *b, const BOOL write)
948 LARGE_INTEGER li;
949 HANDLE handle;
950 DWORD bt;
951 BOOL res;
953 ntfs_log_trace("pos = 0x%llx, count = 0x%llx, direction = %s.\n",
954 (long long)pos, (long long)count, write ? "write" :
955 "read");
956 li.QuadPart = pos;
957 if (fd->vol_handle != INVALID_HANDLE_VALUE && pos < fd->geo_size) {
958 ntfs_log_debug("Transfering via vol_handle.\n");
959 handle = fd->vol_handle;
960 } else {
961 ntfs_log_debug("Transfering via handle.\n");
962 handle = fd->handle;
963 li.QuadPart += fd->part_start;
965 if (!fnSetFilePointerEx(handle, li, NULL, FILE_BEGIN)) {
966 errno = ntfs_w32error_to_errno(GetLastError());
967 ntfs_log_trace("SetFilePointer failed.\n");
968 return -1;
970 if (write)
971 res = WriteFile(handle, b, count, &bt, NULL);
972 else
973 res = ReadFile(handle, b, count, &bt, NULL);
974 if (!res) {
975 errno = ntfs_w32error_to_errno(GetLastError());
976 ntfs_log_trace("%sFile() failed.\n", write ? "Write" : "Read");
977 return -1;
979 return bt;
983 * ntfs_device_win32_pread_simple - positioned simple read
984 * @fd: win32 device descriptor obtained via ->open
985 * @pos: at which position to read from
986 * @count: how many bytes should be read
987 * @b: a pointer to where to put the contents
989 * On success returns the number of bytes read (can be < @count) and on error
990 * returns -1 and errno set. Read starts from position @pos.
992 * Notes:
993 * - @pos, @buf, and @count must be aligned to NTFS_BLOCK_SIZE.
994 * - When dealing with volumes, a single call must not span both volume
995 * and disk extents.
996 * - Does not use/set @fd->pos.
998 static inline s64 ntfs_device_win32_pread_simple(win32_fd *fd, const s64 pos,
999 const s64 count, void *b)
1001 return ntfs_device_win32_pio(fd, pos, count, b, FALSE);
1005 * ntfs_device_win32_read - read bytes from an ntfs device
1006 * @dev: ntfs device obtained via ->open
1007 * @b: pointer to where to put the contents
1008 * @count: how many bytes should be read
1010 * On success returns the number of bytes actually read (can be < @count).
1011 * On error returns -1 with errno set.
1013 static s64 ntfs_device_win32_read(struct ntfs_device *dev, void *b, s64 count)
1015 s64 old_pos, to_read, i, br = 0;
1016 win32_fd *fd = (win32_fd *)dev->d_private;
1017 BYTE *alignedbuffer;
1018 int old_ofs, ofs;
1020 old_pos = fd->pos;
1021 old_ofs = ofs = old_pos & (NTFS_BLOCK_SIZE - 1);
1022 to_read = (ofs + count + NTFS_BLOCK_SIZE - 1) &
1023 ~(s64)(NTFS_BLOCK_SIZE - 1);
1024 /* Impose maximum of 2GB to be on the safe side. */
1025 if (to_read > 0x80000000) {
1026 int delta = to_read - count;
1027 to_read = 0x80000000;
1028 count = to_read - delta;
1030 ntfs_log_trace("fd = %p, b = %p, count = 0x%llx, pos = 0x%llx, "
1031 "ofs = %i, to_read = 0x%llx.\n", fd, b,
1032 (long long)count, (long long)old_pos, ofs,
1033 (long long)to_read);
1034 if (!((unsigned long)b & (NTFS_BLOCK_SIZE - 1)) && !old_ofs &&
1035 !(count & (NTFS_BLOCK_SIZE - 1)))
1036 alignedbuffer = b;
1037 else {
1038 alignedbuffer = (BYTE *)VirtualAlloc(NULL, to_read, MEM_COMMIT,
1039 PAGE_READWRITE);
1040 if (!alignedbuffer) {
1041 errno = ntfs_w32error_to_errno(GetLastError());
1042 ntfs_log_trace("VirtualAlloc failed for read.\n");
1043 return -1;
1046 if (fd->vol_handle != INVALID_HANDLE_VALUE && old_pos < fd->geo_size) {
1047 s64 vol_to_read = fd->geo_size - old_pos;
1048 if (count > vol_to_read) {
1049 br = ntfs_device_win32_pread_simple(fd,
1050 old_pos & ~(s64)(NTFS_BLOCK_SIZE - 1),
1051 ofs + vol_to_read, alignedbuffer);
1052 if (br == -1)
1053 goto read_error;
1054 to_read -= br;
1055 if (br < ofs) {
1056 br = 0;
1057 goto read_partial;
1059 br -= ofs;
1060 fd->pos += br;
1061 ofs = fd->pos & (NTFS_BLOCK_SIZE - 1);
1062 if (br != vol_to_read)
1063 goto read_partial;
1066 i = ntfs_device_win32_pread_simple(fd,
1067 fd->pos & ~(s64)(NTFS_BLOCK_SIZE - 1), to_read,
1068 alignedbuffer + br);
1069 if (i == -1) {
1070 if (br)
1071 goto read_partial;
1072 goto read_error;
1074 if (i < ofs)
1075 goto read_partial;
1076 i -= ofs;
1077 br += i;
1078 if (br > count)
1079 br = count;
1080 fd->pos = old_pos + br;
1081 read_partial:
1082 if (alignedbuffer != b) {
1083 memcpy((void*)b, alignedbuffer + old_ofs, br);
1084 VirtualFree(alignedbuffer, 0, MEM_RELEASE);
1086 return br;
1087 read_error:
1088 if (alignedbuffer != b)
1089 VirtualFree(alignedbuffer, 0, MEM_RELEASE);
1090 return -1;
1094 * ntfs_device_win32_close - close an open ntfs deivce
1095 * @dev: ntfs device obtained via ->open
1097 * Return 0 if o.k.
1098 * -1 if not, and errno set. Note if error fd->vol_handle is trashed.
1100 static int ntfs_device_win32_close(struct ntfs_device *dev)
1102 win32_fd *fd = (win32_fd *)dev->d_private;
1103 BOOL rvl;
1105 ntfs_log_trace("Closing device %p.\n", dev);
1106 if (!NDevOpen(dev)) {
1107 errno = EBADF;
1108 return -1;
1110 if (fd->vol_handle != INVALID_HANDLE_VALUE) {
1111 if (!NDevReadOnly(dev)) {
1112 ntfs_device_win32_dismount(fd->vol_handle);
1113 ntfs_device_win32_unlock(fd->vol_handle);
1115 if (!CloseHandle(fd->vol_handle))
1116 ntfs_log_trace("CloseHandle() failed for volume.\n");
1118 rvl = CloseHandle(fd->handle);
1119 free(fd);
1120 if (!rvl) {
1121 errno = ntfs_w32error_to_errno(GetLastError());
1122 ntfs_log_trace("CloseHandle() failed.\n");
1123 return -1;
1125 return 0;
1129 * ntfs_device_win32_sync - flush write buffers to disk
1130 * @dev: ntfs device obtained via ->open
1132 * Return 0 if o.k.
1133 * -1 if not, and errno set.
1135 * Note: Volume syncing works differently in windows.
1136 * Disk cannot be synced in windows.
1138 static int ntfs_device_win32_sync(struct ntfs_device *dev)
1140 int err = 0;
1141 BOOL to_clear = TRUE;
1143 if (!NDevReadOnly(dev) && NDevDirty(dev)) {
1144 win32_fd *fd = (win32_fd *)dev->d_private;
1146 if ((fd->vol_handle != INVALID_HANDLE_VALUE) &&
1147 !FlushFileBuffers(fd->vol_handle)) {
1148 to_clear = FALSE;
1149 err = ntfs_w32error_to_errno(GetLastError());
1151 if (!FlushFileBuffers(fd->handle)) {
1152 to_clear = FALSE;
1153 if (!err)
1154 err = ntfs_w32error_to_errno(GetLastError());
1156 if (!to_clear) {
1157 ntfs_log_trace("Could not sync.\n");
1158 errno = err;
1159 return -1;
1161 NDevClearDirty(dev);
1163 return 0;
1167 * ntfs_device_win32_pwrite_simple - positioned simple write
1168 * @fd: win32 device descriptor obtained via ->open
1169 * @pos: at which position to write to
1170 * @count: how many bytes should be written
1171 * @b: a pointer to the data to write
1173 * On success returns the number of bytes written and on error returns -1 and
1174 * errno set. Write starts from position @pos.
1176 * Notes:
1177 * - @pos, @buf, and @count must be aligned to NTFS_BLOCK_SIZE.
1178 * - When dealing with volumes, a single call must not span both volume
1179 * and disk extents.
1180 * - Does not use/set @fd->pos.
1182 static inline s64 ntfs_device_win32_pwrite_simple(win32_fd *fd, const s64 pos,
1183 const s64 count, const void *b)
1185 return ntfs_device_win32_pio(fd, pos, count, (void *)b, TRUE);
1189 * ntfs_device_win32_write - write bytes to an ntfs device
1190 * @dev: ntfs device obtained via ->open
1191 * @b: pointer to the data to write
1192 * @count: how many bytes should be written
1194 * On success returns the number of bytes actually written.
1195 * On error returns -1 with errno set.
1197 static s64 ntfs_device_win32_write(struct ntfs_device *dev, const void *b,
1198 s64 count)
1200 s64 old_pos, to_write, i, bw = 0;
1201 win32_fd *fd = (win32_fd *)dev->d_private;
1202 BYTE *alignedbuffer;
1203 int old_ofs, ofs;
1205 old_pos = fd->pos;
1206 old_ofs = ofs = old_pos & (NTFS_BLOCK_SIZE - 1);
1207 to_write = (ofs + count + NTFS_BLOCK_SIZE - 1) &
1208 ~(s64)(NTFS_BLOCK_SIZE - 1);
1209 /* Impose maximum of 2GB to be on the safe side. */
1210 if (to_write > 0x80000000) {
1211 int delta = to_write - count;
1212 to_write = 0x80000000;
1213 count = to_write - delta;
1215 ntfs_log_trace("fd = %p, b = %p, count = 0x%llx, pos = 0x%llx, "
1216 "ofs = %i, to_write = 0x%llx.\n", fd, b,
1217 (long long)count, (long long)old_pos, ofs,
1218 (long long)to_write);
1219 if (NDevReadOnly(dev)) {
1220 ntfs_log_trace("Can't write on a R/O device.\n");
1221 errno = EROFS;
1222 return -1;
1224 if (!count)
1225 return 0;
1226 NDevSetDirty(dev);
1227 if (!((unsigned long)b & (NTFS_BLOCK_SIZE - 1)) && !old_ofs &&
1228 !(count & (NTFS_BLOCK_SIZE - 1)))
1229 alignedbuffer = (BYTE *)b;
1230 else {
1231 s64 end;
1233 alignedbuffer = (BYTE *)VirtualAlloc(NULL, to_write,
1234 MEM_COMMIT, PAGE_READWRITE);
1235 if (!alignedbuffer) {
1236 errno = ntfs_w32error_to_errno(GetLastError());
1237 ntfs_log_trace("VirtualAlloc failed for write.\n");
1238 return -1;
1240 /* Read first sector if start of write not sector aligned. */
1241 if (ofs) {
1242 i = ntfs_device_win32_pread_simple(fd,
1243 old_pos & ~(s64)(NTFS_BLOCK_SIZE - 1),
1244 NTFS_BLOCK_SIZE, alignedbuffer);
1245 if (i != NTFS_BLOCK_SIZE) {
1246 if (i >= 0)
1247 errno = EIO;
1248 goto write_error;
1252 * Read last sector if end of write not sector aligned and last
1253 * sector is either not the same as the first sector or it is
1254 * the same as the first sector but this has not been read in
1255 * yet, i.e. the start of the write is sector aligned.
1257 end = old_pos + count;
1258 if ((end & (NTFS_BLOCK_SIZE - 1)) &&
1259 ((to_write > NTFS_BLOCK_SIZE) || !ofs)) {
1260 i = ntfs_device_win32_pread_simple(fd,
1261 end & ~(s64)(NTFS_BLOCK_SIZE - 1),
1262 NTFS_BLOCK_SIZE, alignedbuffer +
1263 to_write - NTFS_BLOCK_SIZE);
1264 if (i != NTFS_BLOCK_SIZE) {
1265 if (i >= 0)
1266 errno = EIO;
1267 goto write_error;
1270 /* Copy the data to be written into @alignedbuffer. */
1271 memcpy(alignedbuffer + ofs, b, count);
1273 if (fd->vol_handle != INVALID_HANDLE_VALUE && old_pos < fd->geo_size) {
1274 s64 vol_to_write = fd->geo_size - old_pos;
1275 if (count > vol_to_write) {
1276 bw = ntfs_device_win32_pwrite_simple(fd,
1277 old_pos & ~(s64)(NTFS_BLOCK_SIZE - 1),
1278 ofs + vol_to_write, alignedbuffer);
1279 if (bw == -1)
1280 goto write_error;
1281 to_write -= bw;
1282 if (bw < ofs) {
1283 bw = 0;
1284 goto write_partial;
1286 bw -= ofs;
1287 fd->pos += bw;
1288 ofs = fd->pos & (NTFS_BLOCK_SIZE - 1);
1289 if (bw != vol_to_write)
1290 goto write_partial;
1293 i = ntfs_device_win32_pwrite_simple(fd,
1294 fd->pos & ~(s64)(NTFS_BLOCK_SIZE - 1), to_write,
1295 alignedbuffer + bw);
1296 if (i == -1) {
1297 if (bw)
1298 goto write_partial;
1299 goto write_error;
1301 if (i < ofs)
1302 goto write_partial;
1303 i -= ofs;
1304 bw += i;
1305 if (bw > count)
1306 bw = count;
1307 fd->pos = old_pos + bw;
1308 write_partial:
1309 if (alignedbuffer != b)
1310 VirtualFree(alignedbuffer, 0, MEM_RELEASE);
1311 return bw;
1312 write_error:
1313 bw = -1;
1314 goto write_partial;
1318 * ntfs_device_win32_stat - get a unix-like stat structure for an ntfs device
1319 * @dev: ntfs device obtained via ->open
1320 * @buf: pointer to the stat structure to fill
1322 * Note: Only st_mode, st_size, and st_blocks are filled.
1324 * Return 0 if o.k.
1325 * -1 if not and errno set. in this case handle is trashed.
1327 static int ntfs_device_win32_stat(struct ntfs_device *dev, struct stat *buf)
1329 win32_fd *fd = (win32_fd *)dev->d_private;
1330 mode_t st_mode;
1332 switch (GetFileType(fd->handle)) {
1333 case FILE_TYPE_CHAR:
1334 st_mode = S_IFCHR;
1335 break;
1336 case FILE_TYPE_DISK:
1337 st_mode = S_IFBLK;
1338 break;
1339 case FILE_TYPE_PIPE:
1340 st_mode = S_IFIFO;
1341 break;
1342 default:
1343 st_mode = 0;
1345 memset(buf, 0, sizeof(struct stat));
1346 buf->st_mode = st_mode;
1347 buf->st_size = fd->part_length;
1348 if (buf->st_size != -1)
1349 buf->st_blocks = buf->st_size >> 9;
1350 else
1351 buf->st_size = 0;
1352 return 0;
1356 * ntfs_win32_hdio_getgeo - get drive geometry
1357 * @dev: ntfs device obtained via ->open
1358 * @argp: pointer to where to put the output
1360 * Note: Works on windows NT/2k/XP only.
1362 * Return 0 if o.k.
1363 * -1 if not, and errno set. Note if error fd->handle is trashed.
1365 static __inline__ int ntfs_win32_hdio_getgeo(struct ntfs_device *dev,
1366 struct hd_geometry *argp)
1368 win32_fd *fd = (win32_fd *)dev->d_private;
1370 argp->heads = fd->geo_heads;
1371 argp->sectors = fd->geo_sectors;
1372 argp->cylinders = fd->geo_cylinders;
1373 argp->start = fd->part_hidden_sectors;
1374 return 0;
1378 * ntfs_win32_blksszget - get block device sector size
1379 * @dev: ntfs device obtained via ->open
1380 * @argp: pointer to where to put the output
1382 * Note: Works on windows NT/2k/XP only.
1384 * Return 0 if o.k.
1385 * -1 if not, and errno set. Note if error fd->handle is trashed.
1387 static __inline__ int ntfs_win32_blksszget(struct ntfs_device *dev,int *argp)
1389 win32_fd *fd = (win32_fd *)dev->d_private;
1390 DWORD bytesReturned;
1391 DISK_GEOMETRY dg;
1393 if (DeviceIoControl(fd->handle, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0,
1394 &dg, sizeof(DISK_GEOMETRY), &bytesReturned, NULL)) {
1395 /* success */
1396 *argp = dg.BytesPerSector;
1397 return 0;
1399 errno = ntfs_w32error_to_errno(GetLastError());
1400 ntfs_log_trace("GET_DRIVE_GEOMETRY failed.\n");
1401 return -1;
1404 static int ntfs_device_win32_ioctl(struct ntfs_device *dev, int request,
1405 void *argp)
1407 win32_fd *fd = (win32_fd *)dev->d_private;
1409 ntfs_log_trace("win32_ioctl(%d) called.\n", request);
1410 switch (request) {
1411 #if defined(BLKGETSIZE)
1412 case BLKGETSIZE:
1413 ntfs_log_debug("BLKGETSIZE detected.\n");
1414 if (fd->part_length >= 0) {
1415 *(int *)argp = (int)(fd->part_length / 512);
1416 return 0;
1418 errno = EOPNOTSUPP;
1419 return -1;
1420 #endif
1421 #if defined(BLKGETSIZE64)
1422 case BLKGETSIZE64:
1423 ntfs_log_debug("BLKGETSIZE64 detected.\n");
1424 if (fd->part_length >= 0) {
1425 *(s64 *)argp = fd->part_length;
1426 return 0;
1428 errno = EOPNOTSUPP;
1429 return -1;
1430 #endif
1431 #ifdef HDIO_GETGEO
1432 case HDIO_GETGEO:
1433 ntfs_log_debug("HDIO_GETGEO detected.\n");
1434 return ntfs_win32_hdio_getgeo(dev, (struct hd_geometry *)argp);
1435 #endif
1436 #ifdef BLKSSZGET
1437 case BLKSSZGET:
1438 ntfs_log_debug("BLKSSZGET detected.\n");
1439 return ntfs_win32_blksszget(dev, (int *)argp);
1440 #endif
1441 #ifdef BLKBSZSET
1442 case BLKBSZSET:
1443 ntfs_log_debug("BLKBSZSET detected.\n");
1444 /* Nothing to do on Windows. */
1445 return 0;
1446 #endif
1447 default:
1448 ntfs_log_debug("unimplemented ioctl %d.\n", request);
1449 errno = EOPNOTSUPP;
1450 return -1;
1454 static s64 ntfs_device_win32_pread(struct ntfs_device *dev, void *b,
1455 s64 count, s64 offset)
1457 return ntfs_pread(dev, offset, count, b);
1460 static s64 ntfs_device_win32_pwrite(struct ntfs_device *dev, const void *b,
1461 s64 count, s64 offset)
1463 return ntfs_pwrite(dev, offset, count, b);
1466 struct ntfs_device_operations ntfs_device_win32_io_ops = {
1467 .open = ntfs_device_win32_open,
1468 .close = ntfs_device_win32_close,
1469 .seek = ntfs_device_win32_seek,
1470 .read = ntfs_device_win32_read,
1471 .write = ntfs_device_win32_write,
1472 .pread = ntfs_device_win32_pread,
1473 .pwrite = ntfs_device_win32_pwrite,
1474 .sync = ntfs_device_win32_sync,
1475 .stat = ntfs_device_win32_stat,
1476 .ioctl = ntfs_device_win32_ioctl