📄 win32_io.c
字号:
* On success returns the number of bytes read (can be < @count) and on error * returns -1 and errno set. Read starts from position @pos. * * 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 inline s64 ntfs_device_win32_pread_simple(win32_fd *fd, const s64 pos, const s64 count, void *b){ return ntfs_device_win32_pio(fd, pos, count, b, FALSE);}/** * ntfs_device_win32_read - read bytes from an ntfs device * @dev: ntfs device obtained via ->open * @b: pointer to where to put the contents * @count: how many bytes should be read * * On success returns the number of bytes actually read (can be < @count). * On error returns -1 with errno set. */static s64 ntfs_device_win32_read(struct ntfs_device *dev, void *b, s64 count){ s64 old_pos, to_read, i, br = 0; win32_fd *fd = (win32_fd *)dev->d_private; BYTE *alignedbuffer; int old_ofs, ofs; old_pos = fd->pos; old_ofs = ofs = old_pos & (NTFS_BLOCK_SIZE - 1); to_read = (ofs + count + NTFS_BLOCK_SIZE - 1) & ~(s64)(NTFS_BLOCK_SIZE - 1); /* Impose maximum of 2GB to be on the safe side. */ if (to_read > 0x80000000) { int delta = to_read - count; to_read = 0x80000000; count = to_read - delta; } ntfs_log_trace("fd = %p, b = %p, count = 0x%llx, pos = 0x%llx, " "ofs = %i, to_read = 0x%llx.\n", fd, b, (long long)count, (long long)old_pos, ofs, (long long)to_read); if (!((unsigned long)b & (NTFS_BLOCK_SIZE - 1)) && !old_ofs && !(count & (NTFS_BLOCK_SIZE - 1))) alignedbuffer = b; else { alignedbuffer = (BYTE *)VirtualAlloc(NULL, to_read, MEM_COMMIT, PAGE_READWRITE); if (!alignedbuffer) { errno = ntfs_w32error_to_errno(GetLastError()); ntfs_log_trace("VirtualAlloc failed for read.\n"); return -1; } } if (fd->vol_handle != INVALID_HANDLE_VALUE && old_pos < fd->geo_size) { s64 vol_to_read = fd->geo_size - old_pos; if (count > vol_to_read) { br = ntfs_device_win32_pread_simple(fd, old_pos & ~(s64)(NTFS_BLOCK_SIZE - 1), ofs + vol_to_read, alignedbuffer); if (br == -1) goto read_error; to_read -= br; if (br < ofs) { br = 0; goto read_partial; } br -= ofs; fd->pos += br; ofs = fd->pos & (NTFS_BLOCK_SIZE - 1); if (br != vol_to_read) goto read_partial; } } i = ntfs_device_win32_pread_simple(fd, fd->pos & ~(s64)(NTFS_BLOCK_SIZE - 1), to_read, alignedbuffer + br); if (i == -1) { if (br) goto read_partial; goto read_error; } if (i < ofs) goto read_partial; i -= ofs; br += i; if (br > count) br = count; fd->pos = old_pos + br;read_partial: if (alignedbuffer != b) { memcpy((void*)b, alignedbuffer + old_ofs, br); VirtualFree(alignedbuffer, 0, MEM_RELEASE); } return br;read_error: if (alignedbuffer != b) VirtualFree(alignedbuffer, 0, MEM_RELEASE); return -1;}/** * ntfs_device_win32_close - close an open ntfs deivce * @dev: ntfs device obtained via ->open * * Return 0 if o.k. * -1 if not, and errno set. Note if error fd->vol_handle is trashed. */static int ntfs_device_win32_close(struct ntfs_device *dev){ win32_fd *fd = (win32_fd *)dev->d_private; BOOL rvl; ntfs_log_trace("Closing device %p.\n", dev); if (!NDevOpen(dev)) { errno = EBADF; return -1; } if (fd->vol_handle != INVALID_HANDLE_VALUE) { if (!NDevReadOnly(dev)) { ntfs_device_win32_dismount(fd->vol_handle); ntfs_device_win32_unlock(fd->vol_handle); } if (!CloseHandle(fd->vol_handle)) ntfs_log_trace("CloseHandle() failed for volume.\n"); } rvl = CloseHandle(fd->handle); free(fd); if (!rvl) { errno = ntfs_w32error_to_errno(GetLastError()); ntfs_log_trace("CloseHandle() failed.\n"); return -1; } return 0;}/** * ntfs_device_win32_sync - flush write buffers to disk * @dev: ntfs device obtained via ->open * * Return 0 if o.k. * -1 if not, and errno set. * * Note: Volume syncing works differently in windows. * Disk cannot be synced in windows. */static int ntfs_device_win32_sync(struct ntfs_device *dev){ int err = 0; BOOL to_clear = TRUE; if (!NDevReadOnly(dev) && NDevDirty(dev)) { win32_fd *fd = (win32_fd *)dev->d_private; if ((fd->vol_handle != INVALID_HANDLE_VALUE) && !FlushFileBuffers(fd->vol_handle)) { to_clear = FALSE; err = ntfs_w32error_to_errno(GetLastError()); } if (!FlushFileBuffers(fd->handle)) { to_clear = FALSE; if (!err) err = ntfs_w32error_to_errno(GetLastError()); } if (!to_clear) { ntfs_log_trace("Could not sync.\n"); errno = err; return -1; } NDevClearDirty(dev); } return 0;}/** * ntfs_device_win32_pwrite_simple - positioned simple write * @fd: win32 device descriptor obtained via ->open * @pos: at which position to write to * @count: how many bytes should be written * @b: a pointer to the data to write * * On success returns the number of bytes written and on error returns -1 and * errno set. Write starts from position @pos. * * 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 inline s64 ntfs_device_win32_pwrite_simple(win32_fd *fd, const s64 pos, const s64 count, const void *b){ return ntfs_device_win32_pio(fd, pos, count, (void *)b, TRUE);}/** * ntfs_device_win32_write - write bytes to an ntfs device * @dev: ntfs device obtained via ->open * @b: pointer to the data to write * @count: how many bytes should be written * * On success returns the number of bytes actually written. * On error returns -1 with errno set. */static s64 ntfs_device_win32_write(struct ntfs_device *dev, const void *b, s64 count){ s64 old_pos, to_write, i, bw = 0; win32_fd *fd = (win32_fd *)dev->d_private; BYTE *alignedbuffer; int old_ofs, ofs; old_pos = fd->pos; old_ofs = ofs = old_pos & (NTFS_BLOCK_SIZE - 1); to_write = (ofs + count + NTFS_BLOCK_SIZE - 1) & ~(s64)(NTFS_BLOCK_SIZE - 1); /* Impose maximum of 2GB to be on the safe side. */ if (to_write > 0x80000000) { int delta = to_write - count; to_write = 0x80000000; count = to_write - delta; } ntfs_log_trace("fd = %p, b = %p, count = 0x%llx, pos = 0x%llx, " "ofs = %i, to_write = 0x%llx.\n", fd, b, (long long)count, (long long)old_pos, ofs, (long long)to_write); if (NDevReadOnly(dev)) { ntfs_log_trace("Can't write on a R/O device.\n"); errno = EROFS; return -1; } if (!count) return 0; NDevSetDirty(dev); if (!((unsigned long)b & (NTFS_BLOCK_SIZE - 1)) && !old_ofs && !(count & (NTFS_BLOCK_SIZE - 1))) alignedbuffer = (BYTE *)b; else { s64 end; alignedbuffer = (BYTE *)VirtualAlloc(NULL, to_write, MEM_COMMIT, PAGE_READWRITE); if (!alignedbuffer) { errno = ntfs_w32error_to_errno(GetLastError()); ntfs_log_trace("VirtualAlloc failed for write.\n"); return -1; } /* Read first sector if start of write not sector aligned. */ if (ofs) { i = ntfs_device_win32_pread_simple(fd, old_pos & ~(s64)(NTFS_BLOCK_SIZE - 1), NTFS_BLOCK_SIZE, alignedbuffer); if (i != NTFS_BLOCK_SIZE) { if (i >= 0) errno = EIO; goto write_error; } } /* * Read last sector if end of write not sector aligned and last * sector is either not the same as the first sector or it is * the same as the first sector but this has not been read in * yet, i.e. the start of the write is sector aligned. */ end = old_pos + count; if ((end & (NTFS_BLOCK_SIZE - 1)) && ((to_write > NTFS_BLOCK_SIZE) || !ofs)) { i = ntfs_device_win32_pread_simple(fd, end & ~(s64)(NTFS_BLOCK_SIZE - 1), NTFS_BLOCK_SIZE, alignedbuffer + to_write - NTFS_BLOCK_SIZE); if (i != NTFS_BLOCK_SIZE) { if (i >= 0) errno = EIO; goto write_error; } } /* Copy the data to be written into @alignedbuffer. */ memcpy(alignedbuffer + ofs, b, count); } if (fd->vol_handle != INVALID_HANDLE_VALUE && old_pos < fd->geo_size) { s64 vol_to_write = fd->geo_size - old_pos; if (count > vol_to_write) { bw = ntfs_device_win32_pwrite_simple(fd, old_pos & ~(s64)(NTFS_BLOCK_SIZE - 1), ofs + vol_to_write, alignedbuffer); if (bw == -1) goto write_error; to_write -= bw; if (bw < ofs) { bw = 0; goto write_partial; } bw -= ofs; fd->pos += bw; ofs = fd->pos & (NTFS_BLOCK_SIZE - 1); if (bw != vol_to_write) goto write_partial; } } i = ntfs_device_win32_pwrite_simple(fd, fd->pos & ~(s64)(NTFS_BLOCK_SIZE - 1), to_write, alignedbuffer + bw); if (i == -1) { if (bw) goto write_partial; goto write_error; } if (i < ofs) goto write_partial; i -= ofs; bw += i; if (bw > count) bw = count; fd->pos = old_pos + bw;write_partial: if (alignedbuffer != b) VirtualFree(alignedbuffer, 0, MEM_RELEASE); return bw;write_error: bw = -1; goto write_partial;}/** * ntfs_device_win32_stat - get a unix-like stat structure for an ntfs device * @dev: ntfs device obtained via ->open * @buf: pointer to the stat structure to fill * * Note: Only st_mode, st_size, and st_blocks are filled. * * Return 0 if o.k. * -1 if not and errno set. in this case handle is trashed. */static int ntfs_device_win32_stat(struct ntfs_device *dev, struct stat *buf){ win32_fd *fd = (win32_fd *)dev->d_private; mode_t st_mode; switch (GetFileType(fd->handle)) { case FILE_TYPE_CHAR: st_mode = S_IFCHR; break; case FILE_TYPE_DISK: st_mode = S_IFBLK; break; case FILE_TYPE_PIPE: st_mode = S_IFIFO; break; default: st_mode = 0; } memset(buf, 0, sizeof(struct stat)); buf->st_mode = st_mode; buf->st_size = fd->part_length; if (buf->st_size != -1) buf->st_blocks = buf->st_size >> 9; else buf->st_size = 0; return 0;}/** * ntfs_win32_hdio_getgeo - get drive geometry * @dev: ntfs device obtained via ->open * @argp: pointer to where to put the output * * Note: Works on windows NT/2k/XP only. * * Return 0 if o.k. * -1 if not, and errno set. Note if error fd->handle is trashed. */static __inline__ int ntfs_win32_hdio_getgeo(struct ntfs_device *dev, struct hd_geometry *argp){ win32_fd *fd = (win32_fd *)dev->d_private; argp->heads = fd->geo_heads; argp->sectors = fd->geo_sectors; argp->cylinders = fd->geo_cylinders; argp->start = fd->part_hidden_sectors; return 0;}/** * ntfs_win32_blksszget - get block device sector size * @dev: ntfs device obtained via ->open * @argp: pointer to where to put the output * * Note: Works on windows NT/2k/XP only. * * Return 0 if o.k. * -1 if not, and errno set. Note if error fd->handle is trashed. */static __inline__ int ntfs_win32_blksszget(struct ntfs_device *dev,int *argp){ win32_fd *fd = (win32_fd *)dev->d_private; DWORD bytesReturned; DISK_GEOMETRY dg; if (DeviceIoControl(fd->handle, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &dg, sizeof(DISK_GEOMETRY), &bytesReturned, NULL)) { /* success */ *argp = dg.BytesPerSector; return 0; } errno = ntfs_w32error_to_errno(GetLastError()); ntfs_log_trace("GET_DRIVE_GEOMETRY failed.\n"); return -1;}static int ntfs_device_win32_ioctl(struct ntfs_device *dev, int request, void *argp){ win32_fd *fd = (win32_fd *)dev->d_private; ntfs_log_trace("win32_ioctl(%d) called.\n", request); switch (request) {#if defined(BLKGETSIZE) case BLKGETSIZE: ntfs_log_debug("BLKGETSIZE detected.\n"); if (fd->part_length >= 0) { *(int *)argp = (int)(fd->part_length / 512); return 0; } errno = EOPNOTSUPP; return -1;#endif#if defined(BLKGETSIZE64) case BLKGETSIZE64: ntfs_log_debug("BLKGETSIZE64 detected.\n"); if (fd->part_length >= 0) { *(s64 *)argp = fd->part_length; return 0; } errno = EOPNOTSUPP; return -1;#endif#ifdef HDIO_GETGEO case HDIO_GETGEO: ntfs_log_debug("HDIO_GETGEO detected.\n"); return ntfs_win32_hdio_getgeo(dev, (struct hd_geometry *)argp);#endif#ifdef BLKSSZGET case BLKSSZGET: ntfs_log_debug("BLKSSZGET detected.\n"); return ntfs_win32_blksszget(dev, (int *)argp);#endif#ifdef BLKBSZSET case BLKBSZSET: ntfs_log_debug("BLKBSZSET detected.\n"); /* Nothing to do on Windows. */ return 0;#endif default: ntfs_log_debug("unimplemented ioctl %d.\n", request); errno = EOPNOTSUPP; return -1; }}static s64 ntfs_device_win32_pread(struct ntfs_device *dev, void *b, s64 count, s64 offset){ return ntfs_pread(dev, offset, count, b);}static s64 ntfs_device_win32_pwrite(struct ntfs_device *dev, const void *b, s64 count, s64 offset){ return ntfs_pwrite(dev, offset, count, b);}struct ntfs_device_operations ntfs_device_win32_io_ops = { .open = ntfs_device_win32_open, .close = ntfs_device_win32_close, .seek = ntfs_device_win32_seek, .read = ntfs_device_win32_read, .write = ntfs_device_win32_write, .pread = ntfs_device_win32_pread, .pwrite = ntfs_device_win32_pwrite, .sync = ntfs_device_win32_sync, .stat = ntfs_device_win32_stat, .ioctl = ntfs_device_win32_ioctl};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -