r6841: Attempt to fix buf #2681. With "strict allocate = yes" we now zero
authorJeremy Allison <jra@samba.org>
Tue, 17 May 2005 01:04:51 +0000 (01:04 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 15:56:56 +0000 (10:56 -0500)
fill when a file is extended. Should catch disk full errors on write
from MS-Office.
Jeremy.
(This used to be commit 858824f37be443320487a8e28ec8fa172cdf5a18)

source3/smbd/fileio.c
source3/smbd/vfs.c

index dbf1e5a789d0026c473b9c79fb49d12c15d97bca..977988fde465eb46fa505ea85798f7a35628e397 100644 (file)
@@ -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);
        }
 
index ade28f9bee9d721d137b0bfa7858b7117ea2697e..b09935eaa993fa3cde641c49298d58f447ab02d5 100644 (file)
@@ -588,6 +588,72 @@ int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
        return ret;
 }
 
+/****************************************************************************
+ 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.
 ****************************************************************************/