summaryrefslogtreecommitdiff
path: root/source3/smbd/open.c
diff options
context:
space:
mode:
Diffstat (limited to 'source3/smbd/open.c')
-rw-r--r--source3/smbd/open.c120
1 files changed, 119 insertions, 1 deletions
diff --git a/source3/smbd/open.c b/source3/smbd/open.c
index 353e20df8a..44bb6ebaf7 100644
--- a/source3/smbd/open.c
+++ b/source3/smbd/open.c
@@ -50,13 +50,125 @@ static int fd_open(struct connection_struct *conn, char *fname,
}
/****************************************************************************
+ Take care of moving any POSIX pending close fd's to another fsp.
+****************************************************************************/
+
+static BOOL fd_close_posix_locks(files_struct *fsp)
+{
+ files_struct *other_fsp;
+
+ DEBUG(10,("fd_close_posix_locks: file %s: fsp->num_posix_pending_closes = %u.\n", fsp->fsp_name,
+ (unsigned int)fsp->num_posix_pending_closes ));
+
+ for(other_fsp = file_find_di_first(fsp->dev, fsp->inode); other_fsp;
+ other_fsp = file_find_di_next(other_fsp)) {
+
+ if ((other_fsp->fd != -1) && other_fsp->num_posix_locks) {
+
+ /*
+ * POSIX locks pending on another fsp held open, transfer
+ * the fd in this fsp and all the pending fd's in this fsp pending close array
+ * to the other_fsp pending close array.
+ */
+
+ unsigned int extra_fds = fsp->num_posix_pending_closes + 1;
+
+ DEBUG(10,("fd_close_posix_locks: file %s: Transferring to \
+file %s, other_fsp->num_posix_pending_closes = %u.\n",
+ fsp->fsp_name, other_fsp->fsp_name, (unsigned int)other_fsp->num_posix_pending_closes ));
+
+ other_fsp->posix_pending_close_fds = (int *)Realloc(other_fsp->posix_pending_close_fds,
+ (other_fsp->num_posix_pending_closes +
+ extra_fds)*sizeof(int));
+
+ if(other_fsp->posix_pending_close_fds == NULL) {
+ DEBUG(0,("fd_close_posix_locks: Unable to increase posix_pending_close_fds array size !\n"));
+ return False;
+ }
+
+ /*
+ * Copy over any fd's in the existing fsp's pending array.
+ */
+
+ if(fsp->posix_pending_close_fds) {
+ memcpy(&other_fsp->posix_pending_close_fds[other_fsp->num_posix_pending_closes],
+ &fsp->posix_pending_close_fds[0], fsp->num_posix_pending_closes * sizeof(int) );
+
+ free((char *)fsp->posix_pending_close_fds);
+ fsp->posix_pending_close_fds = NULL;
+ fsp->num_posix_pending_closes = 0;
+ }
+
+ other_fsp->posix_pending_close_fds[other_fsp->num_posix_pending_closes+extra_fds-1] = fsp->fd;
+ other_fsp->num_posix_pending_closes += extra_fds;
+
+ fsp->fd = -1; /* We have moved this fd to other_fsp's pending close array.... */
+
+ break;
+ }
+ }
+
+ return True;
+}
+
+/****************************************************************************
Close the file associated with a fsp.
+
+ This is where we must deal with POSIX "first close drops all locks"
+ locking braindamage. We do this by searching for any other fsp open
+ on the same dev/inode with open POSIX locks, and then transferring this
+ fd (and all pending fd's attached to this fsp) to the posix_pending_close_fds
+ array in that fsp.
+
+ If there are no open fsp's on the same dev/inode then we close all the
+ fd's in the posix_pending_close_fds array and then close the fd.
+
****************************************************************************/
int fd_close(struct connection_struct *conn, files_struct *fsp)
{
- int ret = conn->vfs_ops.close(fsp->fd);
+ int ret = 0;
+ int saved_errno = 0;
+ unsigned int i;
+
+ /*
+ * Deal with transferring any pending fd's if there
+ * are POSIX locks outstanding.
+ */
+
+ if(!fd_close_posix_locks(fsp))
+ return -1;
+
+ /*
+ * Close and free any pending closes given to use from
+ * other fsp's.
+ */
+
+ if (fsp->posix_pending_close_fds) {
+
+ for(i = 0; i < fsp->num_posix_pending_closes; i++) {
+ if (fsp->posix_pending_close_fds[i] != -1) {
+ if (conn->vfs_ops.close(fsp->posix_pending_close_fds[i]) == -1) {
+ saved_errno = errno;
+ }
+ }
+ }
+
+ free((char *)fsp->posix_pending_close_fds);
+ fsp->posix_pending_close_fds = NULL;
+ fsp->num_posix_pending_closes = 0;
+ }
+
+ if(fsp->fd != -1)
+ ret = conn->vfs_ops.close(fsp->fd);
+
fsp->fd = -1;
+
+ if (saved_errno != 0) {
+ errno = saved_errno;
+ ret = -1;
+ }
+
return ret;
}
@@ -163,6 +275,8 @@ static BOOL open_file(files_struct *fsp,connection_struct *conn,
fsp->oplock_type = NO_OPLOCK;
fsp->sent_oplock_break = NO_BREAK_SENT;
fsp->num_posix_locks = 0;
+ fsp->num_posix_pending_closes = 0;
+ fsp->posix_pending_close_fds = NULL;
fsp->is_directory = False;
fsp->stat_open = False;
fsp->directory_delete_on_close = False;
@@ -797,6 +911,8 @@ files_struct *open_file_stat(connection_struct *conn,
fsp->oplock_type = NO_OPLOCK;
fsp->sent_oplock_break = NO_BREAK_SENT;
fsp->num_posix_locks = 0;
+ fsp->num_posix_pending_closes = 0;
+ fsp->posix_pending_close_fds = NULL;
fsp->is_directory = False;
fsp->stat_open = True;
fsp->directory_delete_on_close = False;
@@ -921,6 +1037,8 @@ files_struct *open_directory(connection_struct *conn,
fsp->oplock_type = NO_OPLOCK;
fsp->sent_oplock_break = NO_BREAK_SENT;
fsp->num_posix_locks = 0;
+ fsp->num_posix_pending_closes = 0;
+ fsp->posix_pending_close_fds = NULL;
fsp->is_directory = True;
fsp->directory_delete_on_close = False;
fsp->conn = conn;