📄 win32_io.c
字号:
} errno = ntfs_w32error_to_errno(GetLastError()); ntfs_log_trace("Couldn't retrieve disk geometry.\n"); fd->geo_cylinders = -1; fd->geo_sectors = -1; fd->geo_size = -1; return -1;}/** * ntfs_device_win32_open_file - open a file via win32 API * @filename: name of the file to open * @fd: pointer to win32 file device in which to put the result * @flags: unix open status flags * * Return 0 if o.k. * -1 if not, and errno set. */static __inline__ int ntfs_device_win32_open_file(char *filename, win32_fd *fd, int flags){ HANDLE handle; if (ntfs_device_win32_simple_open_file(filename, &handle, flags, FALSE)) { /* open error */ return -1; } /* fill fd */ fd->handle = handle; fd->part_start = 0; fd->part_length = ntfs_device_win32_getsize(handle); fd->pos = 0; fd->part_hidden_sectors = -1; fd->geo_size = -1; /* used as a marker that this is a file */ fd->vol_handle = INVALID_HANDLE_VALUE; return 0;}/** * ntfs_device_win32_open_drive - open a drive via win32 API * @drive_id: drive to open * @fd: pointer to win32 file device in which to put the result * @flags: unix open status flags * * return 0 if o.k. * -1 if not, and errno set. */static __inline__ int ntfs_device_win32_open_drive(int drive_id, win32_fd *fd, int flags){ HANDLE handle; int err; char filename[MAX_PATH]; sprintf(filename, "\\\\.\\PhysicalDrive%d", drive_id); if ((err = ntfs_device_win32_simple_open_file(filename, &handle, flags, TRUE))) { /* open error */ return err; } /* store the drive geometry */ ntfs_device_win32_getgeo(handle, fd); /* Just to be sure */ if (fd->geo_size == -1) fd->geo_size = ntfs_device_win32_getdisklength(handle); /* fill fd */ fd->handle = handle; fd->part_start = 0; fd->part_length = fd->geo_size; fd->pos = 0; fd->part_hidden_sectors = -1; fd->vol_handle = INVALID_HANDLE_VALUE; return 0;}/** * ntfs_device_win32_open_volume_for_partition - find and open a volume * * Windows NT/2k/XP handles volumes instead of partitions. * This function gets the partition details and return an open volume handle. * That volume is the one whose only physical location on disk is the described * partition. * * The function required Windows 2k/XP, otherwise it fails (gracefully). * * Return success: a valid open volume handle. * fail : INVALID_HANDLE_VALUE */static HANDLE ntfs_device_win32_open_volume_for_partition(unsigned int drive_id, s64 part_offset, s64 part_length, int flags){ HANDLE vol_find_handle; TCHAR vol_name[MAX_PATH]; /* Make sure all the required imports exist. */ if (!fnFindFirstVolume || !fnFindNextVolume || !fnFindVolumeClose) { ntfs_log_trace("Required dll imports not found.\n"); return INVALID_HANDLE_VALUE; } /* Start iterating through volumes. */ ntfs_log_trace("Entering with drive_id=%d, part_offset=%lld, " "path_length=%lld, flags=%d.\n", drive_id, (unsigned long long)part_offset, (unsigned long long)part_length, flags); vol_find_handle = fnFindFirstVolume(vol_name, MAX_PATH); /* If a valid handle could not be aquired, reply with "don't know". */ if (vol_find_handle == INVALID_HANDLE_VALUE) { ntfs_log_trace("FindFirstVolume failed.\n"); return INVALID_HANDLE_VALUE; } do { int vol_name_length; HANDLE handle; /* remove trailing '/' from vol_name */#ifdef UNICODE vol_name_length = wcslen(vol_name);#else vol_name_length = strlen(vol_name);#endif if (vol_name_length>0) vol_name[vol_name_length-1]=0; ntfs_log_debug("Processing %s.\n", vol_name); /* open the file */ handle = CreateFile(vol_name, ntfs_device_unix_status_flags_to_win32(flags), FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if (handle != INVALID_HANDLE_VALUE) { DWORD bytesReturned;#define EXTENTS_SIZE sizeof(VOLUME_DISK_EXTENTS) + 9 * sizeof(DISK_EXTENT) char extents[EXTENTS_SIZE]; /* Check physical locations. */ if (DeviceIoControl(handle, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, NULL, 0, extents, EXTENTS_SIZE, &bytesReturned, NULL)) { if (((VOLUME_DISK_EXTENTS *)extents)-> NumberOfDiskExtents == 1) { DISK_EXTENT *extent = &(( VOLUME_DISK_EXTENTS *) extents)->Extents[0]; if ((extent->DiskNumber==drive_id) && (extent->StartingOffset. QuadPart==part_offset) && (extent-> ExtentLength.QuadPart == part_length)) { /* * Eureka! (Archimedes, 287 BC, * "I have found it!") */ fnFindVolumeClose( vol_find_handle); return handle; } } } } else ntfs_log_trace("getExtents() Failed.\n"); } while (fnFindNextVolume(vol_find_handle, vol_name, MAX_PATH)); /* End of iteration through volumes. */ ntfs_log_trace("Closing, volume was not found.\n"); fnFindVolumeClose(vol_find_handle); return INVALID_HANDLE_VALUE;}/** * ntfs_device_win32_find_partition - locates partition details by id. * @handle: HANDLE to the PhysicalDrive * @partition_id: the partition number to locate * @part_offset: pointer to where to put the offset to the partition * @part_length: pointer to where to put the length of the partition * @hidden_sectors: pointer to where to put the hidden sectors * * This function requires an open PhysicalDrive handle and a partition_id. * If a partition with the required id is found on the supplied device, * the partition attributes are returned back. * * Returns: TRUE if found, and sets the output parameters. * FALSE if not and errno is set to the error code. */static BOOL ntfs_device_win32_find_partition(HANDLE handle, DWORD partition_id, s64 *part_offset, s64 *part_length, int *hidden_sectors){ DRIVE_LAYOUT_INFORMATION *drive_layout; unsigned int err, buf_size, part_count; DWORD i; /* * There is no way to know the required buffer, so if the ioctl fails, * try doubling the buffer size each time until the ioctl succeeds. */ part_count = 8; do { buf_size = sizeof(DRIVE_LAYOUT_INFORMATION) + part_count * sizeof(PARTITION_INFORMATION); drive_layout = malloc(buf_size); if (!drive_layout) { errno = ENOMEM; return FALSE; } if (DeviceIoControl(handle, IOCTL_DISK_GET_DRIVE_LAYOUT, NULL, 0, (BYTE*)drive_layout, buf_size, &i, NULL)) break; err = GetLastError(); free(drive_layout); if (err != ERROR_INSUFFICIENT_BUFFER) { ntfs_log_trace("GetDriveLayout failed.\n"); errno = ntfs_w32error_to_errno(err); return FALSE; } ntfs_log_debug("More than %u partitions.\n", part_count); part_count <<= 1; if (part_count > 512) { ntfs_log_trace("GetDriveLayout failed: More than 512 " "partitions?\n"); errno = ENOBUFS; return FALSE; } } while (1); for (i = 0; i < drive_layout->PartitionCount; i++) { if (drive_layout->PartitionEntry[i].PartitionNumber == partition_id) { *part_offset = drive_layout->PartitionEntry[i]. StartingOffset.QuadPart; *part_length = drive_layout->PartitionEntry[i]. PartitionLength.QuadPart; *hidden_sectors = drive_layout->PartitionEntry[i]. HiddenSectors; free(drive_layout); return TRUE; } } free(drive_layout); errno = ENOENT; return FALSE;}/** * ntfs_device_win32_open_partition - open a partition via win32 API * @drive_id: drive to open * @partition_id: partition to open * @fd: win32 file device to return * @flags: unix open status flags * * Return 0 if o.k. * -1 if not, and errno set. * * When fails, fd contents may have not been preserved. */static int ntfs_device_win32_open_partition(int drive_id, unsigned int partition_id, win32_fd *fd, int flags){ s64 part_start, part_length; HANDLE handle; int err, hidden_sectors; char drive_name[MAX_PATH]; sprintf(drive_name, "\\\\.\\PhysicalDrive%d", drive_id); /* Open the entire device without locking, ask questions later */ if ((err = ntfs_device_win32_simple_open_file(drive_name, &handle, flags, FALSE))) { /* error */ return err; } if (ntfs_device_win32_find_partition(handle, partition_id, &part_start, &part_length, &hidden_sectors)) { s64 tmp; HANDLE vol_handle = ntfs_device_win32_open_volume_for_partition( drive_id, part_start, part_length, flags); /* Store the drive geometry. */ ntfs_device_win32_getgeo(handle, fd); fd->handle = handle; fd->pos = 0; fd->part_start = part_start; fd->part_length = part_length; fd->part_hidden_sectors = hidden_sectors; tmp = ntfs_device_win32_getntfssize(vol_handle); if (tmp > 0) fd->geo_size = tmp; else fd->geo_size = fd->part_length; if (vol_handle != INVALID_HANDLE_VALUE) { if (((flags & O_RDWR) == O_RDWR) && ntfs_device_win32_lock(vol_handle)) { CloseHandle(vol_handle); CloseHandle(handle); return -1; } fd->vol_handle = vol_handle; } else { if ((flags & O_RDWR) == O_RDWR) { /* Access if read-write, no volume found. */ ntfs_log_trace("Partitions containing Spanned/" "Mirrored volumes are not " "supported in R/W status " "yet.\n"); CloseHandle(handle); errno = EOPNOTSUPP; return -1; } fd->vol_handle = INVALID_HANDLE_VALUE; } return 0; } else { ntfs_log_debug("Partition %u not found on drive %d.\n", partition_id, drive_id); CloseHandle(handle); errno = ENODEV; return -1; }}/** * ntfs_device_win32_open - open a device * @dev: a pointer to the NTFS_DEVICE to open * @flags: unix open status flags * * @dev->d_name must hold the device name, the rest is ignored. * Supported flags are O_RDONLY, O_WRONLY and O_RDWR. * * If name is in format "(hd[0-9],[0-9])" then open a partition. * If name is in format "(hd[0-9])" then open a volume. * Otherwise open a file. */static int ntfs_device_win32_open(struct ntfs_device *dev, int flags){ int drive_id = 0, numparams; unsigned int part = 0; char drive_char; win32_fd fd; int err; if (NDevOpen(dev)) { errno = EBUSY; return -1; } ntfs_device_win32_init_imports(); numparams = sscanf(dev->d_name, "/dev/hd%c%u", &drive_char, &part); drive_id = toupper(drive_char) - 'A'; switch (numparams) { case 0: ntfs_log_debug("win32_open(%s) -> file.\n", dev->d_name); err = ntfs_device_win32_open_file(dev->d_name, &fd, flags); break; case 1: ntfs_log_debug("win32_open(%s) -> drive %d.\n", dev->d_name, drive_id); err = ntfs_device_win32_open_drive(drive_id, &fd, flags); break; case 2: ntfs_log_debug("win32_open(%s) -> drive %d, part %u.\n", dev->d_name, drive_id, part); err = ntfs_device_win32_open_partition(drive_id, part, &fd, flags); break; default: ntfs_log_debug("win32_open(%s) -> unknwon file format.\n", dev->d_name); err = -1; } if (err) return err; ntfs_log_debug("win32_open(%s) -> %p, offset 0x%llx.\n", dev->d_name, dev, fd.part_start); /* Setup our read-only flag. */ if ((flags & O_RDWR) != O_RDWR) NDevSetReadOnly(dev); dev->d_private = malloc(sizeof(win32_fd)); memcpy(dev->d_private, &fd, sizeof(win32_fd)); NDevSetOpen(dev); NDevClearDirty(dev); return 0;}/** * ntfs_device_win32_seek - change current logical file position * @dev: ntfs device obtained via ->open * @offset: required offset from the whence anchor * @whence: whence anchor specifying what @offset is relative to * * Return the new position on the volume on success and -1 on error with errno * set to the error code. * * @whence may be one of the following: * SEEK_SET - Offset is relative to file start. * SEEK_CUR - Offset is relative to current position. * SEEK_END - Offset is relative to end of file. */static s64 ntfs_device_win32_seek(struct ntfs_device *dev, s64 offset, int whence){ s64 abs_ofs; win32_fd *fd = (win32_fd *)dev->d_private; ntfs_log_trace("seek offset = 0x%llx, whence = %d.\n", offset, whence); switch (whence) { case SEEK_SET: abs_ofs = offset; break; case SEEK_CUR: abs_ofs = fd->pos + offset; break; case SEEK_END: /* End of partition != end of disk. */ if (fd->part_length == -1) { ntfs_log_trace("Position relative to end of disk not " "implemented.\n"); errno = EOPNOTSUPP; return -1; } abs_ofs = fd->part_length + offset; break; default: ntfs_log_trace("Wrong mode %d.\n", whence); errno = EINVAL; return -1; } if (abs_ofs < 0 || abs_ofs > fd->part_length) { ntfs_log_trace("Seeking outsize seekable area.\n"); errno = EINVAL; return -1; } fd->pos = abs_ofs; return abs_ofs;}/** * ntfs_device_win32_pio - positioned low level i/o * @fd: win32 device descriptor obtained via ->open * @pos: at which position to do i/o from/to * @count: how many bytes should be transfered * @b: source/destination buffer * @write: TRUE if write transfer and FALSE if read transfer * * On success returns the number of bytes transfered (can be < @count) and on * error returns -1 and errno set. Transfer starts from position @pos on @fd. * * Notes: * - @pos, @buf, and @count must be aligned to NTFS_BLOCK_SIZE. * - When dealing with volumes, a single call must not span both volume * and disk extents. * - Does not use/set @fd->pos. */static s64 ntfs_device_win32_pio(win32_fd *fd, const s64 pos, const s64 count, void *b, const BOOL write){ LARGE_INTEGER li; HANDLE handle; DWORD bt; BOOL res; ntfs_log_trace("pos = 0x%llx, count = 0x%llx, direction = %s.\n", (long long)pos, (long long)count, write ? "write" : "read"); li.QuadPart = pos; if (fd->vol_handle != INVALID_HANDLE_VALUE && pos < fd->geo_size) { ntfs_log_debug("Transfering via vol_handle.\n"); handle = fd->vol_handle; } else { ntfs_log_debug("Transfering via handle.\n"); handle = fd->handle; li.QuadPart += fd->part_start; } if (!fnSetFilePointerEx(handle, li, NULL, FILE_BEGIN)) { errno = ntfs_w32error_to_errno(GetLastError()); ntfs_log_trace("SetFilePointer failed.\n"); return -1; } if (write) res = WriteFile(handle, b, count, &bt, NULL); else res = ReadFile(handle, b, count, &bt, NULL); if (!res) { errno = ntfs_w32error_to_errno(GetLastError()); ntfs_log_trace("%sFile() failed.\n", write ? "Write" : "Read"); return -1; } return bt;}/** * ntfs_device_win32_pread_simple - positioned simple read * @fd: win32 device descriptor obtained via ->open * @pos: at which position to read from * @count: how many bytes should be read * @b: a pointer to where to put the contents *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -