Fix more POSIX path lstat calls. Fix bug where close can return
[jra/samba/.git] / source3 / smbd / close.c
index a6dff20ec7cb60349d16875758f7184d8eba8cbf..d23b509af2dd16d82cc7f2ca9c6c5eaa00c82049 100644 (file)
@@ -134,6 +134,10 @@ static NTSTATUS close_filestruct(files_struct *fsp)
 static void notify_deferred_opens(struct share_mode_lock *lck)
 {
        int i;
+
+       if (!should_notify_deferred_opens()) {
+               return;
+       }
  
        for (i=0; i<lck->num_share_modes; i++) {
                struct share_mode_entry *e = &lck->share_modes[i];
@@ -167,7 +171,7 @@ static void notify_deferred_opens(struct share_mode_lock *lck)
  Delete all streams
 ****************************************************************************/
 
-static NTSTATUS delete_all_streams(connection_struct *conn, const char *fname)
+NTSTATUS delete_all_streams(connection_struct *conn, const char *fname)
 {
        struct stream_struct *stream_info;
        int i;
@@ -465,11 +469,12 @@ void set_close_write_time(struct files_struct *fsp, struct timespec ts)
 static NTSTATUS update_write_time_on_close(struct files_struct *fsp)
 {
        SMB_STRUCT_STAT sbuf;
-       struct timespec ts[2];
+       struct smb_file_time ft;
        NTSTATUS status;
+       int ret = -1;
 
        ZERO_STRUCT(sbuf);
-       ZERO_STRUCT(ts);
+       ZERO_STRUCT(ft);
 
        if (!fsp->update_write_time_on_close) {
                return NT_STATUS_OK;
@@ -481,23 +486,27 @@ static NTSTATUS update_write_time_on_close(struct files_struct *fsp)
 
        /* Ensure we have a valid stat struct for the source. */
        if (fsp->fh->fd != -1) {
-               if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
-                       return map_nt_error_from_unix(errno);
-               }
+               ret = SMB_VFS_FSTAT(fsp, &sbuf);
        } else {
-               if (SMB_VFS_STAT(fsp->conn,fsp->fsp_name,&sbuf) == -1) {
-                       return map_nt_error_from_unix(errno);
+               if (fsp->posix_open) {
+                       ret = SMB_VFS_LSTAT(fsp->conn,fsp->fsp_name,&sbuf);
+               } else {
+                       ret = SMB_VFS_STAT(fsp->conn,fsp->fsp_name,&sbuf);
                }
        }
 
+       if (ret == -1) {
+               return map_nt_error_from_unix(errno);
+       }
+
        if (!VALID_STAT(sbuf)) {
                /* if it doesn't seem to be a real file */
                return NT_STATUS_OK;
        }
 
-       ts[1] = fsp->close_write_time;
+       ft.mtime = fsp->close_write_time;
        status = smb_set_file_time(fsp->conn, fsp, fsp->fsp_name,
-                                  &sbuf, ts, true);
+                                  &sbuf, &ft, true);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
@@ -549,6 +558,11 @@ static NTSTATUS close_normal_file(struct smb_request *req, files_struct *fsp,
                return NT_STATUS_OK;
        }
 
+       /* Remove the oplock before potentially deleting the file. */
+       if(fsp->oplock_type) {
+               release_file_oplock(fsp);
+       }
+
        /* If this is an old DOS or FCB open and we have multiple opens on
           the same handle we only have one share mode. Ensure we only remove
           the share mode on the last close. */
@@ -558,10 +572,6 @@ static NTSTATUS close_normal_file(struct smb_request *req, files_struct *fsp,
                saved_status3 = close_remove_share_mode(fsp, close_type);
        }
 
-       if(fsp->oplock_type) {
-               release_file_oplock(fsp);
-       }
-
        locking_close_file(smbd_messaging_context(), fsp);
 
        status = fd_close(fsp);
@@ -576,6 +586,13 @@ static NTSTATUS close_normal_file(struct smb_request *req, files_struct *fsp,
         */
 
        saved_status4 = update_write_time_on_close(fsp);
+       if (NT_STATUS_EQUAL(saved_status4, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
+               /* Someone renamed the file or a parent directory containing
+                * this file. We can't do anything about this, we don't have
+                * an "update timestamp by fd" call in POSIX. Eat the error. */
+
+               saved_status4 = NT_STATUS_OK;
+       }
 
        if (NT_STATUS_IS_OK(status)) {
                if (!NT_STATUS_IS_OK(saved_status1)) {