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);
+ }
+ }
}
/****************************************************************************
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);
* 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
*/
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);
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" ));
*/
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);
}
/*