#ifdef DMF_FIX
int numretries = 3;
tryagain:
- readret = SMB_VFS_PREAD(fsp,fsp->fh->fd,data,n,pos);
+ readret = SMB_VFS_PREAD(fsp,data,n,pos);
if (readret == -1) {
if ((errno == EAGAIN) && numretries) {
return -1;
}
#else /* NO DMF fix. */
- readret = SMB_VFS_PREAD(fsp,fsp->fh->fd,data,n,pos);
+ readret = SMB_VFS_PREAD(fsp,data,n,pos);
if (readret == -1) {
return -1;
*Really* write to a file.
****************************************************************************/
-static ssize_t real_write_file(files_struct *fsp,const char *data, SMB_OFF_T pos, size_t n)
+static ssize_t real_write_file(struct smb_request *req,
+ 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);
+ ret = vfs_write_data(req, fsp, data, n);
} else {
fsp->fh->pos = pos;
if (pos && lp_strict_allocate(SNUM(fsp->conn))) {
return -1;
}
}
- ret = vfs_pwrite_data(fsp, data, n, pos);
+ ret = vfs_pwrite_data(req, fsp, data, n, pos);
}
DEBUG(10,("real_write_file (%s): pos = %.0f, size = %lu, returned %ld\n",
if (ret != -1) {
fsp->fh->pos += ret;
- /*
- * It turns out that setting the last write time from a Windows
- * client stops any subsequent writes from updating the write time.
- * Doing this after the write gives a race condition here where
- * a stat may see the changed write time before we reset it here,
- * but it's cheaper than having to store the write time in shared
- * memory and look it up using dev/inode across all running smbd's.
- * The 99% solution will hopefully be good enough in this case. JRA.
- */
-
- if (!null_timespec(fsp->pending_modtime)) {
- set_filetime(fsp->conn, fsp->fsp_name, fsp->pending_modtime);
-
- /* If we didn't get the "set modtime" call ourselves, we must
- store the last write time to restore on close. JRA. */
- if (!fsp->pending_modtime_owner) {
- fsp->last_write_time = timespec_current();
- }
- }
-
/* Yes - this is correct - writes don't update this. JRA. */
/* Found by Samba4 tests. */
#if 0
write_cache *wcp = fsp->wcp;
wcp->file_size = wcp->offset + wcp->data_size;
- ret = SMB_VFS_FTRUNCATE(fsp, fsp->fh->fd, wcp->file_size);
+ ret = SMB_VFS_FTRUNCATE(fsp, 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) ));
return ret;
}
+static void update_write_time_handler(struct event_context *ctx,
+ struct timed_event *te,
+ const struct timeval *now,
+ void *private_data)
+{
+ files_struct *fsp = (files_struct *)private_data;
+
+ /* Remove the timed event handler. */
+ TALLOC_FREE(fsp->update_write_time_event);
+ DEBUG(5, ("Update write time on %s\n", fsp->fsp_name));
+
+ /* change the write time if not already changed by someone else */
+ update_write_time(fsp);
+}
+
+/*********************************************************
+ Schedule a write time update for WRITE_TIME_UPDATE_USEC_DELAY
+ in the future.
+*********************************************************/
+
+void trigger_write_time_update(struct files_struct *fsp)
+{
+ int delay;
+
+ if (fsp->write_time_forced) {
+ /* No point - "sticky" write times
+ * in effect.
+ */
+ return;
+ }
+
+ if (fsp->update_write_time_triggered) {
+ /*
+ * We only update the write time
+ * on the first write. After that
+ * no other writes affect this.
+ */
+ return;
+ }
+ fsp->update_write_time_triggered = true;
+
+ delay = lp_parm_int(SNUM(fsp->conn),
+ "smbd", "writetimeupdatedelay",
+ WRITE_TIME_UPDATE_USEC_DELAY);
+
+ /* trigger the update 2 seconds later */
+ fsp->update_write_time_on_close = true;
+ fsp->update_write_time_event =
+ event_add_timed(smbd_event_context(), NULL,
+ timeval_current_ofs(0, delay),
+ "update_write_time_handler",
+ update_write_time_handler, fsp);
+}
+
+void trigger_write_time_update_immediate(struct files_struct *fsp)
+{
+ if (fsp->write_time_forced) {
+ /*
+ * No point - "sticky" write times
+ * in effect.
+ */
+ return;
+ }
+
+ TALLOC_FREE(fsp->update_write_time_event);
+ DEBUG(5, ("Update write time immediate on %s\n", fsp->fsp_name));
+
+ fsp->update_write_time_triggered = true;
+
+ fsp->update_write_time_on_close = false;
+ update_write_time(fsp);
+}
+
/****************************************************************************
Write to a file.
****************************************************************************/
-ssize_t write_file(files_struct *fsp, const char *data, SMB_OFF_T pos, size_t n)
+ssize_t write_file(struct smb_request *req,
+ files_struct *fsp,
+ const char *data,
+ SMB_OFF_T pos,
+ size_t n)
{
write_cache *wcp = fsp->wcp;
ssize_t total_written = 0;
- int write_path = -1;
+ int write_path = -1;
if (fsp->print_file) {
fstring sharename;
SMB_STRUCT_STAT st;
fsp->modified = True;
- 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);
+ if (SMB_VFS_FSTAT(fsp, &st) == 0) {
+ int dosmode;
+ trigger_write_time_update(fsp);
+ 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,
+ NULL,
+ false);
}
/*
if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) && !wcp) {
setup_write_cache(fsp, st.st_size);
wcp = fsp->wcp;
- }
- }
+ }
+ }
}
#ifdef WITH_PROFILE
}
#endif
+ if (wcp && req->unread_bytes) {
+ /* If we're using receivefile don't
+ * deal with a write cache.
+ */
+ flush_write_cache(fsp, WRITE_FLUSH);
+ delete_write_cache(fsp);
+ wcp = NULL;
+ }
+
if(!wcp) {
DO_PROFILE_INC(writecache_direct_writes);
- total_written = real_write_file(fsp, data, pos, n);
+ total_written = real_write_file(req, fsp, data, pos, n);
return total_written;
}
fsp->fh->pos = pos + n;
- /*
+ /*
* If we have active cache and it isn't contiguous then we flush.
* NOTE: There is a small problem with running out of disk ....
*/
if ( n <= wcp->alloc_size && n > wcp->data_size) {
cache_flush_needed = True;
} else {
- ssize_t ret = real_write_file(fsp, data, pos, n);
+ ssize_t ret = real_write_file(NULL,fsp, data, pos, n);
/*
* If the write overlaps the entire cache, then
*/
if (n > wcp->alloc_size ) {
- ssize_t ret = real_write_file(fsp, data, pos, n);
+ ssize_t ret = real_write_file(NULL,fsp, data, pos, n);
if (ret == -1) {
return -1;
}
/* The cache *must* have been flushed before we do this. */
if (fsp->wcp->data_size != 0) {
char *msg;
- asprintf(&msg, "set_filelen_write_cache: size change "
+ if (asprintf(&msg, "set_filelen_write_cache: size change "
"on file %s with write cache size = %lu\n",
fsp->fsp_name,
- (unsigned long)fsp->wcp->data_size);
- smb_panic(msg);
+ (unsigned long)fsp->wcp->data_size) != -1) {
+ smb_panic(msg);
+ } else {
+ smb_panic("set_filelen_write_cache");
+ }
}
fsp->wcp->file_size = file_size;
}
}
#endif
- ret = real_write_file(fsp, wcp->data, wcp->offset, data_size);
+ ret = real_write_file(NULL, fsp, wcp->data, wcp->offset, data_size);
/*
* Ensure file size if kept up to date if write extends file.
if (ret == -1) {
return map_nt_error_from_unix(errno);
}
- ret = SMB_VFS_FSYNC(fsp,fsp->fh->fd);
+ ret = SMB_VFS_FSYNC(fsp);
if (ret == -1) {
return map_nt_error_from_unix(errno);
}
if (fsp->fh->fd == -1) {
return SMB_VFS_STAT(fsp->conn, fsp->fsp_name, pst);
} else {
- return SMB_VFS_FSTAT(fsp,fsp->fh->fd, pst);
+ return SMB_VFS_FSTAT(fsp, pst);
}
}