summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/smbd/fileio.c54
1 files changed, 50 insertions, 4 deletions
diff --git a/source3/smbd/fileio.c b/source3/smbd/fileio.c
index 92757f7052..f9fcc1be50 100644
--- a/source3/smbd/fileio.c
+++ b/source3/smbd/fileio.c
@@ -653,10 +653,31 @@ nonop=%u allocated=%u active=%u direct=%u perfect=%u readhits=%u\n",
*/
flush_write_cache(fsp, WRITE_FLUSH);
- wcp->offset = wcp->file_size;
- wcp->data_size = pos - wcp->file_size + 1;
- memset(wcp->data, '\0', wcp->data_size);
- memcpy(wcp->data + wcp->data_size-1, data, 1);
+
+ if (data[0] == '\0') {
+ /*
+ * This is a 1-byte write of a 0
+ * beyond the EOF, the typical
+ * file-extending (and allocating, but
+ * we're using the write cache here)
+ * write done by Windows. We just have
+ * to ftruncate the file and rely on
+ * posix semantics to return zeros for
+ * non-written file data that is
+ * within the file length.
+ *
+ * We have to cheat the offset to make
+ * wcp_file_size_change do the right
+ * thing with the ftruncate call.
+ */
+ wcp->offset = pos + 1;
+ wcp->data_size = 0;
+ } else {
+ wcp->offset = wcp->file_size;
+ wcp->data_size = pos - wcp->file_size + 1;
+ memset(wcp->data, '\0', wcp->data_size);
+ memcpy(wcp->data + wcp->data_size-1, data, 1);
+ }
/*
* Update the file size if changed.
@@ -799,6 +820,31 @@ n = %u, wcp->offset=%.0f, wcp->data_size=%u\n",
if ((wcp->data_size == 0)
&& (pos > wcp->file_size)
+ && (n == 1)
+ && (data[0] == '\0')) {
+ /*
+ * This is a 1-byte write of a 0 beyond the
+ * EOF, the typical file-extending (and
+ * allocating, but we're using the write cache
+ * here) write done by Windows. We just have
+ * to ftruncate the file and rely on posix
+ * semantics to return zeros for non-written
+ * file data that is within the file length.
+ *
+ * We have to cheat the offset to make
+ * wcp_file_size_change do the right thing
+ * with the ftruncate call.
+ */
+ wcp->offset = pos+1;
+ wcp->data_size = 0;
+ if (wcp_file_size_change(fsp) == -1) {
+ return -1;
+ }
+ return 1;
+ }
+
+ if ((wcp->data_size == 0)
+ && (pos > wcp->file_size)
&& (pos + n <= wcp->file_size + wcp->alloc_size)) {
/*
* This is a write completely beyond the