static NTSTATUS fsctl_qar_seek_fill(TALLOC_CTX *mem_ctx, struct files_struct *fsp, off_t curr_off, off_t max_off, DATA_BLOB *qar_array_blob) { NTSTATUS status = NT_STATUS_NOT_SUPPORTED; #ifdef HAVE_LSEEK_HOLE_DATA while (curr_off <= max_off) { off_t data_off; off_t hole_off; struct file_alloced_range_buf qar_buf; /* seek next data */ data_off = SMB_VFS_LSEEK(fsp, curr_off, SEEK_DATA); if ((data_off == -1) && (errno == ENXIO)) { /* no data from curr_off to EOF */ break; } else if (data_off == -1) { status = map_nt_error_from_unix_common(errno); DEBUG(1, ("lseek data failed: %s\n", strerror(errno))); return status; } if (data_off > max_off) { /* found something, but passed range of interest */ break; } hole_off = SMB_VFS_LSEEK(fsp, data_off, SEEK_HOLE); if (hole_off == -1) { status = map_nt_error_from_unix_common(errno); DEBUG(1, ("lseek hole failed: %s\n", strerror(errno))); return status; } if (hole_off <= data_off) { DEBUG(1, ("lseek inconsistent: hole %lu at or before " "data %lu\n", (unsigned long)hole_off, (unsigned long)data_off)); return NT_STATUS_INTERNAL_ERROR; } qar_buf.file_off = data_off; /* + 1 to convert maximum offset to length */ qar_buf.len = MIN(hole_off, max_off + 1) - data_off; status = fsctl_qar_buf_push(mem_ctx, &qar_buf, qar_array_blob); if (!NT_STATUS_IS_OK(status)) { return NT_STATUS_NO_MEMORY; } curr_off = hole_off; } status = NT_STATUS_OK; #endif return status; }
static int strict_allocate_ftruncate(vfs_handle_struct *handle, files_struct *fsp, int fd, SMB_OFF_T len) { SMB_STRUCT_STAT st; SMB_OFF_T currpos = SMB_VFS_LSEEK(fsp, fd, 0, SEEK_CUR); unsigned char zero_space[4096]; SMB_OFF_T space_to_write; if (currpos == -1) return -1; if (SMB_VFS_FSTAT(fsp, fd, &st) == -1) return -1; space_to_write = len - st.st_size; #ifdef S_ISFIFO if (S_ISFIFO(st.st_mode)) return 0; #endif if (st.st_size == len) return 0; /* Shrink - just ftruncate. */ if (st.st_size > len) return sys_ftruncate(fd, len); /* Write out the real space on disk. */ if (SMB_VFS_LSEEK(fsp, fd, st.st_size, SEEK_SET) != st.st_size) return -1; space_to_write = len - st.st_size; memset(zero_space, '\0', sizeof(zero_space)); while ( space_to_write > 0) { SMB_OFF_T retlen; SMB_OFF_T current_len_to_write = MIN(sizeof(zero_space),space_to_write); retlen = SMB_VFS_WRITE(fsp,fsp->fh->fd,(char *)zero_space,current_len_to_write); if (retlen <= 0) return -1; space_to_write -= retlen; } /* Seek to where we were */ if (SMB_VFS_LSEEK(fsp, fd, currpos, SEEK_SET) != currpos) return -1; return 0; }
static NTSTATUS cmd_lseek(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, const char **argv) { int fd, offset, whence; SMB_OFF_T pos; if (argc != 4) { printf("Usage: lseek <fd> <offset> <whence>\n...where whence is 1 => SEEK_SET, 2 => SEEK_CUR, 3 => SEEK_END\n"); return NT_STATUS_OK; } fd = atoi(argv[1]); offset = atoi(argv[2]); whence = atoi(argv[3]); switch (whence) { case 1: whence = SEEK_SET; break; case 2: whence = SEEK_CUR; break; default: whence = SEEK_END; } pos = SMB_VFS_LSEEK(vfs->files[fd], fd, offset, whence); if (pos == (SMB_OFF_T)-1) { printf("lseek: error=%d (%s)\n", errno, strerror(errno)); return NT_STATUS_UNSUCCESSFUL; } printf("lseek: ok\n"); return NT_STATUS_OK; }
static ssize_t cprime_read( vfs_handle_struct * handle, files_struct * fsp, int fd, void * data, size_t count) { SMB_OFF_T offset; offset = SMB_VFS_LSEEK(fsp, fd, 0, SEEK_CUR); if (offset >= 0 && g_readbuf) { prime_cache(handle, fsp, fd, offset, count); SMB_VFS_LSEEK(fsp, fd, offset, SEEK_SET); } return SMB_VFS_NEXT_READ(handle, fsp, fd, data, count); }
ssize_t vfswrap_pread(vfs_handle_struct *handle, files_struct *fsp, int fd, void *data, size_t n, SMB_OFF_T offset) { ssize_t result; #if defined(HAVE_PREAD) || defined(HAVE_PREAD64) START_PROFILE_BYTES(syscall_pread, n); result = sys_pread(fd, data, n, offset); END_PROFILE(syscall_pread); if (result == -1 && errno == ESPIPE) { /* Maintain the fiction that pipes can be seeked (sought?) on. */ result = SMB_VFS_READ(fsp, fd, data, n); fsp->fh->pos = 0; } #else /* HAVE_PREAD */ SMB_OFF_T curr; int lerrno; curr = SMB_VFS_LSEEK(fsp, fd, 0, SEEK_CUR); if (curr == -1 && errno == ESPIPE) { /* Maintain the fiction that pipes can be seeked (sought?) on. */ result = SMB_VFS_READ(fsp, fd, data, n); fsp->fh->pos = 0; return result; } if (SMB_VFS_LSEEK(fsp, fd, offset, SEEK_SET) == -1) { return -1; } errno = 0; result = SMB_VFS_READ(fsp, fd, data, n); lerrno = errno; SMB_VFS_LSEEK(fsp, fd, curr, SEEK_SET); errno = lerrno; #endif /* HAVE_PREAD */ return result; }
ssize_t vfswrap_pwrite(vfs_handle_struct *handle, files_struct *fsp, int fd, const void *data, size_t n, SMB_OFF_T offset) { ssize_t result; #if defined(HAVE_PWRITE) || defined(HAVE_PRWITE64) START_PROFILE_BYTES(syscall_pwrite, n); result = sys_pwrite(fd, data, n, offset); END_PROFILE(syscall_pwrite); if (result == -1 && errno == ESPIPE) { /* Maintain the fiction that pipes can be sought on. */ result = SMB_VFS_WRITE(fsp, fd, data, n); } #else /* HAVE_PWRITE */ SMB_OFF_T curr; int lerrno; curr = SMB_VFS_LSEEK(fsp, fd, 0, SEEK_CUR); if (curr == -1) { return -1; } if (SMB_VFS_LSEEK(fsp, fd, offset, SEEK_SET) == -1) { return -1; } result = SMB_VFS_WRITE(fsp, fd, data, n); lerrno = errno; SMB_VFS_LSEEK(fsp, fd, curr, SEEK_SET); errno = lerrno; #endif /* HAVE_PWRITE */ return result; }
int vfswrap_ftruncate(vfs_handle_struct *handle, files_struct *fsp, int fd, SMB_OFF_T len) { int result = -1; SMB_STRUCT_STAT st; char c = 0; SMB_OFF_T currpos; START_PROFILE(syscall_ftruncate); if (lp_strict_allocate(SNUM(fsp->conn))) { result = strict_allocate_ftruncate(handle, fsp, fd, len); END_PROFILE(syscall_ftruncate); return result; } /* we used to just check HAVE_FTRUNCATE_EXTEND and only use sys_ftruncate if the system supports it. Then I discovered that you can have some filesystems that support ftruncate expansion and some that don't! On Linux fat can't do ftruncate extend but ext2 can. */ result = sys_ftruncate(fd, len); if (result == 0) goto done; /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot extend a file with ftruncate. Provide alternate implementation for this */ currpos = SMB_VFS_LSEEK(fsp, fd, 0, SEEK_CUR); if (currpos == -1) { goto done; } /* Do an fstat to see if the file is longer than the requested size in which case the ftruncate above should have succeeded or shorter, in which case seek to len - 1 and write 1 byte of zero */ if (SMB_VFS_FSTAT(fsp, fd, &st) == -1) { goto done; } #ifdef S_ISFIFO if (S_ISFIFO(st.st_mode)) { result = 0; goto done; } #endif if (st.st_size == len) { result = 0; goto done; } if (st.st_size > len) { /* the sys_ftruncate should have worked */ goto done; } if (SMB_VFS_LSEEK(fsp, fd, len-1, SEEK_SET) != len -1) goto done; if (SMB_VFS_WRITE(fsp, fd, &c, 1)!=1) goto done; /* Seek to where we were */ if (SMB_VFS_LSEEK(fsp, fd, currpos, SEEK_SET) != currpos) goto done; result = 0; done: END_PROFILE(syscall_ftruncate); return result; }