diff options
-rw-r--r-- | source3/configure.in | 2 | ||||
-rw-r--r-- | source3/include/proto.h | 1 | ||||
-rw-r--r-- | source3/lib/system.c | 14 | ||||
-rw-r--r-- | source3/modules/vfs_default.c | 25 |
4 files changed, 37 insertions, 5 deletions
diff --git a/source3/configure.in b/source3/configure.in index de30f143a9..fb1d6313e1 100644 --- a/source3/configure.in +++ b/source3/configure.in @@ -1057,7 +1057,7 @@ AC_CHECK_FUNCS(setsid glob strpbrk crypt16 getauthuid) AC_CHECK_FUNCS(sigprocmask sigblock sigaction sigset innetgr setnetgrent getnetgrent endnetgrent) AC_CHECK_FUNCS(initgroups select poll rdchk getgrnam getgrent pathconf) AC_CHECK_FUNCS(setpriv setgidx setuidx setgroups sysconf stat64 fstat64) -AC_CHECK_FUNCS(lstat64 fopen64 atexit grantpt lseek64 ftruncate64) +AC_CHECK_FUNCS(lstat64 fopen64 atexit grantpt lseek64 ftruncate64 posix_fallocate posix_fallocate64) AC_CHECK_FUNCS(fseek64 fseeko64 ftell64 ftello64 setluid getpwanam) AC_CHECK_FUNCS(opendir64 readdir64 seekdir64 telldir64 rewinddir64 closedir64) AC_CHECK_FUNCS(getpwent_r) diff --git a/source3/include/proto.h b/source3/include/proto.h index f0ce7a32f8..7013709fbb 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -932,6 +932,7 @@ int sys_fstat(int fd, SMB_STRUCT_STAT *sbuf, int sys_lstat(const char *fname,SMB_STRUCT_STAT *sbuf, bool fake_dir_create_times); int sys_ftruncate(int fd, SMB_OFF_T offset); +int sys_posix_fallocate(int fd, SMB_OFF_T offset, SMB_OFF_T len); SMB_OFF_T sys_lseek(int fd, SMB_OFF_T offset, int whence); int sys_fseek(FILE *fp, SMB_OFF_T offset, int whence); SMB_OFF_T sys_ftell(FILE *fp); diff --git a/source3/lib/system.c b/source3/lib/system.c index 86802d0c8d..b18358d8b2 100644 --- a/source3/lib/system.c +++ b/source3/lib/system.c @@ -610,6 +610,20 @@ int sys_lstat(const char *fname,SMB_STRUCT_STAT *sbuf, } /******************************************************************* + An posix_fallocate() wrapper that will deal with 64 bit filesizes. +********************************************************************/ +#if defined(HAVE_POSIX_FALLOCATE64) || defined(HAVE_POSIX_FALLOCATE) +int sys_posix_fallocate(int fd, SMB_OFF_T offset, SMB_OFF_T len) +{ +#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_POSIX_FALLOCATE64) + return posix_fallocate64(fd, offset, len); +#else + return posix_fallocate(fd, offset, len); +#endif +} +#endif + +/******************************************************************* An ftruncate() wrapper that will deal with 64 bit filesizes. ********************************************************************/ diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c index 9abf792769..da775d160b 100644 --- a/source3/modules/vfs_default.c +++ b/source3/modules/vfs_default.c @@ -922,8 +922,6 @@ static int strict_allocate_ftruncate(vfs_handle_struct *handle, files_struct *fs if (SMB_VFS_FSTAT(fsp, &st) == -1) return -1; - space_to_write = len - st.st_ex_size; - #ifdef S_ISFIFO if (S_ISFIFO(st.st_ex_mode)) return 0; @@ -936,7 +934,28 @@ static int strict_allocate_ftruncate(vfs_handle_struct *handle, files_struct *fs if (st.st_ex_size > len) return sys_ftruncate(fsp->fh->fd, len); + /* for allocation try posix_fallocate first. This can fail on some + platforms e.g. when the filesystem doesn't support it and no + emulation is being done by the libc (like on AIX with JFS1). In that + case we do our own emulation. posix_fallocate implementations can + return ENOTSUP or EINVAL in cases like that. */ +#if defined(HAVE_POSIX_FALLOCATE) + { + int ret = sys_posix_fallocate(fsp->fh->fd, 0, len); + if (ret == ENOSPC) { + errno = ENOSPC; + return -1; + } + if (ret == 0) { + return 0; + } + DEBUG(10,("strict_allocate_ftruncate: sys_posix_fallocate " + "failed with error %d. " + "Falling back to slow manual allocation\n", ret)); + } +#endif /* available disk space is enough or not? */ + space_to_write = len - st.st_ex_size; if (lp_strict_allocate(SNUM(fsp->conn))){ uint64_t space_avail; uint64_t bsize,dfree,dsize; @@ -956,8 +975,6 @@ static int strict_allocate_ftruncate(vfs_handle_struct *handle, files_struct *fs if (SMB_VFS_LSEEK(fsp, st.st_ex_size, SEEK_SET) != st.st_ex_size) return -1; - space_to_write = len - st.st_ex_size; - memset(zero_space, '\0', sizeof(zero_space)); while ( space_to_write > 0) { SMB_OFF_T retlen; |