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. 5 * 6 * Copyright (c) 2003-2004 Lode Leroy 7 * Copyright (c) 2003-2006 Anton Altaparmakov 8 * Copyright (c) 2004-2005 Yuval Fledel 9 * Copyright (c) 2012-2013 Jean-Pierre Andre 10 * 11 * This program/include file is free software; you can redistribute it and/or 12 * modify it under the terms of the GNU General Public License as published 13 * by the Free Software Foundation; either version 2 of the License, or 14 * (at your option) any later version. 15 * 16 * This program/include file is distributed in the hope that it will be 17 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty 18 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 * GNU General Public License for more details. 20 * 21 * You should have received a copy of the GNU General Public License 22 * along with this program (in the main directory of the NTFS-3G 23 * distribution in the file COPYING); if not, write to the Free Software 24 * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 25 */ 26 27 #include "config.h" 28 29 #ifdef HAVE_WINDOWS_H 30 #define BOOL WINBOOL /* avoid conflicting definitions of BOOL */ 31 #include <windows.h> 32 #undef BOOL 33 #endif 34 35 #ifdef HAVE_STDLIB_H 36 #include <stdlib.h> 37 #endif 38 39 /* 40 * Definitions needed for <winioctl.h> 41 */ 42 #ifndef _ANONYMOUS_UNION 43 #define _ANONYMOUS_UNION 44 #define _ANONYMOUS_STRUCT 45 typedef unsigned long long DWORD64; 46 #endif 47 48 typedef struct { 49 DWORD data1; /* The first eight hexadecimal digits of the GUID. */ 50 WORD data2; /* The first group of four hexadecimal digits. */ 51 WORD data3; /* The second group of four hexadecimal digits. */ 52 char data4[8]; /* The first two bytes are the third group of four 53 hexadecimal digits. The remaining six bytes are the 54 final 12 hexadecimal digits. */ 55 } GUID; 56 57 #include <winioctl.h> 58 59 #ifdef HAVE_STDIO_H 60 #include <stdio.h> 61 #endif 62 #ifdef HAVE_CTYPE_H 63 #include <ctype.h> 64 #endif 65 #ifdef HAVE_ERRNO_H 66 #include <errno.h> 67 #endif 68 #ifdef HAVE_FCNTL_H 69 #include <fcntl.h> 70 #endif 71 #ifdef HAVE_SYS_STAT_H 72 #include <sys/stat.h> 73 #define stat stat64 74 #define st_blocks st_rdev /* emulate st_blocks, missing in Windows */ 75 #endif 76 77 /* Prevent volume.h from being be loaded, as it conflicts with winnt.h. */ 78 #define _NTFS_VOLUME_H 79 struct ntfs_volume; 80 typedef struct ntfs_volume ntfs_volume; 81 82 #include "debug.h" 83 #include "types.h" 84 #include "device.h" 85 #include "misc.h" 86 87 #define cpu_to_le16(x) (x) 88 #define const_cpu_to_le16(x) (x) 89 90 #ifndef MAX_PATH 91 #define MAX_PATH 1024 92 #endif 93 94 #ifndef NTFS_BLOCK_SIZE 95 #define NTFS_BLOCK_SIZE 512 96 #define NTFS_BLOCK_SIZE_BITS 9 97 #endif 98 99 #ifndef INVALID_SET_FILE_POINTER 100 #define INVALID_SET_FILE_POINTER ((DWORD)-1) 101 #endif 102 103 #ifndef IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS 104 #define IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS 5636096 105 #endif 106 107 #ifndef IOCTL_DISK_GET_DRIVE_GEOMETRY 108 #define IOCTL_DISK_GET_DRIVE_GEOMETRY 0x70000 109 #endif 110 111 #ifndef IOCTL_GET_DISK_LENGTH_INFO 112 #define IOCTL_GET_DISK_LENGTH_INFO 0x7405c 113 #endif 114 115 #ifndef FSCTL_ALLOW_EXTENDED_DASD_IO 116 #define FSCTL_ALLOW_EXTENDED_DASD_IO 0x90083 117 #endif 118 119 /* Windows 2k+ imports. */ 120 typedef HANDLE (WINAPI *LPFN_FINDFIRSTVOLUME)(LPTSTR, DWORD); 121 typedef BOOL (WINAPI *LPFN_FINDNEXTVOLUME)(HANDLE, LPTSTR, DWORD); 122 typedef BOOL (WINAPI *LPFN_FINDVOLUMECLOSE)(HANDLE); 123 typedef BOOL (WINAPI *LPFN_SETFILEPOINTEREX)(HANDLE, LARGE_INTEGER, 124 PLARGE_INTEGER, DWORD); 125 126 static LPFN_FINDFIRSTVOLUME fnFindFirstVolume = NULL; 127 static LPFN_FINDNEXTVOLUME fnFindNextVolume = NULL; 128 static LPFN_FINDVOLUMECLOSE fnFindVolumeClose = NULL; 129 static LPFN_SETFILEPOINTEREX fnSetFilePointerEx = NULL; 130 131 #ifdef UNICODE 132 #define FNPOSTFIX "W" 133 #else 134 #define FNPOSTFIX "A" 135 #endif 136 137 enum { /* see http://msdn.microsoft.com/en-us/library/cc704588(v=prot.10).aspx */ 138 STATUS_UNKNOWN = -1, 139 STATUS_SUCCESS = 0x00000000, 140 STATUS_BUFFER_OVERFLOW = 0x80000005, 141 STATUS_INVALID_HANDLE = 0xC0000008, 142 STATUS_INVALID_PARAMETER = 0xC000000D, 143 STATUS_INVALID_DEVICE_REQUEST = 0xC0000010, 144 STATUS_END_OF_FILE = 0xC0000011, 145 STATUS_CONFLICTING_ADDRESSES = 0xC0000018, 146 STATUS_NO_MATCH = 0xC000001E, 147 STATUS_ACCESS_DENIED = 0xC0000022, 148 STATUS_BUFFER_TOO_SMALL = 0xC0000023, 149 STATUS_OBJECT_TYPE_MISMATCH = 0xC0000024, 150 STATUS_FILE_NOT_FOUND = 0xC0000028, 151 STATUS_OBJECT_NAME_INVALID = 0xC0000033, 152 STATUS_OBJECT_NAME_NOT_FOUND = 0xC0000034, 153 STATUS_INVALID_PARAMETER_1 = 0xC00000EF, 154 STATUS_IO_DEVICE_ERROR = 0xC0000185, 155 STATUS_GUARD_PAGE_VIOLATION = 0x80000001 156 } ; 157 158 typedef u32 NTSTATUS; /* do not let the compiler choose the size */ 159 #ifdef __x86_64__ 160 typedef unsigned long long ULONG_PTR; /* an integer the same size as a pointer */ 161 #else 162 typedef unsigned long ULONG_PTR; /* an integer the same size as a pointer */ 163 #endif 164 165 HANDLE get_osfhandle(int); /* from msvcrt.dll */ 166 167 /* 168 * A few needed definitions not included in <windows.h> 169 */ 170 171 typedef struct _IO_STATUS_BLOCK { 172 union { 173 NTSTATUS Status; 174 PVOID Pointer; 175 }; 176 ULONG_PTR Information; 177 } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; 178 179 typedef struct _UNICODE_STRING { 180 USHORT Length; 181 USHORT MaximumLength; 182 #ifdef __x86_64__ 183 u32 padding; 184 #endif 185 PWSTR Buffer; 186 } UNICODE_STRING, *PUNICODE_STRING; 187 188 typedef struct _OBJECT_ATTRIBUTES { 189 ULONG Length; 190 #ifdef __x86_64__ 191 u32 padding1; 192 HANDLE RootDirectory; 193 PUNICODE_STRING ObjectName; 194 ULONG Attributes; 195 u32 padding2; 196 #else 197 HANDLE RootDirectory; 198 PUNICODE_STRING ObjectName; 199 ULONG Attributes; 200 #endif 201 PVOID SecurityDescriptor; 202 PVOID SecurityQualityOfService; 203 } OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES; 204 205 #define FILE_OPEN 1 206 #define FILE_CREATE 2 207 #define FILE_OVERWRITE 4 208 #define FILE_SYNCHRONOUS_IO_ALERT 0x10 209 #define FILE_SYNCHRONOUS_IO_NONALERT 0x20 210 #define OBJ_CASE_INSENSITIVE 0x40 211 212 typedef void (WINAPI *PIO_APC_ROUTINE)(void*, PIO_STATUS_BLOCK, ULONG); 213 214 extern WINAPI NTSTATUS NtOpenFile( 215 PHANDLE FileHandle, 216 ACCESS_MASK DesiredAccess, 217 POBJECT_ATTRIBUTES ObjectAttributes, 218 PIO_STATUS_BLOCK IoStatusBlock, 219 ULONG ShareAccess, 220 ULONG OpenOptions 221 ); 222 223 extern WINAPI NTSTATUS NtReadFile( 224 HANDLE FileHandle, 225 HANDLE Event, 226 PIO_APC_ROUTINE ApcRoutine, 227 PVOID ApcContext, 228 PIO_STATUS_BLOCK IoStatusBlock, 229 PVOID Buffer, 230 ULONG Length, 231 PLARGE_INTEGER ByteOffset, 232 PULONG Key 233 ); 234 235 extern WINAPI NTSTATUS NtWriteFile( 236 HANDLE FileHandle, 237 HANDLE Event, 238 PIO_APC_ROUTINE ApcRoutine, 239 PVOID ApcContext, 240 PIO_STATUS_BLOCK IoStatusBlock, 241 LPCVOID Buffer, 242 ULONG Length, 243 PLARGE_INTEGER ByteOffset, 244 PULONG Key 245 ); 246 247 extern NTSTATUS WINAPI NtClose( 248 HANDLE Handle 249 ); 250 251 extern NTSTATUS WINAPI NtDeviceIoControlFile( 252 HANDLE FileHandle, 253 HANDLE Event, 254 PIO_APC_ROUTINE ApcRoutine, 255 PVOID ApcContext, 256 PIO_STATUS_BLOCK IoStatusBlock, 257 ULONG IoControlCode, 258 PVOID InputBuffer, 259 ULONG InputBufferLength, 260 PVOID OutputBuffer, 261 ULONG OutputBufferLength 262 ); 263 264 extern NTSTATUS WINAPI NtFsControlFile( 265 HANDLE FileHandle, 266 HANDLE Event, 267 PIO_APC_ROUTINE ApcRoutine, 268 PVOID ApcContext, 269 PIO_STATUS_BLOCK IoStatusBlock, 270 ULONG FsControlCode, 271 PVOID InputBuffer, 272 ULONG InputBufferLength, 273 PVOID OutputBuffer, 274 ULONG OutputBufferLength 275 ); 276 277 /** 278 * struct win32_fd - 279 */ 280 typedef struct { 281 HANDLE handle; 282 s64 pos; /* Logical current position on the volume. */ 283 s64 part_start; 284 s64 part_length; 285 int part_hidden_sectors; 286 s64 geo_size, geo_cylinders; 287 s32 geo_sector_size; 288 s64 volume_size; 289 DWORD geo_sectors, geo_heads; 290 HANDLE vol_handle; 291 BOOL ntdll; 292 } win32_fd; 293 294 /** 295 * ntfs_w32error_to_errno - convert a win32 error code to the unix one 296 * @w32error: the win32 error code 297 * 298 * Limited to a relatively small but useful number of codes. 299 */ 300 static int ntfs_w32error_to_errno(unsigned int w32error) 301 { 302 ntfs_log_trace("Converting w32error 0x%x.\n",w32error); 303 switch (w32error) { 304 case ERROR_INVALID_FUNCTION: 305 return EBADRQC; 306 case ERROR_FILE_NOT_FOUND: 307 case ERROR_PATH_NOT_FOUND: 308 case ERROR_INVALID_NAME: 309 return ENOENT; 310 case ERROR_TOO_MANY_OPEN_FILES: 311 return EMFILE; 312 case ERROR_ACCESS_DENIED: 313 return EACCES; 314 case ERROR_INVALID_HANDLE: 315 return EBADF; 316 case ERROR_NOT_ENOUGH_MEMORY: 317 return ENOMEM; 318 case ERROR_OUTOFMEMORY: 319 return ENOSPC; 320 case ERROR_INVALID_DRIVE: 321 case ERROR_BAD_UNIT: 322 return ENODEV; 323 case ERROR_WRITE_PROTECT: 324 return EROFS; 325 case ERROR_NOT_READY: 326 case ERROR_SHARING_VIOLATION: 327 return EBUSY; 328 case ERROR_BAD_COMMAND: 329 return EINVAL; 330 case ERROR_SEEK: 331 case ERROR_NEGATIVE_SEEK: 332 return ESPIPE; 333 case ERROR_NOT_SUPPORTED: 334 return EOPNOTSUPP; 335 case ERROR_BAD_NETPATH: 336 return ENOSHARE; 337 default: 338 /* generic message */ 339 return ENOMSG; 340 } 341 } 342 343 static int ntfs_ntstatus_to_errno(NTSTATUS status) 344 { 345 ntfs_log_trace("Converting w32error 0x%x.\n",w32error); 346 switch (status) { 347 case STATUS_INVALID_HANDLE : 348 case STATUS_INVALID_PARAMETER : 349 case STATUS_OBJECT_NAME_INVALID : 350 case STATUS_INVALID_DEVICE_REQUEST : 351 return (EINVAL); 352 case STATUS_ACCESS_DENIED : 353 return (EACCES); 354 case STATUS_IO_DEVICE_ERROR : 355 case STATUS_END_OF_FILE : 356 return (EIO); 357 default: 358 /* generic message */ 359 return ENOMSG; 360 } 361 } 362 363 /** 364 * libntfs_SetFilePointerEx - emulation for SetFilePointerEx() 365 * 366 * We use this to emulate SetFilePointerEx() when it is not present. This can 367 * happen since SetFilePointerEx() only exists in Win2k+. 368 */ 369 static BOOL WINAPI libntfs_SetFilePointerEx(HANDLE hFile, 370 LARGE_INTEGER liDistanceToMove, 371 PLARGE_INTEGER lpNewFilePointer, DWORD dwMoveMethod) 372 { 373 liDistanceToMove.u.LowPart = SetFilePointer(hFile, 374 liDistanceToMove.u.LowPart, 375 &liDistanceToMove.u.HighPart, dwMoveMethod); 376 SetLastError(NO_ERROR); 377 if (liDistanceToMove.u.LowPart == INVALID_SET_FILE_POINTER && 378 GetLastError() != NO_ERROR) { 379 if (lpNewFilePointer) 380 lpNewFilePointer->QuadPart = -1; 381 return FALSE; 382 } 383 if (lpNewFilePointer) 384 lpNewFilePointer->QuadPart = liDistanceToMove.QuadPart; 385 return TRUE; 386 } 387 388 /** 389 * ntfs_device_win32_init_imports - initialize the function pointers 390 * 391 * The Find*Volume and SetFilePointerEx functions exist only on win2k+, as such 392 * we cannot just staticly import them. 393 * 394 * This function initializes the imports if the functions do exist and in the 395 * SetFilePointerEx case, we emulate the function ourselves if it is not 396 * present. 397 * 398 * Note: The values are cached, do be afraid to run it more than once. 399 */ 400 static void ntfs_device_win32_init_imports(void) 401 { 402 HMODULE kernel32 = GetModuleHandle("kernel32"); 403 if (!kernel32) { 404 errno = ntfs_w32error_to_errno(GetLastError()); 405 ntfs_log_trace("kernel32.dll could not be imported.\n"); 406 } 407 if (!fnSetFilePointerEx) { 408 if (kernel32) 409 fnSetFilePointerEx = (LPFN_SETFILEPOINTEREX) 410 GetProcAddress(kernel32, 411 "SetFilePointerEx"); 412 /* 413 * If we did not get kernel32.dll or it is not Win2k+, emulate 414 * SetFilePointerEx(). 415 */ 416 if (!fnSetFilePointerEx) { 417 ntfs_log_debug("SetFilePointerEx() not found in " 418 "kernel32.dll: Enabling emulation.\n"); 419 fnSetFilePointerEx = libntfs_SetFilePointerEx; 420 } 421 } 422 /* Cannot do lookups if we could not get kernel32.dll... */ 423 if (!kernel32) 424 return; 425 if (!fnFindFirstVolume) 426 fnFindFirstVolume = (LPFN_FINDFIRSTVOLUME) 427 GetProcAddress(kernel32, "FindFirstVolume" 428 FNPOSTFIX); 429 if (!fnFindNextVolume) 430 fnFindNextVolume = (LPFN_FINDNEXTVOLUME) 431 GetProcAddress(kernel32, "FindNextVolume" 432 FNPOSTFIX); 433 if (!fnFindVolumeClose) 434 fnFindVolumeClose = (LPFN_FINDVOLUMECLOSE) 435 GetProcAddress(kernel32, "FindVolumeClose"); 436 } 437 438 /** 439 * ntfs_device_unix_status_flags_to_win32 - convert unix->win32 open flags 440 * @flags: unix open status flags 441 * 442 * Supported flags are O_RDONLY, O_WRONLY and O_RDWR. 443 */ 444 static __inline__ int ntfs_device_unix_status_flags_to_win32(int flags) 445 { 446 int win_mode; 447 448 switch (flags & O_ACCMODE) { 449 case O_RDONLY: 450 win_mode = GENERIC_READ; 451 break; 452 case O_WRONLY: 453 win_mode = GENERIC_WRITE; 454 break; 455 case O_RDWR: 456 win_mode = GENERIC_READ | GENERIC_WRITE; 457 break; 458 default: 459 /* error */ 460 ntfs_log_trace("Unknown status flags.\n"); 461 win_mode = 0; 462 } 463 return win_mode; 464 } 465 466 467 /** 468 * ntfs_device_win32_simple_open_file - just open a file via win32 API 469 * @filename: name of the file to open 470 * @handle: pointer the a HANDLE in which to put the result 471 * @flags: unix open status flags 472 * @locking: will the function gain an exclusive lock on the file? 473 * 474 * Supported flags are O_RDONLY, O_WRONLY and O_RDWR. 475 * 476 * Return 0 if o.k. 477 * -1 if not, and errno set. In this case handle is trashed. 478 */ 479 static int ntfs_device_win32_simple_open_file(const char *filename, 480 HANDLE *handle, int flags, BOOL locking) 481 { 482 *handle = CreateFile(filename, 483 ntfs_device_unix_status_flags_to_win32(flags), 484 locking ? 0 : (FILE_SHARE_WRITE | FILE_SHARE_READ), 485 NULL, (flags & O_CREAT ? OPEN_ALWAYS : OPEN_EXISTING), 486 0, NULL); 487 if (*handle == INVALID_HANDLE_VALUE) { 488 errno = ntfs_w32error_to_errno(GetLastError()); 489 ntfs_log_trace("CreateFile(%s) failed.\n", filename); 490 return -1; 491 } 492 return 0; 493 } 494 495 /** 496 * ntfs_device_win32_lock - lock the volume 497 * @handle: a win32 HANDLE for a volume to lock 498 * 499 * Locking a volume means no one can access its contents. 500 * Exiting the process automatically unlocks the volume, except in old NT4s. 501 * 502 * Return 0 if o.k. 503 * -1 if not, and errno set. 504 */ 505 static int ntfs_device_win32_lock(HANDLE handle) 506 { 507 DWORD i; 508 509 if (!DeviceIoControl(handle, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &i, 510 NULL)) { 511 errno = ntfs_w32error_to_errno(GetLastError()); 512 ntfs_log_trace("Couldn't lock volume.\n"); 513 return -1; 514 } 515 ntfs_log_debug("Volume locked.\n"); 516 return 0; 517 } 518 519 /** 520 * ntfs_device_win32_unlock - unlock the volume 521 * @handle: the win32 HANDLE which the volume was locked with 522 * 523 * Return 0 if o.k. 524 * -1 if not, and errno set. 525 */ 526 static int ntfs_device_win32_unlock(HANDLE handle) 527 { 528 DWORD i; 529 530 if (!DeviceIoControl(handle, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0, &i, 531 NULL)) { 532 errno = ntfs_w32error_to_errno(GetLastError()); 533 ntfs_log_trace("Couldn't unlock volume.\n"); 534 return -1; 535 } 536 ntfs_log_debug("Volume unlocked.\n"); 537 return 0; 538 } 539 540 static int ntfs_device_win32_setlock(HANDLE handle, ULONG code) 541 { 542 IO_STATUS_BLOCK io_status; 543 NTSTATUS res; 544 545 io_status.Status = STATUS_SUCCESS; 546 io_status.Information = 0; 547 res = NtFsControlFile(handle,(HANDLE)NULL, 548 (PIO_APC_ROUTINE)NULL,(void*)NULL, 549 &io_status, code, 550 (char*)NULL,0,(char*)NULL,0); 551 if (res != STATUS_SUCCESS) 552 errno = ntfs_ntstatus_to_errno(res); 553 return (res == STATUS_SUCCESS ? 0 : -1); 554 } 555 556 /** 557 * ntfs_device_win32_dismount - dismount a volume 558 * @handle: a win32 HANDLE for a volume to dismount 559 * 560 * Dismounting means the system will refresh the volume in the first change it 561 * gets. Usefull after altering the file structures. 562 * The volume must be locked by the current process while dismounting. 563 * A side effect is that the volume is also unlocked, but you must not rely om 564 * this. 565 * 566 * Return 0 if o.k. 567 * -1 if not, and errno set. 568 */ 569 static int ntfs_device_win32_dismount(HANDLE handle) 570 { 571 DWORD i; 572 573 if (!DeviceIoControl(handle, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0, 574 &i, NULL)) { 575 errno = ntfs_w32error_to_errno(GetLastError()); 576 ntfs_log_trace("Couldn't dismount volume.\n"); 577 return -1; 578 } 579 ntfs_log_debug("Volume dismounted.\n"); 580 return 0; 581 } 582 583 /** 584 * ntfs_device_win32_getsize - get file size via win32 API 585 * @handle: pointer the file HANDLE obtained via open 586 * 587 * Only works on ordinary files. 588 * 589 * Return The file size if o.k. 590 * -1 if not, and errno set. 591 */ 592 static s64 ntfs_device_win32_getsize(HANDLE handle) 593 { 594 LONG loword, hiword; 595 596 SetLastError(NO_ERROR); 597 hiword = 0; 598 loword = SetFilePointer(handle, 0, &hiword, 2); 599 if ((loword == INVALID_SET_FILE_POINTER) 600 && (GetLastError() != NO_ERROR)) { 601 errno = ntfs_w32error_to_errno(GetLastError()); 602 ntfs_log_trace("Couldn't get file size.\n"); 603 return -1; 604 } 605 return ((s64)hiword << 32) + (ULONG)loword; 606 } 607 608 /** 609 * ntfs_device_win32_getdisklength - get disk size via win32 API 610 * @handle: pointer the file HANDLE obtained via open 611 * @argp: pointer to result buffer 612 * 613 * Only works on PhysicalDriveX type handles. 614 * 615 * Return The disk size if o.k. 616 * -1 if not, and errno set. 617 */ 618 static s64 ntfs_device_win32_getdisklength(HANDLE handle) 619 { 620 GET_LENGTH_INFORMATION buf; 621 DWORD i; 622 623 if (!DeviceIoControl(handle, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &buf, 624 sizeof(buf), &i, NULL)) { 625 errno = ntfs_w32error_to_errno(GetLastError()); 626 ntfs_log_trace("Couldn't get disk length.\n"); 627 return -1; 628 } 629 ntfs_log_debug("Disk length: %lld.\n", buf.Length.QuadPart); 630 return buf.Length.QuadPart; 631 } 632 633 /** 634 * ntfs_device_win32_getntfssize - get NTFS volume size via win32 API 635 * @handle: pointer the file HANDLE obtained via open 636 * @argp: pointer to result buffer 637 * 638 * Only works on NTFS volume handles. 639 * An annoying bug in windows is that an NTFS volume does not occupy the entire 640 * partition, namely not the last sector (which holds the backup boot sector, 641 * and normally not interesting). 642 * Use this function to get the length of the accessible space through a given 643 * volume handle. 644 * 645 * Return The volume size if o.k. 646 * -1 if not, and errno set. 647 */ 648 static s64 ntfs_device_win32_getntfssize(HANDLE handle) 649 { 650 s64 rvl; 651 #ifdef FSCTL_GET_NTFS_VOLUME_DATA 652 DWORD i; 653 NTFS_VOLUME_DATA_BUFFER buf; 654 655 if (!DeviceIoControl(handle, FSCTL_GET_NTFS_VOLUME_DATA, NULL, 0, &buf, 656 sizeof(buf), &i, NULL)) { 657 errno = ntfs_w32error_to_errno(GetLastError()); 658 ntfs_log_trace("Couldn't get NTFS volume length.\n"); 659 return -1; 660 } 661 rvl = buf.NumberSectors.QuadPart * buf.BytesPerSector; 662 ntfs_log_debug("NTFS volume length: 0x%llx.\n", (long long)rvl); 663 #else 664 errno = EINVAL; 665 rvl = -1; 666 #endif 667 return rvl; 668 } 669 670 /** 671 * ntfs_device_win32_getgeo - get CHS information of a drive 672 * @handle: an open handle to the PhysicalDevice 673 * @fd: a win_fd structure that will be filled 674 * 675 * Return 0 if o.k. 676 * -1 if not, and errno set. 677 * 678 * In Windows NT+: fills size, sectors, and cylinders and sets heads to -1. 679 * In Windows XP+: fills size, sectors, cylinders, and heads. 680 * 681 * Note: In pre XP, this requires write permission, even though nothing is 682 * actually written. 683 * 684 * If fails, sets sectors, cylinders, heads, and size to -1. 685 */ 686 static int ntfs_device_win32_getgeo(HANDLE handle, win32_fd *fd) 687 { 688 DWORD i; 689 BOOL rvl; 690 BYTE b[sizeof(DISK_GEOMETRY) + sizeof(DISK_PARTITION_INFO) + 691 sizeof(DISK_DETECTION_INFO) + 512]; 692 693 rvl = DeviceIoControl(handle, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, 694 0, &b, sizeof(b), &i, NULL); 695 if (rvl) { 696 ntfs_log_debug("GET_DRIVE_GEOMETRY_EX detected.\n"); 697 DISK_DETECTION_INFO *ddi = (PDISK_DETECTION_INFO) 698 (((PBYTE)(&((PDISK_GEOMETRY_EX)b)->Data)) + 699 (((PDISK_PARTITION_INFO) 700 (&((PDISK_GEOMETRY_EX)b)->Data))-> 701 SizeOfPartitionInfo)); 702 fd->geo_cylinders = ((DISK_GEOMETRY*)&b)->Cylinders.QuadPart; 703 fd->geo_sectors = ((DISK_GEOMETRY*)&b)->SectorsPerTrack; 704 fd->geo_size = ((DISK_GEOMETRY_EX*)&b)->DiskSize.QuadPart; 705 fd->geo_sector_size = NTFS_BLOCK_SIZE; 706 switch (ddi->DetectionType) { 707 case DetectInt13: 708 fd->geo_cylinders = ddi->Int13.MaxCylinders; 709 fd->geo_sectors = ddi->Int13.SectorsPerTrack; 710 fd->geo_heads = ddi->Int13.MaxHeads; 711 return 0; 712 case DetectExInt13: 713 fd->geo_cylinders = ddi->ExInt13.ExCylinders; 714 fd->geo_sectors = ddi->ExInt13.ExSectorsPerTrack; 715 fd->geo_heads = ddi->ExInt13.ExHeads; 716 return 0; 717 case DetectNone: 718 default: 719 break; 720 } 721 } else 722 fd->geo_heads = -1; 723 rvl = DeviceIoControl(handle, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, 724 &b, sizeof(b), &i, NULL); 725 if (rvl) { 726 ntfs_log_debug("GET_DRIVE_GEOMETRY detected.\n"); 727 fd->geo_cylinders = ((DISK_GEOMETRY*)&b)->Cylinders.QuadPart; 728 fd->geo_sectors = ((DISK_GEOMETRY*)&b)->SectorsPerTrack; 729 fd->geo_size = fd->geo_cylinders * fd->geo_sectors * 730 ((DISK_GEOMETRY*)&b)->TracksPerCylinder * 731 ((DISK_GEOMETRY*)&b)->BytesPerSector; 732 fd->geo_sector_size = ((DISK_GEOMETRY*)&b)->BytesPerSector; 733 return 0; 734 } 735 errno = ntfs_w32error_to_errno(GetLastError()); 736 ntfs_log_trace("Couldn't retrieve disk geometry.\n"); 737 fd->geo_cylinders = -1; 738 fd->geo_sectors = -1; 739 fd->geo_size = -1; 740 fd->geo_sector_size = NTFS_BLOCK_SIZE; 741 return -1; 742 } 743 744 static int ntfs_device_win32_getntgeo(HANDLE handle, win32_fd *fd) 745 { 746 DISK_GEOMETRY geo; 747 NTSTATUS st; 748 IO_STATUS_BLOCK status; 749 u64 bytes; 750 int res; 751 752 res = -1; 753 fd->geo_cylinders = 0; 754 fd->geo_sectors = 0; 755 fd->geo_size = 1073741824; 756 fd->geo_sectors = fd->geo_size >> 9; 757 fd->geo_sector_size = NTFS_BLOCK_SIZE; 758 759 st = NtDeviceIoControlFile(handle, (HANDLE)NULL, 760 (PIO_APC_ROUTINE)NULL, (void*)NULL, 761 &status, IOCTL_DISK_GET_DRIVE_GEOMETRY, (void*)NULL, 0, 762 (void*)&geo, sizeof(geo)); 763 if (st == STATUS_SUCCESS) { 764 /* over-estimate the (rounded) number of cylinders */ 765 fd->geo_cylinders = geo.Cylinders.QuadPart + 1; 766 fd->geo_sectors = fd->geo_cylinders 767 *geo.TracksPerCylinder*geo.SectorsPerTrack; 768 fd->geo_size = fd->geo_sectors*geo.BytesPerSector; 769 fd->geo_sector_size = geo.BytesPerSector; 770 res = 0; 771 /* try to get the exact sector count */ 772 st = NtDeviceIoControlFile(handle, (HANDLE)NULL, 773 (PIO_APC_ROUTINE)NULL, (void*)NULL, 774 &status, IOCTL_GET_DISK_LENGTH_INFO, 775 (void*)NULL, 0, 776 (void*)&bytes, sizeof(bytes)); 777 if (st == STATUS_SUCCESS) { 778 fd->geo_size = bytes; 779 fd->geo_sectors = bytes/geo.BytesPerSector; 780 } 781 } 782 return (res); 783 } 784 785 /** 786 * ntfs_device_win32_open_file - open a file via win32 API 787 * @filename: name of the file to open 788 * @fd: pointer to win32 file device in which to put the result 789 * @flags: unix open status flags 790 * 791 * Return 0 if o.k. 792 * -1 if not, and errno set. 793 */ 794 static __inline__ int ntfs_device_win32_open_file(char *filename, win32_fd *fd, 795 int flags) 796 { 797 HANDLE handle; 798 int mode; 799 800 if (ntfs_device_win32_simple_open_file(filename, &handle, flags, 801 FALSE)) { 802 /* open error */ 803 return -1; 804 } 805 mode = flags & O_ACCMODE; 806 if ((mode == O_RDWR) || (mode == O_WRONLY)) { 807 DWORD bytes; 808 809 /* try making sparse (but ignore errors) */ 810 DeviceIoControl(handle, FSCTL_SET_SPARSE, 811 (void*)NULL, 0, (void*)NULL, 0, 812 &bytes, (LPOVERLAPPED)NULL); 813 } 814 /* fill fd */ 815 fd->handle = handle; 816 fd->part_start = 0; 817 fd->part_length = ntfs_device_win32_getsize(handle); 818 fd->pos = 0; 819 fd->part_hidden_sectors = -1; 820 fd->geo_size = -1; /* used as a marker that this is a file */ 821 fd->vol_handle = INVALID_HANDLE_VALUE; 822 fd->geo_sector_size = 512; /* will be adjusted from the boot sector */ 823 fd->ntdll = FALSE; 824 return 0; 825 } 826 827 /** 828 * ntfs_device_win32_open_drive - open a drive via win32 API 829 * @drive_id: drive to open 830 * @fd: pointer to win32 file device in which to put the result 831 * @flags: unix open status flags 832 * 833 * return 0 if o.k. 834 * -1 if not, and errno set. 835 */ 836 static __inline__ int ntfs_device_win32_open_drive(int drive_id, win32_fd *fd, 837 int flags) 838 { 839 HANDLE handle; 840 int err; 841 char filename[MAX_PATH]; 842 843 sprintf(filename, "\\\\.\\PhysicalDrive%d", drive_id); 844 if ((err = ntfs_device_win32_simple_open_file(filename, &handle, flags, 845 TRUE))) { 846 /* open error */ 847 return err; 848 } 849 /* store the drive geometry */ 850 ntfs_device_win32_getgeo(handle, fd); 851 /* Just to be sure */ 852 if (fd->geo_size == -1) 853 fd->geo_size = ntfs_device_win32_getdisklength(handle); 854 /* fill fd */ 855 fd->ntdll = FALSE; 856 fd->handle = handle; 857 fd->part_start = 0; 858 fd->part_length = fd->geo_size; 859 fd->pos = 0; 860 fd->part_hidden_sectors = -1; 861 fd->vol_handle = INVALID_HANDLE_VALUE; 862 return 0; 863 } 864 865 /** 866 * ntfs_device_win32_open_lowlevel - open a drive via low level win32 API 867 * @drive_id: drive to open 868 * @fd: pointer to win32 file device in which to put the result 869 * @flags: unix open status flags 870 * 871 * return 0 if o.k. 872 * -1 if not, and errno set. 873 */ 874 static __inline__ int ntfs_device_win32_open_lowlevel(int drive_id, 875 win32_fd *fd, int flags) 876 { 877 HANDLE handle; 878 NTSTATUS st; 879 ACCESS_MASK access; 880 ULONG share; 881 OBJECT_ATTRIBUTES attr; 882 IO_STATUS_BLOCK io_status; 883 UNICODE_STRING unicode_name; 884 ntfschar unicode_buffer[7]; 885 int mode; 886 static const ntfschar unicode_init[] = { 887 const_cpu_to_le16('\\'), const_cpu_to_le16('?'), 888 const_cpu_to_le16('?'), const_cpu_to_le16('\\'), 889 const_cpu_to_le16(' '), const_cpu_to_le16(':'), 890 const_cpu_to_le16(0) 891 }; 892 893 memcpy(unicode_buffer, unicode_init, sizeof(unicode_buffer)); 894 unicode_buffer[4] = cpu_to_le16(drive_id + 'A'); 895 unicode_name.Buffer = unicode_buffer; 896 unicode_name.Length = 6*sizeof(ntfschar); 897 unicode_name.MaximumLength = 6*sizeof(ntfschar); 898 899 attr.Length = sizeof(OBJECT_ATTRIBUTES); 900 attr.RootDirectory = (HANDLE*)NULL; 901 attr.ObjectName = &unicode_name; 902 attr.Attributes = OBJ_CASE_INSENSITIVE; 903 attr.SecurityDescriptor = (void*)NULL; 904 attr.SecurityQualityOfService = (void*)NULL; 905 906 io_status.Status = 0; 907 io_status.Information = 0; 908 mode = flags & O_ACCMODE; 909 share = (mode == O_RDWR ? 910 0 : FILE_SHARE_READ | FILE_SHARE_WRITE); 911 access = (mode == O_RDWR ? 912 FILE_READ_DATA | FILE_WRITE_DATA | SYNCHRONIZE 913 : FILE_READ_DATA | SYNCHRONIZE); 914 915 st = NtOpenFile(&handle, access, 916 &attr, &io_status, 917 share, 918 FILE_SYNCHRONOUS_IO_ALERT); 919 if (st != STATUS_SUCCESS) { 920 errno = ntfs_ntstatus_to_errno(st); 921 return (-1); 922 } 923 ntfs_device_win32_setlock(handle,FSCTL_LOCK_VOLUME); 924 /* store the drive geometry */ 925 ntfs_device_win32_getntgeo(handle, fd); 926 fd->ntdll = TRUE; 927 /* allow accessing the full partition */ 928 st = NtFsControlFile(handle, (HANDLE)NULL, 929 (PIO_APC_ROUTINE)NULL, 930 (PVOID)NULL, &io_status, 931 FSCTL_ALLOW_EXTENDED_DASD_IO, 932 NULL, 0, NULL, 0); 933 if (st != STATUS_SUCCESS) { 934 errno = ntfs_ntstatus_to_errno(st); 935 NtClose(handle); 936 return (-1); 937 } 938 /* fill fd */ 939 fd->handle = handle; 940 fd->part_start = 0; 941 fd->part_length = fd->geo_size; 942 fd->pos = 0; 943 fd->part_hidden_sectors = -1; 944 fd->vol_handle = INVALID_HANDLE_VALUE; 945 return 0; 946 } 947 948 /** 949 * ntfs_device_win32_open_volume_for_partition - find and open a volume 950 * 951 * Windows NT/2k/XP handles volumes instead of partitions. 952 * This function gets the partition details and return an open volume handle. 953 * That volume is the one whose only physical location on disk is the described 954 * partition. 955 * 956 * The function required Windows 2k/XP, otherwise it fails (gracefully). 957 * 958 * Return success: a valid open volume handle. 959 * fail : INVALID_HANDLE_VALUE 960 */ 961 static HANDLE ntfs_device_win32_open_volume_for_partition(unsigned int drive_id, 962 s64 part_offset, s64 part_length, int flags) 963 { 964 HANDLE vol_find_handle; 965 TCHAR vol_name[MAX_PATH]; 966 967 /* Make sure all the required imports exist. */ 968 if (!fnFindFirstVolume || !fnFindNextVolume || !fnFindVolumeClose) { 969 ntfs_log_trace("Required dll imports not found.\n"); 970 return INVALID_HANDLE_VALUE; 971 } 972 /* Start iterating through volumes. */ 973 ntfs_log_trace("Entering with drive_id=%d, part_offset=%lld, " 974 "path_length=%lld, flags=%d.\n", drive_id, 975 (unsigned long long)part_offset, 976 (unsigned long long)part_length, flags); 977 vol_find_handle = fnFindFirstVolume(vol_name, MAX_PATH); 978 /* If a valid handle could not be aquired, reply with "don't know". */ 979 if (vol_find_handle == INVALID_HANDLE_VALUE) { 980 ntfs_log_trace("FindFirstVolume failed.\n"); 981 return INVALID_HANDLE_VALUE; 982 } 983 do { 984 int vol_name_length; 985 HANDLE handle; 986 987 /* remove trailing '/' from vol_name */ 988 #ifdef UNICODE 989 vol_name_length = wcslen(vol_name); 990 #else 991 vol_name_length = strlen(vol_name); 992 #endif 993 if (vol_name_length>0) 994 vol_name[vol_name_length-1]=0; 995 996 ntfs_log_debug("Processing %s.\n", vol_name); 997 /* open the file */ 998 handle = CreateFile(vol_name, 999 ntfs_device_unix_status_flags_to_win32(flags), 1000 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, 1001 OPEN_EXISTING, 0, NULL); 1002 if (handle != INVALID_HANDLE_VALUE) { 1003 DWORD bytesReturned; 1004 #define EXTENTS_SIZE sizeof(VOLUME_DISK_EXTENTS) + 9 * sizeof(DISK_EXTENT) 1005 char extents[EXTENTS_SIZE]; 1006 1007 /* Check physical locations. */ 1008 if (DeviceIoControl(handle, 1009 IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, 1010 NULL, 0, extents, EXTENTS_SIZE, 1011 &bytesReturned, NULL)) { 1012 if (((VOLUME_DISK_EXTENTS *)extents)-> 1013 NumberOfDiskExtents == 1) { 1014 DISK_EXTENT *extent = &(( 1015 VOLUME_DISK_EXTENTS *) 1016 extents)->Extents[0]; 1017 if ((extent->DiskNumber==drive_id) && 1018 (extent->StartingOffset. 1019 QuadPart==part_offset) 1020 && (extent-> 1021 ExtentLength.QuadPart 1022 == part_length)) { 1023 /* 1024 * Eureka! (Archimedes, 287 BC, 1025 * "I have found it!") 1026 */ 1027 fnFindVolumeClose( 1028 vol_find_handle); 1029 return handle; 1030 } 1031 } 1032 } 1033 } else 1034 ntfs_log_trace("getExtents() Failed.\n"); 1035 } while (fnFindNextVolume(vol_find_handle, vol_name, MAX_PATH)); 1036 /* End of iteration through volumes. */ 1037 ntfs_log_trace("Closing, volume was not found.\n"); 1038 fnFindVolumeClose(vol_find_handle); 1039 return INVALID_HANDLE_VALUE; 1040 } 1041 1042 /** 1043 * ntfs_device_win32_find_partition - locates partition details by id. 1044 * @handle: HANDLE to the PhysicalDrive 1045 * @partition_id: the partition number to locate 1046 * @part_offset: pointer to where to put the offset to the partition 1047 * @part_length: pointer to where to put the length of the partition 1048 * @hidden_sectors: pointer to where to put the hidden sectors 1049 * 1050 * This function requires an open PhysicalDrive handle and a partition_id. 1051 * If a partition with the required id is found on the supplied device, 1052 * the partition attributes are returned back. 1053 * 1054 * Returns: TRUE if found, and sets the output parameters. 1055 * FALSE if not and errno is set to the error code. 1056 */ 1057 static BOOL ntfs_device_win32_find_partition(HANDLE handle, DWORD partition_id, 1058 s64 *part_offset, s64 *part_length, int *hidden_sectors) 1059 { 1060 DRIVE_LAYOUT_INFORMATION *drive_layout; 1061 unsigned int err, buf_size, part_count; 1062 DWORD i; 1063 1064 /* 1065 * There is no way to know the required buffer, so if the ioctl fails, 1066 * try doubling the buffer size each time until the ioctl succeeds. 1067 */ 1068 part_count = 8; 1069 do { 1070 buf_size = sizeof(DRIVE_LAYOUT_INFORMATION) + 1071 part_count * sizeof(PARTITION_INFORMATION); 1072 drive_layout = (DRIVE_LAYOUT_INFORMATION*)ntfs_malloc(buf_size); 1073 if (!drive_layout) { 1074 errno = ENOMEM; 1075 return FALSE; 1076 } 1077 if (DeviceIoControl(handle, IOCTL_DISK_GET_DRIVE_LAYOUT, NULL, 1078 0, (BYTE*)drive_layout, buf_size, &i, NULL)) 1079 break; 1080 err = GetLastError(); 1081 free(drive_layout); 1082 if (err != ERROR_INSUFFICIENT_BUFFER) { 1083 ntfs_log_trace("GetDriveLayout failed.\n"); 1084 errno = ntfs_w32error_to_errno(err); 1085 return FALSE; 1086 } 1087 ntfs_log_debug("More than %u partitions.\n", part_count); 1088 part_count <<= 1; 1089 if (part_count > 512) { 1090 ntfs_log_trace("GetDriveLayout failed: More than 512 " 1091 "partitions?\n"); 1092 errno = ENOBUFS; 1093 return FALSE; 1094 } 1095 } while (1); 1096 for (i = 0; i < drive_layout->PartitionCount; i++) { 1097 if (drive_layout->PartitionEntry[i].PartitionNumber == 1098 partition_id) { 1099 *part_offset = drive_layout->PartitionEntry[i]. 1100 StartingOffset.QuadPart; 1101 *part_length = drive_layout->PartitionEntry[i]. 1102 PartitionLength.QuadPart; 1103 *hidden_sectors = drive_layout->PartitionEntry[i]. 1104 HiddenSectors; 1105 free(drive_layout); 1106 return TRUE; 1107 } 1108 } 1109 free(drive_layout); 1110 errno = ENOENT; 1111 return FALSE; 1112 } 1113 1114 /** 1115 * ntfs_device_win32_open_partition - open a partition via win32 API 1116 * @drive_id: drive to open 1117 * @partition_id: partition to open 1118 * @fd: win32 file device to return 1119 * @flags: unix open status flags 1120 * 1121 * Return 0 if o.k. 1122 * -1 if not, and errno set. 1123 * 1124 * When fails, fd contents may have not been preserved. 1125 */ 1126 static int ntfs_device_win32_open_partition(int drive_id, 1127 unsigned int partition_id, win32_fd *fd, int flags) 1128 { 1129 s64 part_start, part_length; 1130 HANDLE handle; 1131 int err, hidden_sectors; 1132 char drive_name[MAX_PATH]; 1133 1134 sprintf(drive_name, "\\\\.\\PhysicalDrive%d", drive_id); 1135 /* Open the entire device without locking, ask questions later */ 1136 if ((err = ntfs_device_win32_simple_open_file(drive_name, &handle, 1137 flags, FALSE))) { 1138 /* error */ 1139 return err; 1140 } 1141 if (ntfs_device_win32_find_partition(handle, partition_id, &part_start, 1142 &part_length, &hidden_sectors)) { 1143 s64 tmp; 1144 HANDLE vol_handle = ntfs_device_win32_open_volume_for_partition( 1145 drive_id, part_start, part_length, flags); 1146 /* Store the drive geometry. */ 1147 ntfs_device_win32_getgeo(handle, fd); 1148 fd->handle = handle; 1149 fd->pos = 0; 1150 fd->part_start = part_start; 1151 fd->part_length = part_length; 1152 fd->part_hidden_sectors = hidden_sectors; 1153 fd->geo_sector_size = 512; 1154 fd->ntdll = FALSE; 1155 tmp = ntfs_device_win32_getntfssize(vol_handle); 1156 if (tmp > 0) 1157 fd->geo_size = tmp; 1158 else 1159 fd->geo_size = fd->part_length; 1160 if (vol_handle != INVALID_HANDLE_VALUE) { 1161 if (((flags & O_RDWR) == O_RDWR) && 1162 ntfs_device_win32_lock(vol_handle)) { 1163 CloseHandle(vol_handle); 1164 CloseHandle(handle); 1165 return -1; 1166 } 1167 fd->vol_handle = vol_handle; 1168 } else { 1169 if ((flags & O_RDWR) == O_RDWR) { 1170 /* Access if read-write, no volume found. */ 1171 ntfs_log_trace("Partitions containing Spanned/" 1172 "Mirrored volumes are not " 1173 "supported in R/W status " 1174 "yet.\n"); 1175 CloseHandle(handle); 1176 errno = EOPNOTSUPP; 1177 return -1; 1178 } 1179 fd->vol_handle = INVALID_HANDLE_VALUE; 1180 } 1181 return 0; 1182 } else { 1183 ntfs_log_debug("Partition %u not found on drive %d.\n", 1184 partition_id, drive_id); 1185 CloseHandle(handle); 1186 errno = ENODEV; 1187 return -1; 1188 } 1189 } 1190 1191 /** 1192 * ntfs_device_win32_open - open a device 1193 * @dev: a pointer to the NTFS_DEVICE to open 1194 * @flags: unix open status flags 1195 * 1196 * @dev->d_name must hold the device name, the rest is ignored. 1197 * Supported flags are O_RDONLY, O_WRONLY and O_RDWR. 1198 * 1199 * If name is in format "(hd[0-9],[0-9])" then open a partition. 1200 * If name is in format "(hd[0-9])" then open a volume. 1201 * Otherwise open a file. 1202 */ 1203 static int ntfs_device_win32_open(struct ntfs_device *dev, int flags) 1204 { 1205 int drive_id = 0, numparams; 1206 unsigned int part = 0; 1207 char drive_char; 1208 win32_fd fd; 1209 int err; 1210 1211 if (NDevOpen(dev)) { 1212 errno = EBUSY; 1213 return -1; 1214 } 1215 ntfs_device_win32_init_imports(); 1216 numparams = sscanf(dev->d_name, "/dev/hd%c%u", &drive_char, &part); 1217 if (!numparams 1218 && (dev->d_name[1] == ':') 1219 && (dev->d_name[2] == '\0')) { 1220 drive_char = dev->d_name[0]; 1221 numparams = 3; 1222 drive_id = toupper(drive_char) - 'A'; 1223 } 1224 switch (numparams) { 1225 case 0: 1226 ntfs_log_debug("win32_open(%s) -> file.\n", dev->d_name); 1227 err = ntfs_device_win32_open_file(dev->d_name, &fd, flags); 1228 break; 1229 case 1: 1230 ntfs_log_debug("win32_open(%s) -> drive %d.\n", dev->d_name, 1231 drive_id); 1232 err = ntfs_device_win32_open_drive(drive_id, &fd, flags); 1233 break; 1234 case 2: 1235 ntfs_log_debug("win32_open(%s) -> drive %d, part %u.\n", 1236 dev->d_name, drive_id, part); 1237 err = ntfs_device_win32_open_partition(drive_id, part, &fd, 1238 flags); 1239 break; 1240 case 3: 1241 ntfs_log_debug("win32_open(%s) -> drive %c:\n", 1242 dev->d_name, drive_char); 1243 err = ntfs_device_win32_open_lowlevel(drive_id, &fd, 1244 flags); 1245 break; 1246 default: 1247 ntfs_log_debug("win32_open(%s) -> unknwon file format.\n", 1248 dev->d_name); 1249 err = -1; 1250 } 1251 if (err) 1252 return err; 1253 ntfs_log_debug("win32_open(%s) -> %p, offset 0x%llx.\n", dev->d_name, 1254 dev, fd.part_start); 1255 /* Setup our read-only flag. */ 1256 if ((flags & O_RDWR) != O_RDWR) 1257 NDevSetReadOnly(dev); 1258 dev->d_private = (win32_fd*)ntfs_malloc(sizeof(win32_fd)); 1259 memcpy(dev->d_private, &fd, sizeof(win32_fd)); 1260 NDevSetOpen(dev); 1261 NDevClearDirty(dev); 1262 return 0; 1263 } 1264 1265 /** 1266 * ntfs_device_win32_seek - change current logical file position 1267 * @dev: ntfs device obtained via ->open 1268 * @offset: required offset from the whence anchor 1269 * @whence: whence anchor specifying what @offset is relative to 1270 * 1271 * Return the new position on the volume on success and -1 on error with errno 1272 * set to the error code. 1273 * 1274 * @whence may be one of the following: 1275 * SEEK_SET - Offset is relative to file start. 1276 * SEEK_CUR - Offset is relative to current position. 1277 * SEEK_END - Offset is relative to end of file. 1278 */ 1279 static s64 ntfs_device_win32_seek(struct ntfs_device *dev, s64 offset, 1280 int whence) 1281 { 1282 s64 abs_ofs; 1283 win32_fd *fd = (win32_fd *)dev->d_private; 1284 1285 ntfs_log_trace("seek offset = 0x%llx, whence = %d.\n", offset, whence); 1286 switch (whence) { 1287 case SEEK_SET: 1288 abs_ofs = offset; 1289 break; 1290 case SEEK_CUR: 1291 abs_ofs = fd->pos + offset; 1292 break; 1293 case SEEK_END: 1294 /* End of partition != end of disk. */ 1295 if (fd->part_length == -1) { 1296 ntfs_log_trace("Position relative to end of disk not " 1297 "implemented.\n"); 1298 errno = EOPNOTSUPP; 1299 return -1; 1300 } 1301 abs_ofs = fd->part_length + offset; 1302 break; 1303 default: 1304 ntfs_log_trace("Wrong mode %d.\n", whence); 1305 errno = EINVAL; 1306 return -1; 1307 } 1308 if ((abs_ofs < 0) 1309 || (fd->ntdll && (abs_ofs > fd->part_length))) { 1310 ntfs_log_trace("Seeking outsize seekable area.\n"); 1311 errno = EINVAL; 1312 return -1; 1313 } 1314 fd->pos = abs_ofs; 1315 return abs_ofs; 1316 } 1317 1318 /** 1319 * ntfs_device_win32_pio - positioned low level i/o 1320 * @fd: win32 device descriptor obtained via ->open 1321 * @pos: at which position to do i/o from/to 1322 * @count: how many bytes should be transfered 1323 * @b: source/destination buffer 1324 * @write: TRUE if write transfer and FALSE if read transfer 1325 * 1326 * On success returns the number of bytes transfered (can be < @count) and on 1327 * error returns -1 and errno set. Transfer starts from position @pos on @fd. 1328 * 1329 * Notes: 1330 * - @pos, @buf, and @count must be aligned to geo_sector_size 1331 * - When dealing with volumes, a single call must not span both volume 1332 * and disk extents. 1333 * - Does not use/set @fd->pos. 1334 */ 1335 static s64 ntfs_device_win32_pio(win32_fd *fd, const s64 pos, 1336 const s64 count, void *rbuf, const void *wbuf) 1337 { 1338 LARGE_INTEGER li; 1339 HANDLE handle; 1340 DWORD bt; 1341 BOOL res; 1342 s64 bytes; 1343 1344 ntfs_log_trace("pos = 0x%llx, count = 0x%llx, direction = %s.\n", 1345 (long long)pos, (long long)count, write ? "write" : 1346 "read"); 1347 li.QuadPart = pos; 1348 if (fd->vol_handle != INVALID_HANDLE_VALUE && pos < fd->geo_size) { 1349 ntfs_log_debug("Transfering via vol_handle.\n"); 1350 handle = fd->vol_handle; 1351 } else { 1352 ntfs_log_debug("Transfering via handle.\n"); 1353 handle = fd->handle; 1354 li.QuadPart += fd->part_start; 1355 } 1356 1357 if (fd->ntdll) { 1358 IO_STATUS_BLOCK io_status; 1359 NTSTATUS res; 1360 LARGE_INTEGER offset; 1361 1362 io_status.Status = STATUS_SUCCESS; 1363 io_status.Information = 0; 1364 offset.QuadPart = pos; 1365 if (wbuf) { 1366 res = NtWriteFile(fd->handle,(HANDLE)NULL, 1367 (PIO_APC_ROUTINE)NULL,(void*)NULL, 1368 &io_status, wbuf, count, 1369 &offset, (PULONG)NULL); 1370 } else { 1371 res = NtReadFile(fd->handle,(HANDLE)NULL, 1372 (PIO_APC_ROUTINE)NULL,(void*)NULL, 1373 &io_status, rbuf, count, 1374 &offset, (PULONG)NULL); 1375 } 1376 if (res == STATUS_SUCCESS) { 1377 bytes = io_status.Information; 1378 } else { 1379 bytes = -1; 1380 errno = ntfs_ntstatus_to_errno(res); 1381 } 1382 } else { 1383 if (!fnSetFilePointerEx(handle, li, NULL, FILE_BEGIN)) { 1384 errno = ntfs_w32error_to_errno(GetLastError()); 1385 ntfs_log_trace("SetFilePointer failed.\n"); 1386 return -1; 1387 } 1388 if (wbuf) 1389 res = WriteFile(handle, wbuf, count, &bt, NULL); 1390 else 1391 res = ReadFile(handle, rbuf, count, &bt, NULL); 1392 bytes = bt; 1393 if (!res) { 1394 errno = ntfs_w32error_to_errno(GetLastError()); 1395 ntfs_log_trace("%sFile() failed.\n", write ? 1396 "Write" : "Read"); 1397 return -1; 1398 } 1399 if (rbuf && !pos) { 1400 /* get the sector size from the boot sector */ 1401 char *boot = (char*)rbuf; 1402 fd->geo_sector_size = (boot[11] & 255) 1403 + ((boot[12] & 255) << 8); 1404 } 1405 } 1406 return bytes; 1407 } 1408 1409 /** 1410 * ntfs_device_win32_pread_simple - positioned simple read 1411 * @fd: win32 device descriptor obtained via ->open 1412 * @pos: at which position to read from 1413 * @count: how many bytes should be read 1414 * @b: a pointer to where to put the contents 1415 * 1416 * On success returns the number of bytes read (can be < @count) and on error 1417 * returns -1 and errno set. Read starts from position @pos. 1418 * 1419 * Notes: 1420 * - @pos, @buf, and @count must be aligned to geo_sector_size. 1421 * - When dealing with volumes, a single call must not span both volume 1422 * and disk extents. 1423 * - Does not use/set @fd->pos. 1424 */ 1425 static inline s64 ntfs_device_win32_pread_simple(win32_fd *fd, const s64 pos, 1426 const s64 count, void *b) 1427 { 1428 return ntfs_device_win32_pio(fd, pos, count, b, (void*)NULL); 1429 } 1430 1431 /** 1432 * ntfs_device_win32_read - read bytes from an ntfs device 1433 * @dev: ntfs device obtained via ->open 1434 * @b: pointer to where to put the contents 1435 * @count: how many bytes should be read 1436 * 1437 * On success returns the number of bytes actually read (can be < @count). 1438 * On error returns -1 with errno set. 1439 */ 1440 static s64 ntfs_device_win32_read(struct ntfs_device *dev, void *b, s64 count) 1441 { 1442 s64 old_pos, to_read, i, br = 0; 1443 win32_fd *fd = (win32_fd *)dev->d_private; 1444 BYTE *alignedbuffer; 1445 int old_ofs, ofs; 1446 1447 old_pos = fd->pos; 1448 old_ofs = ofs = old_pos & (fd->geo_sector_size - 1); 1449 to_read = (ofs + count + fd->geo_sector_size - 1) & 1450 ~(s64)(fd->geo_sector_size - 1); 1451 /* Impose maximum of 2GB to be on the safe side. */ 1452 if (to_read > 0x80000000) { 1453 int delta = to_read - count; 1454 to_read = 0x80000000; 1455 count = to_read - delta; 1456 } 1457 ntfs_log_trace("fd = %p, b = %p, count = 0x%llx, pos = 0x%llx, " 1458 "ofs = %i, to_read = 0x%llx.\n", fd, b, 1459 (long long)count, (long long)old_pos, ofs, 1460 (long long)to_read); 1461 if (!((unsigned long)b & (fd->geo_sector_size - 1)) && !old_ofs && 1462 !(count & (fd->geo_sector_size - 1))) 1463 alignedbuffer = b; 1464 else { 1465 alignedbuffer = (BYTE *)VirtualAlloc(NULL, to_read, MEM_COMMIT, 1466 PAGE_READWRITE); 1467 if (!alignedbuffer) { 1468 errno = ntfs_w32error_to_errno(GetLastError()); 1469 ntfs_log_trace("VirtualAlloc failed for read.\n"); 1470 return -1; 1471 } 1472 } 1473 if (fd->vol_handle != INVALID_HANDLE_VALUE && old_pos < fd->geo_size) { 1474 s64 vol_to_read = fd->geo_size - old_pos; 1475 if (count > vol_to_read) { 1476 br = ntfs_device_win32_pread_simple(fd, 1477 old_pos & ~(s64)(fd->geo_sector_size - 1), 1478 ofs + vol_to_read, alignedbuffer); 1479 if (br == -1) 1480 goto read_error; 1481 to_read -= br; 1482 if (br < ofs) { 1483 br = 0; 1484 goto read_partial; 1485 } 1486 br -= ofs; 1487 fd->pos += br; 1488 ofs = fd->pos & (fd->geo_sector_size - 1); 1489 if (br != vol_to_read) 1490 goto read_partial; 1491 } 1492 } 1493 i = ntfs_device_win32_pread_simple(fd, 1494 fd->pos & ~(s64)(fd->geo_sector_size - 1), to_read, 1495 alignedbuffer + br); 1496 if (i == -1) { 1497 if (br) 1498 goto read_partial; 1499 goto read_error; 1500 } 1501 if (i < ofs) 1502 goto read_partial; 1503 i -= ofs; 1504 br += i; 1505 if (br > count) 1506 br = count; 1507 fd->pos = old_pos + br; 1508 read_partial: 1509 if (alignedbuffer != b) { 1510 memcpy((void*)b, alignedbuffer + old_ofs, br); 1511 VirtualFree(alignedbuffer, 0, MEM_RELEASE); 1512 } 1513 return br; 1514 read_error: 1515 if (alignedbuffer != b) 1516 VirtualFree(alignedbuffer, 0, MEM_RELEASE); 1517 return -1; 1518 } 1519 1520 /** 1521 * ntfs_device_win32_close - close an open ntfs deivce 1522 * @dev: ntfs device obtained via ->open 1523 * 1524 * Return 0 if o.k. 1525 * -1 if not, and errno set. Note if error fd->vol_handle is trashed. 1526 */ 1527 static int ntfs_device_win32_close(struct ntfs_device *dev) 1528 { 1529 win32_fd *fd = (win32_fd *)dev->d_private; 1530 BOOL rvl; 1531 1532 ntfs_log_trace("Closing device %p.\n", dev); 1533 if (!NDevOpen(dev)) { 1534 errno = EBADF; 1535 return -1; 1536 } 1537 if (fd->vol_handle != INVALID_HANDLE_VALUE) { 1538 if (!NDevReadOnly(dev)) { 1539 ntfs_device_win32_dismount(fd->vol_handle); 1540 ntfs_device_win32_unlock(fd->vol_handle); 1541 } 1542 if (!CloseHandle(fd->vol_handle)) 1543 ntfs_log_trace("CloseHandle() failed for volume.\n"); 1544 } 1545 if (fd->ntdll) { 1546 ntfs_device_win32_setlock(fd->handle,FSCTL_UNLOCK_VOLUME); 1547 rvl = NtClose(fd->handle) == STATUS_SUCCESS; 1548 } else 1549 rvl = CloseHandle(fd->handle); 1550 free(fd); 1551 if (!rvl) { 1552 errno = ntfs_w32error_to_errno(GetLastError()); 1553 if (fd->ntdll) 1554 ntfs_log_trace("NtClose() failed.\n"); 1555 else 1556 ntfs_log_trace("CloseHandle() failed.\n"); 1557 return -1; 1558 } 1559 return 0; 1560 } 1561 1562 /** 1563 * ntfs_device_win32_sync - flush write buffers to disk 1564 * @dev: ntfs device obtained via ->open 1565 * 1566 * Return 0 if o.k. 1567 * -1 if not, and errno set. 1568 * 1569 * Note: Volume syncing works differently in windows. 1570 * Disk cannot be synced in windows. 1571 */ 1572 static int ntfs_device_win32_sync(struct ntfs_device *dev) 1573 { 1574 int err = 0; 1575 BOOL to_clear = TRUE; 1576 1577 if (!NDevReadOnly(dev) && NDevDirty(dev)) { 1578 win32_fd *fd = (win32_fd *)dev->d_private; 1579 1580 if ((fd->vol_handle != INVALID_HANDLE_VALUE) && 1581 !FlushFileBuffers(fd->vol_handle)) { 1582 to_clear = FALSE; 1583 err = ntfs_w32error_to_errno(GetLastError()); 1584 } 1585 if (!FlushFileBuffers(fd->handle)) { 1586 to_clear = FALSE; 1587 if (!err) 1588 err = ntfs_w32error_to_errno(GetLastError()); 1589 } 1590 if (!to_clear) { 1591 ntfs_log_trace("Could not sync.\n"); 1592 errno = err; 1593 return -1; 1594 } 1595 NDevClearDirty(dev); 1596 } 1597 return 0; 1598 } 1599 1600 /** 1601 * ntfs_device_win32_pwrite_simple - positioned simple write 1602 * @fd: win32 device descriptor obtained via ->open 1603 * @pos: at which position to write to 1604 * @count: how many bytes should be written 1605 * @b: a pointer to the data to write 1606 * 1607 * On success returns the number of bytes written and on error returns -1 and 1608 * errno set. Write starts from position @pos. 1609 * 1610 * Notes: 1611 * - @pos, @buf, and @count must be aligned to geo_sector_size. 1612 * - When dealing with volumes, a single call must not span both volume 1613 * and disk extents. 1614 * - Does not use/set @fd->pos. 1615 */ 1616 static inline s64 ntfs_device_win32_pwrite_simple(win32_fd *fd, const s64 pos, 1617 const s64 count, const void *b) 1618 { 1619 return ntfs_device_win32_pio(fd, pos, count, (void*)NULL, b); 1620 } 1621 1622 /** 1623 * ntfs_device_win32_write - write bytes to an ntfs device 1624 * @dev: ntfs device obtained via ->open 1625 * @b: pointer to the data to write 1626 * @count: how many bytes should be written 1627 * 1628 * On success returns the number of bytes actually written. 1629 * On error returns -1 with errno set. 1630 */ 1631 static s64 ntfs_device_win32_write(struct ntfs_device *dev, const void *b, 1632 s64 count) 1633 { 1634 s64 old_pos, to_write, i, bw = 0; 1635 win32_fd *fd = (win32_fd *)dev->d_private; 1636 BYTE *alignedbuffer; 1637 int old_ofs, ofs; 1638 1639 old_pos = fd->pos; 1640 old_ofs = ofs = old_pos & (fd->geo_sector_size - 1); 1641 to_write = (ofs + count + fd->geo_sector_size - 1) & 1642 ~(s64)(fd->geo_sector_size - 1); 1643 /* Impose maximum of 2GB to be on the safe side. */ 1644 if (to_write > 0x80000000) { 1645 int delta = to_write - count; 1646 to_write = 0x80000000; 1647 count = to_write - delta; 1648 } 1649 ntfs_log_trace("fd = %p, b = %p, count = 0x%llx, pos = 0x%llx, " 1650 "ofs = %i, to_write = 0x%llx.\n", fd, b, 1651 (long long)count, (long long)old_pos, ofs, 1652 (long long)to_write); 1653 if (NDevReadOnly(dev)) { 1654 ntfs_log_trace("Can't write on a R/O device.\n"); 1655 errno = EROFS; 1656 return -1; 1657 } 1658 if (!count) 1659 return 0; 1660 NDevSetDirty(dev); 1661 if (!((unsigned long)b & (fd->geo_sector_size - 1)) && !old_ofs && 1662 !(count & (fd->geo_sector_size - 1))) 1663 alignedbuffer = (BYTE *)b; 1664 else { 1665 s64 end; 1666 1667 alignedbuffer = (BYTE *)VirtualAlloc(NULL, to_write, 1668 MEM_COMMIT, PAGE_READWRITE); 1669 if (!alignedbuffer) { 1670 errno = ntfs_w32error_to_errno(GetLastError()); 1671 ntfs_log_trace("VirtualAlloc failed for write.\n"); 1672 return -1; 1673 } 1674 /* Read first sector if start of write not sector aligned. */ 1675 if (ofs) { 1676 i = ntfs_device_win32_pread_simple(fd, 1677 old_pos & ~(s64)(fd->geo_sector_size - 1), 1678 fd->geo_sector_size, alignedbuffer); 1679 if (i != fd->geo_sector_size) { 1680 if (i >= 0) 1681 errno = EIO; 1682 goto write_error; 1683 } 1684 } 1685 /* 1686 * Read last sector if end of write not sector aligned and last 1687 * sector is either not the same as the first sector or it is 1688 * the same as the first sector but this has not been read in 1689 * yet, i.e. the start of the write is sector aligned. 1690 */ 1691 end = old_pos + count; 1692 if ((end & (fd->geo_sector_size - 1)) && 1693 ((to_write > fd->geo_sector_size) || !ofs)) { 1694 i = ntfs_device_win32_pread_simple(fd, 1695 end & ~(s64)(fd->geo_sector_size - 1), 1696 fd->geo_sector_size, alignedbuffer + 1697 to_write - fd->geo_sector_size); 1698 if (i != fd->geo_sector_size) { 1699 if (i >= 0) 1700 errno = EIO; 1701 goto write_error; 1702 } 1703 } 1704 /* Copy the data to be written into @alignedbuffer. */ 1705 memcpy(alignedbuffer + ofs, b, count); 1706 } 1707 if (fd->vol_handle != INVALID_HANDLE_VALUE && old_pos < fd->geo_size) { 1708 s64 vol_to_write = fd->geo_size - old_pos; 1709 if (count > vol_to_write) { 1710 bw = ntfs_device_win32_pwrite_simple(fd, 1711 old_pos & ~(s64)(fd->geo_sector_size - 1), 1712 ofs + vol_to_write, alignedbuffer); 1713 if (bw == -1) 1714 goto write_error; 1715 to_write -= bw; 1716 if (bw < ofs) { 1717 bw = 0; 1718 goto write_partial; 1719 } 1720 bw -= ofs; 1721 fd->pos += bw; 1722 ofs = fd->pos & (fd->geo_sector_size - 1); 1723 if (bw != vol_to_write) 1724 goto write_partial; 1725 } 1726 } 1727 i = ntfs_device_win32_pwrite_simple(fd, 1728 fd->pos & ~(s64)(fd->geo_sector_size - 1), to_write, 1729 alignedbuffer + bw); 1730 if (i == -1) { 1731 if (bw) 1732 goto write_partial; 1733 goto write_error; 1734 } 1735 if (i < ofs) 1736 goto write_partial; 1737 i -= ofs; 1738 bw += i; 1739 if (bw > count) 1740 bw = count; 1741 fd->pos = old_pos + bw; 1742 write_partial: 1743 if (alignedbuffer != b) 1744 VirtualFree(alignedbuffer, 0, MEM_RELEASE); 1745 return bw; 1746 write_error: 1747 bw = -1; 1748 goto write_partial; 1749 } 1750 1751 /** 1752 * ntfs_device_win32_stat - get a unix-like stat structure for an ntfs device 1753 * @dev: ntfs device obtained via ->open 1754 * @buf: pointer to the stat structure to fill 1755 * 1756 * Note: Only st_mode, st_size, and st_blocks are filled. 1757 * 1758 * Return 0 if o.k. 1759 * -1 if not and errno set. in this case handle is trashed. 1760 */ 1761 static int ntfs_device_win32_stat(struct ntfs_device *dev, struct stat *buf) 1762 { 1763 win32_fd *fd = (win32_fd *)dev->d_private; 1764 mode_t st_mode; 1765 1766 if ((dev->d_name[1] == ':') && (dev->d_name[2] == '\0')) 1767 st_mode = S_IFBLK; 1768 else 1769 switch (GetFileType(fd->handle)) { 1770 case FILE_TYPE_CHAR: 1771 st_mode = S_IFCHR; 1772 break; 1773 case FILE_TYPE_DISK: 1774 st_mode = S_IFREG; 1775 break; 1776 case FILE_TYPE_PIPE: 1777 st_mode = S_IFIFO; 1778 break; 1779 default: 1780 st_mode = 0; 1781 } 1782 memset(buf, 0, sizeof(struct stat)); 1783 buf->st_mode = st_mode; 1784 buf->st_size = fd->part_length; 1785 if (buf->st_size != -1) 1786 buf->st_blocks = buf->st_size >> 9; 1787 else 1788 buf->st_size = 0; 1789 return 0; 1790 } 1791 1792 #ifdef HDIO_GETGEO 1793 /** 1794 * ntfs_win32_hdio_getgeo - get drive geometry 1795 * @dev: ntfs device obtained via ->open 1796 * @argp: pointer to where to put the output 1797 * 1798 * Note: Works on windows NT/2k/XP only. 1799 * 1800 * Return 0 if o.k. 1801 * -1 if not, and errno set. Note if error fd->handle is trashed. 1802 */ 1803 static __inline__ int ntfs_win32_hdio_getgeo(struct ntfs_device *dev, 1804 struct hd_geometry *argp) 1805 { 1806 win32_fd *fd = (win32_fd *)dev->d_private; 1807 1808 argp->heads = fd->geo_heads; 1809 argp->sectors = fd->geo_sectors; 1810 argp->cylinders = fd->geo_cylinders; 1811 argp->start = fd->part_hidden_sectors; 1812 return 0; 1813 } 1814 #endif 1815 1816 /** 1817 * ntfs_win32_blksszget - get block device sector size 1818 * @dev: ntfs device obtained via ->open 1819 * @argp: pointer to where to put the output 1820 * 1821 * Note: Works on windows NT/2k/XP only. 1822 * 1823 * Return 0 if o.k. 1824 * -1 if not, and errno set. Note if error fd->handle is trashed. 1825 */ 1826 static __inline__ int ntfs_win32_blksszget(struct ntfs_device *dev,int *argp) 1827 { 1828 win32_fd *fd = (win32_fd *)dev->d_private; 1829 DWORD bytesReturned; 1830 DISK_GEOMETRY dg; 1831 1832 if (DeviceIoControl(fd->handle, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, 1833 &dg, sizeof(DISK_GEOMETRY), &bytesReturned, NULL)) { 1834 /* success */ 1835 *argp = dg.BytesPerSector; 1836 return 0; 1837 } 1838 errno = ntfs_w32error_to_errno(GetLastError()); 1839 ntfs_log_trace("GET_DRIVE_GEOMETRY failed.\n"); 1840 return -1; 1841 } 1842 1843 static int ntfs_device_win32_ioctl(struct ntfs_device *dev, int request, 1844 void *argp) 1845 { 1846 #if defined(BLKGETSIZE) | defined(BLKGETSIZE64) 1847 win32_fd *fd = (win32_fd *)dev->d_private; 1848 #endif 1849 1850 ntfs_log_trace("win32_ioctl(%d) called.\n", request); 1851 switch (request) { 1852 #if defined(BLKGETSIZE) 1853 case BLKGETSIZE: 1854 ntfs_log_debug("BLKGETSIZE detected.\n"); 1855 if (fd->part_length >= 0) { 1856 *(int *)argp = (int)(fd->part_length / 512); 1857 return 0; 1858 } 1859 errno = EOPNOTSUPP; 1860 return -1; 1861 #endif 1862 #if defined(BLKGETSIZE64) 1863 case BLKGETSIZE64: 1864 ntfs_log_debug("BLKGETSIZE64 detected.\n"); 1865 if (fd->part_length >= 0) { 1866 *(s64 *)argp = fd->part_length; 1867 return 0; 1868 } 1869 errno = EOPNOTSUPP; 1870 return -1; 1871 #endif 1872 #ifdef HDIO_GETGEO 1873 case HDIO_GETGEO: 1874 ntfs_log_debug("HDIO_GETGEO detected.\n"); 1875 return ntfs_win32_hdio_getgeo(dev, (struct hd_geometry *)argp); 1876 #endif 1877 #ifdef BLKSSZGET 1878 case BLKSSZGET: 1879 ntfs_log_debug("BLKSSZGET detected.\n"); 1880 return ntfs_win32_blksszget(dev, (int *)argp); 1881 #endif 1882 #ifdef BLKBSZSET 1883 case BLKBSZSET: 1884 ntfs_log_debug("BLKBSZSET detected.\n"); 1885 /* Nothing to do on Windows. */ 1886 return 0; 1887 #endif 1888 default: 1889 ntfs_log_debug("unimplemented ioctl %d.\n", request); 1890 errno = EOPNOTSUPP; 1891 return -1; 1892 } 1893 } 1894 1895 static s64 ntfs_device_win32_pread(struct ntfs_device *dev, void *b, 1896 s64 count, s64 offset) 1897 { 1898 s64 got; 1899 win32_fd *fd; 1900 1901 /* read the fast way if sector aligned */ 1902 fd = (win32_fd*)dev->d_private; 1903 if (!((count | offset) & (fd->geo_sector_size - 1))) { 1904 got = ntfs_device_win32_pio(fd, offset, count, b, (void*)NULL); 1905 } else { 1906 if (ntfs_device_win32_seek(dev, offset, 0) == -1) 1907 got = 0; 1908 else 1909 got = ntfs_device_win32_read(dev, b, count); 1910 } 1911 1912 return (got); 1913 } 1914 1915 static s64 ntfs_device_win32_pwrite(struct ntfs_device *dev, const void *b, 1916 s64 count, s64 offset) 1917 { 1918 s64 put; 1919 win32_fd *fd; 1920 1921 /* write the fast way if sector aligned */ 1922 fd = (win32_fd*)dev->d_private; 1923 if (!((count | offset) & (fd->geo_sector_size - 1))) { 1924 put = ntfs_device_win32_pio(fd, offset, count, (void*)NULL, b); 1925 } else { 1926 if (ntfs_device_win32_seek(dev, offset, 0) == -1) 1927 put = 0; 1928 else 1929 put = ntfs_device_win32_write(dev, b, count); 1930 } 1931 return (put); 1932 } 1933 1934 struct ntfs_device_operations ntfs_device_win32_io_ops = { 1935 .open = ntfs_device_win32_open, 1936 .close = ntfs_device_win32_close, 1937 .seek = ntfs_device_win32_seek, 1938 .read = ntfs_device_win32_read, 1939 .write = ntfs_device_win32_write, 1940 .pread = ntfs_device_win32_pread, 1941 .pwrite = ntfs_device_win32_pwrite, 1942 .sync = ntfs_device_win32_sync, 1943 .stat = ntfs_device_win32_stat, 1944 .ioctl = ntfs_device_win32_ioctl 1945 }; 1946 1947 /* 1948 * Mark an open file as sparse 1949 * 1950 * This is only called by ntfsclone when cloning a volume to a file. 1951 * The argument is the target file, not a volume. 1952 * 1953 * Returns 0 if successful. 1954 */ 1955 1956 int ntfs_win32_set_sparse(int fd) 1957 { 1958 BOOL ok; 1959 HANDLE handle; 1960 DWORD bytes; 1961 1962 handle = get_osfhandle(fd); 1963 if (handle == INVALID_HANDLE_VALUE) 1964 ok = FALSE; 1965 else 1966 ok = DeviceIoControl(handle, FSCTL_SET_SPARSE, 1967 (void*)NULL, 0, (void*)NULL, 0, 1968 &bytes, (LPOVERLAPPED)NULL); 1969 return (!ok); 1970 } 1971 1972 /* 1973 * Resize an open file 1974 * 1975 * This is only called by ntfsclone when cloning a volume to a file. 1976 * The argument must designate a file, not a volume. 1977 * 1978 * Returns 0 if successful. 1979 */ 1980 1981 static int win32_ftruncate(HANDLE handle, s64 size) 1982 { 1983 BOOL ok; 1984 LONG hsize, lsize; 1985 LONG ohsize, olsize; 1986 1987 if (handle == INVALID_HANDLE_VALUE) 1988 ok = FALSE; 1989 else { 1990 SetLastError(NO_ERROR); 1991 /* save original position */ 1992 ohsize = 0; 1993 olsize = SetFilePointer(handle, 0, &ohsize, 1); 1994 hsize = size >> 32; 1995 lsize = size & 0xffffffff; 1996 ok = (SetFilePointer(handle, lsize, &hsize, 0) == (DWORD)lsize) 1997 && (GetLastError() == NO_ERROR) 1998 && SetEndOfFile(handle); 1999 /* restore original position, even if above failed */ 2000 SetFilePointer(handle, olsize, &ohsize, 0); 2001 if (GetLastError() != NO_ERROR) 2002 ok = FALSE; 2003 } 2004 if (!ok) 2005 errno = EINVAL; 2006 return (ok ? 0 : -1); 2007 } 2008 2009 int ntfs_device_win32_ftruncate(struct ntfs_device *dev, s64 size) 2010 { 2011 win32_fd *fd; 2012 int ret; 2013 2014 ret = -1; 2015 fd = (win32_fd*)dev->d_private; 2016 if (fd && !fd->ntdll) 2017 ret = win32_ftruncate(fd->handle, size); 2018 return (ret); 2019 } 2020 2021 int ntfs_win32_ftruncate(int fd, s64 size) 2022 { 2023 int ret; 2024 HANDLE handle; 2025 2026 handle = get_osfhandle(fd); 2027 ret = win32_ftruncate(handle, size); 2028 return (ret); 2029 } 2030