diff options
author | Jeremy Allison <jra@samba.org> | 2005-05-17 01:04:51 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 10:56:56 -0500 |
commit | 8a1756006a1abf8ceb22fff889c94b3d28d19c20 (patch) | |
tree | 93d2ae1d18347cb8a50598837c8149612296c561 | |
parent | 6019df0858aa33e81167eeeade7f7264cd719cef (diff) | |
download | samba-8a1756006a1abf8ceb22fff889c94b3d28d19c20.tar.gz samba-8a1756006a1abf8ceb22fff889c94b3d28d19c20.tar.bz2 samba-8a1756006a1abf8ceb22fff889c94b3d28d19c20.zip |
r6841: Attempt to fix buf #2681. With "strict allocate = yes" we now zero
fill when a file is extended. Should catch disk full errors on write
from MS-Office.
Jeremy.
(This used to be commit 858824f37be443320487a8e28ec8fa172cdf5a18)
-rw-r--r-- | source3/smbd/fileio.c | 5 | ||||
-rw-r--r-- | source3/smbd/vfs.c | 66 |
2 files changed, 71 insertions, 0 deletions
diff --git a/source3/smbd/fileio.c b/source3/smbd/fileio.c index dbf1e5a789..977988fde4 100644 --- a/source3/smbd/fileio.c +++ b/source3/smbd/fileio.c @@ -125,6 +125,11 @@ static ssize_t real_write_file(files_struct *fsp,char *data,SMB_OFF_T pos, size_ ret = vfs_write_data(fsp, data, n); } else { fsp->pos = pos; + if (pos && lp_strict_allocate(SNUM(fsp->conn))) { + if (vfs_fill_sparse(fsp, pos) == -1) { + return -1; + } + } ret = vfs_pwrite_data(fsp, data, n, pos); } diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c index ade28f9bee..b09935eaa9 100644 --- a/source3/smbd/vfs.c +++ b/source3/smbd/vfs.c @@ -589,6 +589,72 @@ int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len) } /**************************************************************************** + A vfs fill sparse call. + Writes zeros from the end of file to len, if len is greater than EOF. + Used only by strict_sync. + Returns 0 on success, -1 on failure. +****************************************************************************/ + +static char *sparse_buf; +#define SPARSE_BUF_WRITE_SIZE (32*1024) + +int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len) +{ + int ret; + SMB_STRUCT_STAT st; + SMB_OFF_T offset; + size_t total; + size_t num_to_write; + ssize_t pwrite_ret; + + release_level_2_oplocks_on_change(fsp); + ret = SMB_VFS_FSTAT(fsp,fsp->fd,&st); + if (ret == -1) { + return ret; + } + + if (len <= st.st_size) { + return 0; + } + + DEBUG(10,("vfs_fill_sparse: write zeros in file %s from len %.0f to len %.0f (%.0f bytes)\n", + fsp->fsp_name, (double)st.st_size, (double)len, (double)(len - st.st_size))); + + flush_write_cache(fsp, SIZECHANGE_FLUSH); + + if (!sparse_buf) { + sparse_buf = SMB_CALLOC_ARRAY(char, SPARSE_BUF_WRITE_SIZE); + if (!sparse_buf) { + errno = ENOMEM; + return -1; + } + } + + offset = st.st_size; + num_to_write = len - st.st_size; + total = 0; + + while (total < num_to_write) { + size_t curr_write_size = MIN(SPARSE_BUF_WRITE_SIZE, (num_to_write - total)); + + pwrite_ret = SMB_VFS_PWRITE(fsp, fsp->fd, sparse_buf, curr_write_size, offset + total); + if (pwrite_ret == -1) { + DEBUG(10,("vfs_fill_sparse: SMB_VFS_PWRITE for file %s failed with error %s\n", + fsp->fsp_name, strerror(errno) )); + return -1; + } + if (pwrite_ret == 0) { + return 0; + } + + total += pwrite_ret; + } + + set_filelen_write_cache(fsp, len); + return 0; +} + +/**************************************************************************** Transfer some data (n bytes) between two file_struct's. ****************************************************************************/ |