*/
if(read_from_write_cache(fsp, data, pos, n)) {
- fsp->pos = pos + n;
- fsp->position_information = fsp->pos;
+ fsp->fh->pos = pos + n;
+ fsp->fh->position_information = fsp->fh->pos;
return n;
}
flush_write_cache(fsp, READ_FLUSH);
- fsp->pos = pos;
+ fsp->fh->pos = pos;
if (n > 0) {
#ifdef DMF_FIX
int numretries = 3;
tryagain:
- readret = SMB_VFS_PREAD(fsp,fsp->fd,data,n,pos);
+ readret = SMB_VFS_PREAD(fsp,fsp->fh->fd,data,n,pos);
if (readret == -1) {
if ((errno == EAGAIN) && numretries) {
return -1;
}
#else /* NO DMF fix. */
- readret = SMB_VFS_PREAD(fsp,fsp->fd,data,n,pos);
+ readret = SMB_VFS_PREAD(fsp,fsp->fh->fd,data,n,pos);
if (readret == -1) {
return -1;
DEBUG(10,("read_file (%s): pos = %.0f, size = %lu, returned %lu\n",
fsp->fsp_name, (double)pos, (unsigned long)n, (long)ret ));
- fsp->pos += ret;
- fsp->position_information = fsp->pos;
+ fsp->fh->pos += ret;
+ fsp->fh->position_information = fsp->fh->pos;
return(ret);
}
*Really* write to a file.
****************************************************************************/
-static ssize_t real_write_file(files_struct *fsp,char *data,SMB_OFF_T pos, size_t n)
+static ssize_t real_write_file(files_struct *fsp,const char *data, SMB_OFF_T pos, size_t n)
{
ssize_t ret;
if (pos == -1) {
ret = vfs_write_data(fsp, data, n);
} else {
- fsp->pos = pos;
+ fsp->fh->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);
}
fsp->fsp_name, (double)pos, (unsigned long)n, (long)ret ));
if (ret != -1) {
- fsp->pos += ret;
+ fsp->fh->pos += ret;
/*
* It turns out that setting the last write time from a Windows
write_cache *wcp = fsp->wcp;
wcp->file_size = wcp->offset + wcp->data_size;
- ret = SMB_VFS_FTRUNCATE(fsp, fsp->fd, wcp->file_size);
+ ret = SMB_VFS_FTRUNCATE(fsp, fsp->fh->fd, wcp->file_size);
if (ret == -1) {
DEBUG(0,("wcp_file_size_change (%s): ftruncate of size %.0f error %s\n",
fsp->fsp_name, (double)wcp->file_size, strerror(errno) ));
Write to a file.
****************************************************************************/
-ssize_t write_file(files_struct *fsp, char *data, SMB_OFF_T pos, size_t n)
+ssize_t write_file(files_struct *fsp, const char *data, SMB_OFF_T pos, size_t n)
{
write_cache *wcp = fsp->wcp;
ssize_t total_written = 0;
return -1;
}
- return print_job_write(SNUM(fsp->conn), jobid, data, n);
+ return print_job_write(SNUM(fsp->conn), jobid, data, pos, n);
}
if (!fsp->can_write) {
errno = EPERM;
- return(0);
+ return -1;
}
if (!fsp->modified) {
SMB_STRUCT_STAT st;
fsp->modified = True;
- if (SMB_VFS_FSTAT(fsp,fsp->fd,&st) == 0) {
+ if (SMB_VFS_FSTAT(fsp,fsp->fh->fd,&st) == 0) {
int dosmode = dos_mode(fsp->conn,fsp->fsp_name,&st);
if ((lp_store_dos_attributes(SNUM(fsp->conn)) || MAP_ARCHIVE(fsp->conn)) && !IS_DOS_ARCHIVE(dosmode)) {
file_set_dosmode(fsp->conn,fsp->fsp_name,dosmode | aARCH,&st, False);
}
DEBUG(9,("write_file (%s)(fd=%d pos=%.0f size=%u) wcp->offset=%.0f wcp->data_size=%u\n",
- fsp->fsp_name, fsp->fd, (double)pos, (unsigned int)n, (double)wcp->offset, (unsigned int)wcp->data_size));
+ fsp->fsp_name, fsp->fh->fd, (double)pos, (unsigned int)n, (double)wcp->offset, (unsigned int)wcp->data_size));
- fsp->pos = pos + n;
+ fsp->fh->pos = pos + n;
/*
* If we have active cache and it isn't contiguous then we flush.
write_path = 3;
+ } else if ( (pos >= wcp->file_size) &&
+ (n == 1) &&
+ (pos < wcp->offset + 2*wcp->alloc_size) &&
+ (wcp->file_size == wcp->offset + wcp->data_size)) {
+
+ /*
+ +---------------+
+ | Cached data |
+ +---------------+
+
+ +--------+
+ | 1 Byte |
+ +--------+
+
+ MS-Office seems to do this a lot to determine if there's enough
+ space on the filesystem to write a new file.
+ */
+
+ SMB_BIG_UINT new_start = wcp->offset + wcp->data_size;
+
+ flush_write_cache(fsp, WRITE_FLUSH);
+ wcp->offset = new_start;
+ wcp->data_size = pos - new_start + 1;
+ memset(wcp->data, '\0', wcp->data_size);
+ memcpy(wcp->data + wcp->data_size-1, data, 1);
+
+ /*
+ * Update the file size if changed.
+ */
+
+ if (wcp->offset + wcp->data_size > wcp->file_size) {
+ if (wcp_file_size_change(fsp) == -1) {
+ return -1;
+ }
+ }
+
+ return n;
+
} else {
/* ASCII art..... JRA.
*/
DEBUG(9,("write_file: non cacheable write : fd = %d, pos = %.0f, len = %u, current cache pos = %.0f \
-len = %u\n",fsp->fd, (double)pos, (unsigned int)n, (double)wcp->offset, (unsigned int)wcp->data_size ));
+len = %u\n",fsp->fh->fd, (double)pos, (unsigned int)n, (double)wcp->offset, (unsigned int)wcp->data_size ));
/*
* If write would fit in the cache, and is larger than
if ((pos <= wcp->offset) &&
(pos + n >= wcp->offset + wcp->data_size) ) {
DEBUG(9,("write_file: discarding overwritten write \
-cache: fd = %d, off=%.0f, size=%u\n", fsp->fd, (double)wcp->offset, (unsigned int)wcp->data_size ));
+cache: fd = %d, off=%.0f, size=%u\n", fsp->fh->fd, (double)wcp->offset, (unsigned int)wcp->data_size ));
wcp->data_size = 0;
}
if (cache_flush_needed) {
DEBUG(3,("WRITE_FLUSH:%d: due to noncontinuous write: fd = %d, size = %.0f, pos = %.0f, \
n = %u, wcp->offset=%.0f, wcp->data_size=%u\n",
- write_path, fsp->fd, (double)wcp->file_size, (double)pos, (unsigned int)n,
+ write_path, fsp->fh->fd, (double)wcp->file_size, (double)pos, (unsigned int)n,
(double)wcp->offset, (unsigned int)wcp->data_size ));
flush_write_cache(fsp, WRITE_FLUSH);
wcp->offset = 0;
wcp->alloc_size = alloc_size;
wcp->data_size = 0;
- if((wcp->data = SMB_MALLOC(wcp->alloc_size)) == NULL) {
+ if((wcp->data = (char *)SMB_MALLOC(wcp->alloc_size)) == NULL) {
DEBUG(0,("setup_write_cache: malloc fail for buffer size %u.\n",
(unsigned int)wcp->alloc_size ));
SAFE_FREE(wcp);
DO_PROFILE_DEC_INC(writecache_num_write_caches,writecache_flushed_writes[reason]);
DEBUG(9,("flushing write cache: fd = %d, off=%.0f, size=%u\n",
- fsp->fd, (double)wcp->offset, (unsigned int)data_size));
+ fsp->fh->fd, (double)wcp->offset, (unsigned int)data_size));
#ifdef WITH_PROFILE
if(data_size == wcp->alloc_size) {
sync a file
********************************************************************/
-void sync_file(connection_struct *conn, files_struct *fsp)
+void sync_file(connection_struct *conn, files_struct *fsp, BOOL write_through)
{
- if(lp_strict_sync(SNUM(conn)) && fsp->fd != -1) {
+ if (fsp->fh->fd == -1)
+ return;
+
+ if (lp_strict_sync(SNUM(conn)) &&
+ (lp_syncalways(SNUM(conn)) || write_through)) {
flush_write_cache(fsp, SYNC_FLUSH);
- SMB_VFS_FSYNC(fsp,fsp->fd);
+ SMB_VFS_FSYNC(fsp,fsp->fh->fd);
}
}
-
/************************************************************
Perform a stat whether a valid fd or not.
************************************************************/
int fsp_stat(files_struct *fsp, SMB_STRUCT_STAT *pst)
{
- if (fsp->fd == -1) {
+ if (fsp->fh->fd == -1) {
return SMB_VFS_STAT(fsp->conn, fsp->fsp_name, pst);
} else {
- return SMB_VFS_FSTAT(fsp,fsp->fd, pst);
+ return SMB_VFS_FSTAT(fsp,fsp->fh->fd, pst);
}
}