1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-13 13:18:06 +03:00

Fix "strict allocate" to write the data out on ftruncate with extend.

Jeremy.
This commit is contained in:
Jeremy Allison 0001-01-01 00:00:00 +00:00
parent 3c887d9021
commit 48fc42c710

View File

@ -476,6 +476,62 @@ int vfswrap_utime(connection_struct *conn, const char *path, struct utimbuf *tim
return result;
}
/*********************************************************************
A version of ftruncate that will write the space on disk if strict
allocate is set.
**********************************************************************/
static int strict_allocate_ftruncate(files_struct *fsp, int fd, SMB_OFF_T len)
{
struct vfs_ops *vfs_ops = &fsp->conn->vfs_ops;
SMB_STRUCT_STAT st;
SMB_OFF_T currpos = vfs_ops->lseek(fsp, fd, 0, SEEK_CUR);
unsigned char zero_space[4096];
SMB_OFF_T space_to_write = len - st.st_size;
if (currpos == -1)
return -1;
if (vfs_ops->fstat(fsp, fd, &st) == -1)
return -1;
#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 (vfs_ops->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 = vfs_ops->write(fsp,fsp->fd,(char *)zero_space,current_len_to_write);
if (retlen <= 0)
return -1;
space_to_write -= retlen;
}
/* Seek to where we were */
if (vfs_ops->lseek(fsp, fd, currpos, SEEK_SET) != currpos)
return -1;
return 0;
}
int vfswrap_ftruncate(files_struct *fsp, int fd, SMB_OFF_T len)
{
int result = -1;
@ -486,13 +542,21 @@ int vfswrap_ftruncate(files_struct *fsp, int fd, SMB_OFF_T len)
START_PROFILE(syscall_ftruncate);
if (lp_strict_allocate(SNUM(fsp->conn))) {
result = strict_allocate_ftruncate(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;
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
@ -506,7 +570,7 @@ int vfswrap_ftruncate(files_struct *fsp, int fd, SMB_OFF_T len)
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 (vfs_ops->fstat(fsp, fd, &st) < 0) {
if (vfs_ops->fstat(fsp, fd, &st) == -1) {
goto done;
}
@ -527,19 +591,17 @@ int vfswrap_ftruncate(files_struct *fsp, int fd, SMB_OFF_T len)
goto done;
}
if (vfs_ops->lseek(fsp, fd, len-1, SEEK_SET) != len -1) {
if (vfs_ops->lseek(fsp, fd, len-1, SEEK_SET) != len -1)
goto done;
}
if (vfs_ops->write(fsp, fd, &c, 1)!=1) {
if (vfs_ops->write(fsp, fd, &c, 1)!=1)
goto done;
}
/* Seek to where we were */
if (vfs_ops->lseek(fsp, fd, currpos, SEEK_SET) != currpos) {
if (vfs_ops->lseek(fsp, fd, currpos, SEEK_SET) != currpos)
goto done;
}
result = 0;
done:
END_PROFILE(syscall_ftruncate);