/* Unix SMB/CIFS implementation. file closing Copyright (C) Andrew Tridgell 1992-1998 Copyright (C) Jeremy Allison 1992-2004. Copyright (C) Volker Lendecke 2005 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "includes.h" /**************************************************************************** Run a file if it is a magic script. ****************************************************************************/ static void check_magic(files_struct *fsp,connection_struct *conn) { if (!*lp_magicscript(SNUM(conn))) return; DEBUG(5,("checking magic for %s\n",fsp->fsp_name)); { char *p; if (!(p = strrchr_m(fsp->fsp_name,'/'))) p = fsp->fsp_name; else p++; if (!strequal(lp_magicscript(SNUM(conn)),p)) return; } { int ret; pstring magic_output; pstring fname; SMB_STRUCT_STAT st; int tmp_fd, outfd; pstrcpy(fname,fsp->fsp_name); if (*lp_magicoutput(SNUM(conn))) pstrcpy(magic_output,lp_magicoutput(SNUM(conn))); else slprintf(magic_output,sizeof(fname)-1, "%s.out",fname); chmod(fname,0755); ret = smbrun(fname,&tmp_fd); DEBUG(3,("Invoking magic command %s gave %d\n",fname,ret)); unlink(fname); if (ret != 0 || tmp_fd == -1) { if (tmp_fd != -1) close(tmp_fd); return; } outfd = open(magic_output, O_CREAT|O_EXCL|O_RDWR, 0600); if (outfd == -1) { close(tmp_fd); return; } if (sys_fstat(tmp_fd,&st) == -1) { close(tmp_fd); close(outfd); return; } transfer_file(tmp_fd,outfd,(SMB_OFF_T)st.st_size); close(tmp_fd); close(outfd); } } /**************************************************************************** Common code to close a file or a directory. ****************************************************************************/ static int close_filestruct(files_struct *fsp) { connection_struct *conn = fsp->conn; int ret = 0; if (fsp->fh->fd != -1) { if(flush_write_cache(fsp, CLOSE_FLUSH) == -1) ret = -1; delete_write_cache(fsp); } conn->num_files_open--; SAFE_FREE(fsp->wbmpx_ptr); return ret; } /**************************************************************************** If any deferred opens are waiting on this close, notify them. ****************************************************************************/ static void notify_deferred_opens(struct share_mode_lock *lck) { int i; for (i=0; inum_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 { char msg[MSG_SMB_SHARE_MODE_ENTRY_SIZE]; share_mode_entry_to_message(msg, e); become_root(); message_send_pid(e->pid, MSG_SMB_OPEN_RETRY, msg, MSG_SMB_SHARE_MODE_ENTRY_SIZE, True); unbecome_root(); } } } /**************************************************************************** Close a file. close_type can be NORMAL_CLOSE=0,SHUTDOWN_CLOSE,ERROR_CLOSE. printing and magic scripts are only run on normal close. delete on close is done on normal and shutdown close. ****************************************************************************/ static int close_normal_file(files_struct *fsp, enum file_close_type close_type) { 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); if (fsp->aio_write_behind) { /* * If we're finishing write behind on a close we can get a write * error here, we must remember this. */ int ret = wait_for_aio_completion(fsp); if (ret) { saved_errno = ret; err1 = -1; } } else { cancel_aio_by_fsp(fsp); } /* * If we're flushing on a close we can get a write * error here, we must remember this. */ if (close_filestruct(fsp) == -1) { saved_errno = errno; err1 = -1; } if (fsp->print_file) { print_fsp_end(fsp, close_type); file_free(fsp); return 0; } /* * Lock the share entries, and determine if we should delete * on close. If so delete whilst the lock is still in effect. * This prevents race conditions with the file being created. JRA. */ lck = get_share_mode_lock(NULL, fsp->dev, fsp->inode, NULL, NULL); if (lck == NULL) { DEBUG(0, ("close_file: Could not get share mode lock for file %s\n", fsp->fsp_name)); return EINVAL; } if (!del_share_mode(lck, fsp)) { DEBUG(0, ("close_file: Could not delete share entry for file %s\n", fsp->fsp_name)); } delete_file = (lck->delete_on_close | lck->initial_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; inum_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(lck); reply_to_oplock_break_requests(fsp); /* * NT can set delete_on_close of the last open * reference to a file. */ if ((close_type == NORMAL_CLOSE || close_type == SHUTDOWN_CLOSE) && delete_file && lck->delete_token) { SMB_STRUCT_STAT sbuf; DEBUG(5,("close_file: file %s. Delete on close was set - deleting file.\n", fsp->fsp_name)); /* Become the user who requested the delete. */ if (!push_sec_ctx()) { smb_panic("close_file: file %s. failed to push sec_ctx.\n"); } set_sec_ctx(lck->delete_token->uid, lck->delete_token->gid, lck->delete_token->ngroups, lck->delete_token->groups, NULL); /* 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) )); } } /* unbecome user. */ pop_sec_ctx(); process_pending_change_notify_queue((time_t)0); } TALLOC_FREE(lck); if(fsp->oplock_type) release_file_oplock(fsp); locking_close_file(fsp); err = fd_close(conn, fsp); /* Only save errno if fd_close failed and we don't already have an errno saved from a flush call. */ if ((err1 != -1) && (err == -1)) { saved_errno = errno; } /* check for magic scripts */ if (close_type == NORMAL_CLOSE) { check_magic(fsp,conn); } /* * Ensure pending modtime is set after close. */ if(fsp->pending_modtime && fsp->pending_modtime_owner) { set_filetime(conn, fsp->fsp_name, fsp->pending_modtime); } else if (fsp->last_write_time) { set_filetime(conn, fsp->fsp_name, fsp->last_write_time); } DEBUG(2,("%s closed file %s (numopen=%d) %s\n", conn->user,fsp->fsp_name, conn->num_files_open, (err == -1 || err1 == -1) ? strerror(saved_errno) : "")); if (fsp->fsp_name) string_free(&fsp->fsp_name); file_free(fsp); if (err == -1 || err1 == -1) { errno = saved_errno; return saved_errno; } else { return 0; } } /**************************************************************************** Close a directory opened by an NT SMB call. ****************************************************************************/ static int close_directory(files_struct *fsp, enum file_close_type close_type) { 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. */ 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 | lck->initial_delete_on_close); TALLOC_FREE(lck); if ((close_type == NORMAL_CLOSE || close_type == SHUTDOWN_CLOSE) && delete_dir && lck->delete_token) { BOOL ok; /* Become the user who requested the delete. */ if (!push_sec_ctx()) { smb_panic("close_directory: failed to push sec_ctx.\n"); } set_sec_ctx(lck->delete_token->uid, lck->delete_token->gid, lck->delete_token->ngroups, lck->delete_token->groups, NULL); 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" )); /* unbecome user. */ pop_sec_ctx(); /* * Ensure we remove any change notify requests that would * now fail as the directory has been deleted. */ if(ok) { 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); } /* * Do the code common to files and directories. */ close_filestruct(fsp); if (fsp->fsp_name) { string_free(&fsp->fsp_name); } file_free(fsp); return 0; } /**************************************************************************** Close a 'stat file' opened internally. ****************************************************************************/ static int close_stat(files_struct *fsp) { /* * Do the code common to files and directories. */ close_filestruct(fsp); if (fsp->fsp_name) string_free(&fsp->fsp_name); file_free(fsp); return 0; } /**************************************************************************** Close a files_struct. ****************************************************************************/ int close_file(files_struct *fsp, enum file_close_type close_type) { if(fsp->is_directory) return close_directory(fsp, close_type); else if (fsp->is_stat) return close_stat(fsp); else return close_normal_file(fsp, close_type); }