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