r12311: Reformatting
[kai/samba.git] / source3 / smbd / close.c
index afc645ca0627bd1bb7470d4d69d9e8f495b946e8..407c6078385c827f59eaa1fe01c62f4dc5e657bb 100644 (file)
@@ -110,31 +110,30 @@ static int close_filestruct(files_struct *fsp)
  If any deferred opens are waiting on this close, notify them.
 ****************************************************************************/
 
-static void notify_deferred_opens(files_struct *fsp)
+static void notify_deferred_opens(struct share_mode_lock *lck)
 {
-       deferred_open_entry *de_array = NULL;
-       int num_de_entries, i;
-       pid_t mypid = sys_getpid();
-
-       if (!lp_defer_sharing_violations()) {
-               return;
-       }
-
-       num_de_entries = get_deferred_opens(fsp->conn, fsp->dev, fsp->inode, &de_array);
-       for (i = 0; i < num_de_entries; i++) {
-               deferred_open_entry *entry = &de_array[i];
-               if (entry->pid == mypid) {
-                       /*
-                        * We need to notify ourself to retry the open.
-                        * Do this by finding the queued SMB record, moving it
-                        * to the head of the queue and changing the wait time to zero.
-                        */
-                       schedule_sharing_violation_open_smb_message(entry->mid);
-               } else {
-                       send_deferred_open_retry_message(entry);
-               }
-       }
-       SAFE_FREE(de_array);
+       int i;
+       for (i=0; i<lck->num_share_modes; i++) {
+               struct share_mode_entry *e = &lck->share_modes[i];
+               if (!is_deferred_open_entry(e)) {
+                       continue;
+               }
+               if (procid_is_me(&e->pid)) {
+                       /*
+                        * We need to notify ourself to retry the open.  Do
+                        * this by finding the queued SMB record, moving it to
+                        * the head of the queue and changing the wait time to
+                        * zero.
+                        */
+                       schedule_deferred_open_smb_message(e->op_mid);
+               } else {
+                       message_send_pid(e->pid, MSG_SMB_OPEN_RETRY,
+                                        e, sizeof(*e), True);
+               }
+       }
 }
 
 /****************************************************************************
@@ -148,13 +147,12 @@ static void notify_deferred_opens(files_struct *fsp)
 
 static int close_normal_file(files_struct *fsp, BOOL normal_close)
 {
-       share_mode_entry *share_entry = NULL;
-       size_t share_entry_count = 0;
        BOOL delete_file = False;
        connection_struct *conn = fsp->conn;
        int saved_errno = 0;
        int err = 0;
        int err1 = 0;
+       struct share_mode_lock *lck;
 
        remove_pending_lock_requests_by_fid(fsp);
 
@@ -194,23 +192,34 @@ static int close_normal_file(files_struct *fsp, BOOL normal_close)
         * This prevents race conditions with the file being created. JRA.
         */
 
-       lock_share_entry_fsp(fsp);
-
-       share_entry_count = del_share_mode(fsp, &share_entry,
-                                          &delete_file);
+       lck = get_share_mode_lock(NULL, fsp->dev, fsp->inode, NULL, NULL);
 
-       DEBUG(10,("close_normal_file: share_entry_count = %lu for file %s\n",
-               (unsigned long)share_entry_count, fsp->fsp_name ));
+       if (lck == NULL) {
+               DEBUG(0, ("close_file: Could not get share mode lock for file %s\n", fsp->fsp_name));
+               return EINVAL;
+       }
 
-       if (share_entry_count != 0) {
-               /* We're not the last ones -- don't delete */
-               delete_file = False;
+       if (!del_share_mode(lck, fsp)) {
+               DEBUG(0, ("close_file: Could not delete share entry for file %s\n", fsp->fsp_name));
        }
 
-       SAFE_FREE(share_entry);
+       delete_file = lck->delete_on_close;
+
+       if (delete_file) {
+               int i;
+               /* See if others still have the file open. If this is the
+                * case, then don't delete */
+               for (i=0; i<lck->num_share_modes; i++) {
+                       if (is_valid_share_mode_entry(&lck->share_modes[i])) {
+                               delete_file = False;
+                               break;
+                       }
+               }
+       }
 
        /* Notify any deferred opens waiting on this close. */
-       notify_deferred_opens(fsp);
+       notify_deferred_opens(lck);
+       reply_to_oplock_break_requests(fsp);
 
        /*
         * NT can set delete_on_close of the last open
@@ -218,23 +227,46 @@ static int close_normal_file(files_struct *fsp, BOOL normal_close)
         */
 
        if (normal_close && delete_file) {
+               SMB_STRUCT_STAT sbuf;
+
                DEBUG(5,("close_file: file %s. Delete on close was set - deleting file.\n",
                        fsp->fsp_name));
-               if(SMB_VFS_UNLINK(conn,fsp->fsp_name) != 0) {
-                       /*
-                        * This call can potentially fail as another smbd may have
-                        * had the file open with delete on close set and deleted
-                        * it when its last reference to this file went away. Hence
-                        * we log this but not at debug level zero.
-                        */
-
-               DEBUG(5,("close_file: file %s. Delete on close was set and unlink failed \
-with error %s\n", fsp->fsp_name, strerror(errno) ));
+
+               /* We can only delete the file if the name we have
+                  is still valid and hasn't been renamed. */
+
+               if(SMB_VFS_STAT(conn,fsp->fsp_name,&sbuf) != 0) {
+                       DEBUG(5,("close_file: file %s. Delete on close was set "
+                               "and stat failed with error %s\n",
+                               fsp->fsp_name, strerror(errno) ));
+               } else {
+                       if(sbuf.st_dev != fsp->dev || sbuf.st_ino != fsp->inode) {
+                               DEBUG(5,("close_file: file %s. Delete on close was set and "
+                                       "dev and/or inode does not match\n",
+                                       fsp->fsp_name ));
+                               DEBUG(5,("close_file: file %s. stored dev = %x, inode = %.0f "
+                                       "stat dev = %x, inode = %.0f\n",
+                                       fsp->fsp_name,
+                                       (unsigned int)fsp->dev, (double)fsp->inode,
+                                       (unsigned int)sbuf.st_dev, (double)sbuf.st_ino ));
+
+                       } else if(SMB_VFS_UNLINK(conn,fsp->fsp_name) != 0) {
+                               /*
+                                * This call can potentially fail as another smbd may have
+                                * had the file open with delete on close set and deleted
+                                * it when its last reference to this file went away. Hence
+                                * we log this but not at debug level zero.
+                                */
+
+                               DEBUG(5,("close_file: file %s. Delete on close was set "
+                                       "and unlink failed with error %s\n",
+                                       fsp->fsp_name, strerror(errno) ));
+                       }
+                       process_pending_change_notify_queue((time_t)0);
                }
-               process_pending_change_notify_queue((time_t)0);
        }
 
-       unlock_share_entry_fsp(fsp);
+       talloc_free(lck);
 
        if(fsp->oplock_type)
                release_file_oplock(fsp);
@@ -288,15 +320,30 @@ with error %s\n", fsp->fsp_name, strerror(errno) ));
   
 static int close_directory(files_struct *fsp, BOOL normal_close)
 {
-       remove_pending_change_notify_requests_by_fid(fsp);
+       struct share_mode_lock *lck = 0;
+       BOOL delete_dir = False;
 
        /*
         * NT can set delete_on_close of the last open
         * reference to a directory also.
         */
 
-       if (normal_close &&
-           get_delete_on_close_flag(fsp->dev, fsp->inode)) {
+       lck = get_share_mode_lock(NULL, fsp->dev, fsp->inode, NULL, NULL);
+
+       if (lck == NULL) {
+               DEBUG(0, ("close_directory: Could not get share mode lock for %s\n", fsp->fsp_name));
+               return EINVAL;
+       }
+
+       if (!del_share_mode(lck, fsp)) {
+               DEBUG(0, ("close_directory: Could not delete share entry for %s\n", fsp->fsp_name));
+       }
+
+       delete_dir = lck->delete_on_close;
+
+       talloc_free(lck);
+
+       if (normal_close && delete_dir) {
                BOOL ok = rmdir_internals(fsp->conn, fsp->fsp_name);
                DEBUG(5,("close_directory: %s. Delete on close was set - deleting directory %s.\n",
                        fsp->fsp_name, ok ? "succeeded" : "failed" ));
@@ -307,9 +354,13 @@ static int close_directory(files_struct *fsp, BOOL normal_close)
                 */
 
                if(ok) {
-                       remove_pending_change_notify_requests_by_filename(fsp);
+                       remove_pending_change_notify_requests_by_fid(fsp, NT_STATUS_DELETE_PENDING);
+                       remove_pending_change_notify_requests_by_filename(fsp, NT_STATUS_DELETE_PENDING);
+
                }
                process_pending_change_notify_queue((time_t)0);
+       } else {
+               remove_pending_change_notify_requests_by_fid(fsp, NT_STATUS_CANCELLED);
        }
 
        /*