diff options
author | Andrew Tridgell <tridge@samba.org> | 1999-12-13 13:27:58 +0000 |
---|---|---|
committer | Andrew Tridgell <tridge@samba.org> | 1999-12-13 13:27:58 +0000 |
commit | 453a822a76780063dff23526c35408866d0c0154 (patch) | |
tree | 804feffcd5e60153e27d3ca2b007021e66e5bd0a /source/smbd/open.c | |
parent | 054195df9b6187c663ede5cf4489499abbdc29fc (diff) | |
download | samba-453a822a76780063dff23526c35408866d0c0154.tar.gz samba-453a822a76780063dff23526c35408866d0c0154.tar.xz samba-453a822a76780063dff23526c35408866d0c0154.zip |
first pass at updating head branch to be to be the same as the SAMBA_2_0 branch
Diffstat (limited to 'source/smbd/open.c')
-rw-r--r-- | source/smbd/open.c | 386 |
1 files changed, 256 insertions, 130 deletions
diff --git a/source/smbd/open.c b/source/smbd/open.c index 2c12d425b95..4491082b2c5 100644 --- a/source/smbd/open.c +++ b/source/smbd/open.c @@ -25,22 +25,22 @@ extern int DEBUGLEVEL; extern pstring sesssetup_user; extern uint16 global_oplock_port; - +extern BOOL global_client_failed_oplock_break; /**************************************************************************** fd support routines - attempt to do a dos_open ****************************************************************************/ -static int fd_attempt_open(struct connection_struct *conn, char *fname, - int flags, mode_t mode) + +static int fd_attempt_open(char *fname, int flags, mode_t mode) { - int fd = conn->vfs_ops.open(fname,flags,mode); + int fd = dos_open(fname,flags,mode); /* Fix for files ending in '.' */ if((fd == -1) && (errno == ENOENT) && (strchr(fname,'.')==NULL)) { pstrcat(fname,"."); - fd = conn->vfs_ops.open(fname,flags,mode); + fd = dos_open(fname,flags,mode); } #if (defined(ENAMETOOLONG) && defined(HAVE_PATHCONF)) @@ -71,7 +71,7 @@ static int fd_attempt_open(struct connection_struct *conn, char *fname, char tmp = p[max_len]; p[max_len] = '\0'; - if ((fd = conn->vfs_ops.open(fname,flags,mode)) == -1) + if ((fd = dos_open(fname,flags,mode)) == -1) p[max_len] = tmp; } } @@ -83,6 +83,7 @@ static int fd_attempt_open(struct connection_struct *conn, char *fname, Cache a uid_t currently with this file open. This is an optimization only used when multiple sessionsetup's have been done to one smbd. ****************************************************************************/ + void fd_add_to_uid_cache(file_fd_struct *fd_ptr, uid_t u) { if(fd_ptr->uid_cache_count >= sizeof(fd_ptr->uid_users_cache)/sizeof(uid_t)) @@ -94,6 +95,7 @@ void fd_add_to_uid_cache(file_fd_struct *fd_ptr, uid_t u) Remove a uid_t that currently has this file open. This is an optimization only used when multiple sessionsetup's have been done to one smbd. ****************************************************************************/ + static void fd_remove_from_uid_cache(file_fd_struct *fd_ptr, uid_t u) { int i; @@ -111,6 +113,7 @@ static void fd_remove_from_uid_cache(file_fd_struct *fd_ptr, uid_t u) Check if a uid_t that currently has this file open is present. This is an optimization only used when multiple sessionsetup's have been done to one smbd. ****************************************************************************/ + static BOOL fd_is_in_uid_cache(file_fd_struct *fd_ptr, uid_t u) { int i; @@ -120,11 +123,11 @@ static BOOL fd_is_in_uid_cache(file_fd_struct *fd_ptr, uid_t u) return False; } - /**************************************************************************** fd support routines - attempt to re-open an already open fd as O_RDWR. Save the already open fd (we cannot close due to POSIX file locking braindamage. ****************************************************************************/ + static void fd_attempt_reopen(char *fname, mode_t mode, file_fd_struct *fd_ptr) { int fd = dos_open( fname, O_RDWR, mode); @@ -145,17 +148,13 @@ static void fd_attempt_reopen(char *fname, mode_t mode, file_fd_struct *fd_ptr) fd support routines - attempt to close the file referenced by this fd. Decrements the ref_count and returns it. ****************************************************************************/ -uint16 fd_attempt_close(files_struct *fsp) + +uint16 fd_attempt_close(file_fd_struct *fd_ptr, int *err_ret) { extern struct current_user current_user; - file_fd_struct *fd_ptr = fsp->fd_ptr; - uint16 ret_ref; + uint16 ret_ref = fd_ptr->ref_count; - if (fd_ptr != NULL) { - ret_ref = fd_ptr->ref_count; - } else { - return 0; - } + *err_ret = 0; DEBUG(3,("fd_attempt_close fd = %d, dev = %x, inode = %.0f, open_flags = %d, ref_count = %d.\n", fd_ptr->fd, (unsigned int)fd_ptr->dev, (double)fd_ptr->inode, @@ -168,12 +167,26 @@ uint16 fd_attempt_close(files_struct *fsp) ret_ref = fd_ptr->ref_count; if(fd_ptr->ref_count == 0) { - if(fd_ptr->fd != -1) - fsp->conn->vfs_ops.close(fd_ptr->fd); - if(fd_ptr->fd_readonly != -1) - fsp->conn->vfs_ops.close(fd_ptr->fd_readonly); - if(fd_ptr->fd_writeonly != -1) - fsp->conn->vfs_ops.close(fd_ptr->fd_writeonly); + + if(fd_ptr->fd != -1) { + if(close(fd_ptr->fd) < 0) + *err_ret = errno; + } + + if(fd_ptr->fd_readonly != -1) { + if(close(fd_ptr->fd_readonly) < 0) { + if(*err_ret == 0) + *err_ret = errno; + } + } + + if(fd_ptr->fd_writeonly != -1) { + if( close(fd_ptr->fd_writeonly) < 0) { + if(*err_ret == 0) + *err_ret = errno; + } + } + /* * Delete this fd_ptr. */ @@ -182,7 +195,7 @@ uint16 fd_attempt_close(files_struct *fsp) fd_remove_from_uid_cache(fd_ptr, (uid_t)current_user.uid); } - return ret_ref; + return ret_ref; } /**************************************************************************** @@ -192,14 +205,21 @@ This is really ugly code, as due to POSIX locking braindamage we must fork and then attempt to open the file, and return success or failure via an exit code. ****************************************************************************/ -static BOOL check_access_allowed_for_current_user(struct connection_struct - *conn, char *fname, - int accmode ) + +static BOOL check_access_allowed_for_current_user( char *fname, int accmode ) { pid_t child_pid; + /* + * We need to temporarily stop CatchChild from eating + * SIGCLD signals as it also eats the exit status code. JRA. + */ + + CatchChildLeaveStatus(); + if((child_pid = fork()) < 0) { DEBUG(0,("check_access_allowed_for_current_user: fork failed.\n")); + CatchChild(); return False; } @@ -209,11 +229,23 @@ static BOOL check_access_allowed_for_current_user(struct connection_struct */ pid_t wpid; int status_code; - if ((wpid = sys_waitpid(child_pid, &status_code, 0)) < 0) { - DEBUG(0,("check_access_allowed_for_current_user: The process is no longer waiting!\n")); + + while ((wpid = sys_waitpid(child_pid, &status_code, 0)) < 0) { + if(errno == EINTR) { + errno = 0; + continue; + } + DEBUG(0,("check_access_allowed_for_current_user: The process \ +is no longer waiting ! Error = %s\n", strerror(errno) )); + CatchChild(); return(False); } + /* + * Go back to ignoring children. + */ + CatchChild(); + if (child_pid != wpid) { DEBUG(0,("check_access_allowed_for_current_user: We were waiting for the wrong process ID\n")); return(False); @@ -245,7 +277,7 @@ static BOOL check_access_allowed_for_current_user(struct connection_struct */ int fd; DEBUG(9,("check_access_allowed_for_current_user: Child - attempting to open %s with mode %d.\n", fname, accmode )); - if((fd = fd_attempt_open(conn, fname, accmode, 0)) < 0) { + if((fd = fd_attempt_open( fname, accmode, 0)) < 0) { /* Access denied. */ _exit(EACCES); } @@ -260,11 +292,12 @@ static BOOL check_access_allowed_for_current_user(struct connection_struct /**************************************************************************** check a filename for the pipe string ****************************************************************************/ + static void check_for_pipe(char *fname) { /* special case of pipe opens */ char s[10]; - StrnCpy(s,fname,9); + StrnCpy(s,fname,sizeof(s)-1); strlower(s); if (strstr(s,"pipe/")) { DEBUG(3,("Rejecting named pipe open for %s\n",fname)); @@ -276,6 +309,7 @@ static void check_for_pipe(char *fname) /**************************************************************************** open a file ****************************************************************************/ + static void open_file(files_struct *fsp,connection_struct *conn, char *fname1,int flags,mode_t mode, SMB_STRUCT_STAT *sbuf) { @@ -287,7 +321,7 @@ static void open_file(files_struct *fsp,connection_struct *conn, fsp->open = False; fsp->fd_ptr = 0; - fsp->granted_oplock = False; + fsp->oplock_type = NO_OPLOCK; errno = EPERM; pstrcpy(fname,fname1); @@ -304,7 +338,7 @@ static void open_file(files_struct *fsp,connection_struct *conn, * JRA. */ - if (conn->read_only && !conn->printer) { + if (!CAN_WRITE(conn) && !conn->printer) { /* It's a read-only share - fail if we wanted to write. */ if(accmode != O_RDONLY) { DEBUG(3,("Permission denied opening %s\n",fname)); @@ -335,7 +369,7 @@ static void open_file(files_struct *fsp,connection_struct *conn, * open fd table. */ if(sbuf == 0) { - if(conn->vfs_ops.stat(dos_to_unix(fname,False), &statbuf) < 0) { + if(dos_stat(fname, &statbuf) < 0) { if(errno != ENOENT) { DEBUG(3,("Error doing stat on file %s (%s)\n", fname,strerror(errno))); @@ -376,7 +410,7 @@ static void open_file(files_struct *fsp,connection_struct *conn, */ if(!fd_is_in_uid_cache(fd_ptr, (uid_t)current_user.uid)) { - if(!check_access_allowed_for_current_user(conn, fname, accmode )) { + if(!check_access_allowed_for_current_user( fname, accmode )) { /* Error - permission denied. */ DEBUG(3,("Permission denied opening file %s (flags=%d, accmode = %d)\n", fname, flags, accmode)); @@ -433,7 +467,7 @@ static void open_file(files_struct *fsp,connection_struct *conn, fd_ptr->real_open_flags = O_RDWR; /* Set the flags as needed without the read/write modes. */ open_flags = flags & ~(O_RDWR|O_WRONLY|O_RDONLY); - fd_ptr->fd = fd_attempt_open(conn, fname, open_flags|O_RDWR, mode); + fd_ptr->fd = fd_attempt_open(fname, open_flags|O_RDWR, mode); /* * On some systems opening a file for R/W access on a read only * filesystems sets errno to EROFS. @@ -444,7 +478,7 @@ static void open_file(files_struct *fsp,connection_struct *conn, if((fd_ptr->fd == -1) && (errno == EACCES)) { #endif /* EROFS */ if(accmode != O_RDWR) { - fd_ptr->fd = fd_attempt_open(conn, fname, open_flags|accmode, mode); + fd_ptr->fd = fd_attempt_open(fname, open_flags|accmode, mode); fd_ptr->real_open_flags = accmode; } } @@ -458,10 +492,10 @@ static void open_file(files_struct *fsp,connection_struct *conn, pstrcpy(dname,fname); p = strrchr(dname,'/'); if (p) *p = 0; - if (conn->vfs_ops.disk_free(dname,&dum1,&dum2,&dum3) < - (SMB_BIG_UINT)lp_minprintspace(SNUM(conn))) { - if(fd_attempt_close(fsp) == 0) - conn->vfs_ops.unlink(fname); + if (sys_disk_free(dname,False,&dum1,&dum2,&dum3) < (SMB_BIG_UINT)lp_minprintspace(SNUM(conn))) { + int err; + if(fd_attempt_close(fd_ptr, &err) == 0) + dos_unlink(fname); fsp->fd_ptr = 0; errno = ENOSPC; return; @@ -470,10 +504,11 @@ static void open_file(files_struct *fsp,connection_struct *conn, if (fd_ptr->fd < 0) { + int err; DEBUG(3,("Error opening file %s (%s) (flags=%d)\n", fname,strerror(errno),flags)); /* Ensure the ref_count is decremented. */ - fd_attempt_close(fsp); + fd_attempt_close(fd_ptr,&err); check_for_pipe(fname); return; } @@ -482,12 +517,13 @@ static void open_file(files_struct *fsp,connection_struct *conn, { if(sbuf == 0) { /* Do the fstat */ - if(conn->vfs_ops.fstat(fd_ptr->fd, &statbuf) == -1) { + if(sys_fstat(fd_ptr->fd, &statbuf) == -1) { + int err; /* Error - backout !! */ DEBUG(3,("Error doing fstat on fd %d, file %s (%s)\n", fd_ptr->fd, fname,strerror(errno))); /* Ensure the ref_count is decremented. */ - fd_attempt_close(fsp); + fd_attempt_close(fd_ptr,&err); return; } sbuf = &statbuf; @@ -505,17 +541,17 @@ static void open_file(files_struct *fsp,connection_struct *conn, fsp->size = 0; fsp->pos = -1; fsp->open = True; - fsp->mmap_ptr = NULL; - fsp->mmap_size = 0; fsp->can_lock = True; fsp->can_read = ((flags & O_WRONLY)==0); fsp->can_write = ((flags & (O_WRONLY|O_RDWR))!=0); fsp->share_mode = 0; fsp->print_file = conn->printer; fsp->modified = False; - fsp->granted_oplock = False; - fsp->sent_oplock_break = False; + fsp->oplock_type = NO_OPLOCK; + fsp->sent_oplock_break = NO_BREAK_SENT; fsp->is_directory = False; + fsp->stat_open = False; + fsp->directory_delete_on_close = False; fsp->conn = conn; /* * Note that the file name here is the *untranslated* name @@ -526,6 +562,7 @@ static void open_file(files_struct *fsp,connection_struct *conn, */ string_set(&fsp->fsp_name,fname); fsp->wbmpx_ptr = NULL; + fsp->wcp = NULL; /* Write cache pointer. */ /* * If the printer is marked as postscript output a leading @@ -536,7 +573,7 @@ static void open_file(files_struct *fsp,connection_struct *conn, */ if (fsp->print_file && lp_postscript(SNUM(conn)) && fsp->can_write) { DEBUG(3,("Writing postscript line\n")); - conn->vfs_ops.write(fsp->fd_ptr->fd,"%!\n",3); + write_file(fsp,"%!\n",-1,3); } DEBUG(2,("%s opened file %s read=%s write=%s (numopen=%d)\n", @@ -548,39 +585,11 @@ static void open_file(files_struct *fsp,connection_struct *conn, } /**************************************************************************** - If it's a read-only file, and we were compiled with mmap enabled, - try and mmap the file. This is split out from open_file() above - as mmap'ing the file can cause the kernel reference count to - be incremented, which can cause kernel oplocks to be refused. - Splitting this call off allows the kernel oplock to be granted, then - the file mmap'ed. -****************************************************************************/ - -static void mmap_open_file(files_struct *fsp) -{ -#if WITH_MMAP - /* mmap it if read-only */ - if (!fsp->can_write) { - fsp->mmap_size = dos_file_size(fsp->fsp_name); - if (fsp->mmap_size < MAX_MMAP_SIZE) { - fsp->mmap_ptr = (char *)sys_mmap(NULL,fsp->mmap_size, - PROT_READ,MAP_SHARED,fsp->fd_ptr->fd,(SMB_OFF_T)0); - - if (fsp->mmap_ptr == (char *)-1 || !fsp->mmap_ptr) { - DEBUG(3,("Failed to mmap() %s - %s\n", - fsp->fsp_name,strerror(errno))); - fsp->mmap_ptr = NULL; - } - } - } -#endif -} - -/**************************************************************************** C. Hoch 11/22/95 Helper for open_file_shared. Truncate a file after checking locking; close file if locked. **************************************************************************/ + static void truncate_unless_locked(files_struct *fsp, connection_struct *conn, int token, BOOL *share_locked) { @@ -606,19 +615,19 @@ static void truncate_unless_locked(files_struct *fsp, connection_struct *conn, i } } - enum {AFAIL,AREAD,AWRITE,AALL}; /******************************************************************* reproduce the share mode access table ********************************************************************/ + static int access_table(int new_deny,int old_deny,int old_mode, - int share_pid,char *fname) + pid_t share_pid,char *fname) { if (new_deny == DENY_ALL || old_deny == DENY_ALL) return(AFAIL); if (new_deny == DENY_DOS || old_deny == DENY_DOS) { - int pid = getpid(); + pid_t pid = getpid(); if (old_deny == new_deny && share_pid == pid) return(AALL); @@ -660,10 +669,10 @@ static int access_table(int new_deny,int old_deny,int old_mode, return(AFAIL); } - /**************************************************************************** check if we can open a file with a share mode ****************************************************************************/ + static int check_share_mode( share_mode_entry *share, int deny_mode, char *fname, BOOL fcbopen, int *flags) @@ -707,7 +716,7 @@ static int check_share_mode( share_mode_entry *share, int deny_mode, { DEBUG(2,("Share violation on file (%d,%d,%d,%d,%s,fcbopen = %d, flags = %d) = %d\n", deny_mode,old_deny_mode,old_open_mode, - share->pid,fname, fcbopen, *flags, access_allowed)); + (int)share->pid,fname, fcbopen, *flags, access_allowed)); unix_ERR_class = ERRDOS; unix_ERR_code = ERRbadshare; @@ -726,34 +735,39 @@ static int check_share_mode( share_mode_entry *share, int deny_mode, return True; } - /**************************************************************************** open a file with a share mode ****************************************************************************/ -void open_file_shared(files_struct *fsp, connection_struct *conn, - char *fname, int share_mode, int ofun, - mode_t mode, int oplock_request, int *Access, - int *action) + +void open_file_shared(files_struct *fsp,connection_struct *conn,char *fname,int share_mode,int ofun, + mode_t mode,int oplock_request, int *Access,int *action) { int flags=0; int flags2=0; int deny_mode = GET_DENY_MODE(share_mode); BOOL allow_share_delete = GET_ALLOW_SHARE_DELETE(share_mode); SMB_STRUCT_STAT sbuf; - BOOL file_existed = vfs_file_exist(conn, dos_to_unix(fname,False), &sbuf); + BOOL file_existed = dos_file_exist(fname,&sbuf); BOOL share_locked = False; BOOL fcbopen = False; - int token; + int token = 0; SMB_DEV_T dev = 0; SMB_INO_T inode = 0; int num_share_modes = 0; - + int oplock_contention_count = 0; + BOOL all_current_opens_are_level_II = False; fsp->open = False; fsp->fd_ptr = 0; DEBUG(10,("open_file_shared: fname = %s, share_mode = %x, ofun = %x, mode = %o, oplock request = %d\n", fname, share_mode, ofun, (int)mode, oplock_request )); + + /* ignore any oplock requests if oplocks are disabled */ + if (!lp_oplocks(SNUM(conn)) || global_client_failed_oplock_break) { + oplock_request = 0; + } + /* this is for OS/2 EAs - try and say we don't support them */ if (strstr(fname,".+,;=[].")) { @@ -861,6 +875,8 @@ void open_file_shared(files_struct *fsp, connection_struct *conn, { broke_oplock = False; + all_current_opens_are_level_II = True; + for(i = 0; i < num_share_modes; i++) { share_mode_entry *share_entry = &old_shares[i]; @@ -872,7 +888,8 @@ void open_file_shared(files_struct *fsp, connection_struct *conn, * Check if someone has an oplock on this file. If so we must break * it before continuing. */ - if(share_entry->op_type & (EXCLUSIVE_OPLOCK|BATCH_OPLOCK)) + if((oplock_request && EXCLUSIVE_OPLOCK_TYPE(share_entry->op_type)) || + (!oplock_request && (share_entry->op_type != NO_OPLOCK))) { DEBUG(5,("open_file_shared: breaking oplock (%x) on file %s, \ @@ -894,7 +911,10 @@ dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (dou } lock_share_entry(conn, dev, inode, &token); broke_oplock = True; + all_current_opens_are_level_II = False; break; + } else if (!LEVEL_II_OPLOCK_TYPE(share_entry->op_type)) { + all_current_opens_are_level_II = False; } /* someone else has a share lock on it, check to see @@ -913,6 +933,7 @@ dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (dou { free((char *)old_shares); num_share_modes = get_share_modes(conn, token, dev, inode, &old_shares); + oplock_contention_count++; } } while(broke_oplock); } @@ -921,6 +942,18 @@ dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (dou free((char *)old_shares); } + /* + * Refuse to grant an oplock in case the contention limit is + * reached when going through the lock list multiple times. + */ + + if(oplock_contention_count >= lp_oplock_contention_limit(SNUM(conn))) + { + oplock_request = 0; + DEBUG(4,("open_file_shared: oplock contention = %d. Not granting oplock.\n", + oplock_contention_count )); + } + DEBUG(4,("calling open_file with flags=0x%X flags2=0x%X mode=0%o\n", flags,flags2,(int)mode)); @@ -978,18 +1011,19 @@ dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (dou { uint16 port = 0; - /* JRA. Currently this only services Exlcusive and batch - oplocks (no other opens on this file). This needs to - be extended to level II oplocks (multiple reader - oplocks). */ + /* + * Setup the oplock info in both the shared memory and + * file structs. + */ - if((oplock_request) && (num_share_modes == 0) && lp_oplocks(SNUM(conn)) && - !IS_VETO_OPLOCK_PATH(conn,fname) && set_file_oplock(fsp) ) - { + if(oplock_request && (num_share_modes == 0) && + !IS_VETO_OPLOCK_PATH(conn,fname) && set_file_oplock(fsp, oplock_request) ) { port = global_oplock_port; - } - else - { + } else if (oplock_request && all_current_opens_are_level_II) { + port = global_oplock_port; + oplock_request = LEVEL_II_OPLOCK; + set_file_oplock(fsp, oplock_request); + } else { port = 0; oplock_request = 0; } @@ -999,13 +1033,6 @@ dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (dou if ((flags2&O_TRUNC) && file_existed) truncate_unless_locked(fsp,conn,token,&share_locked); - - /* - * Attempt to mmap a read only file. - * Moved until after a kernel oplock may - * be granted due to reference count issues. JRA. - */ - mmap_open_file(fsp); } if (share_locked && lp_share_modes(SNUM(conn))) @@ -1013,6 +1040,69 @@ dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (dou } /**************************************************************************** + Open a file for permissions read only. Return a pseudo file entry + with the 'stat_open' flag set and a fd_ptr of NULL. +****************************************************************************/ + +int open_file_stat(files_struct *fsp,connection_struct *conn, + char *fname, int smb_ofun, SMB_STRUCT_STAT *pst, int *action) +{ + extern struct current_user current_user; + + if(dos_stat(fname, pst) < 0) { + DEBUG(0,("open_file_stat: unable to stat name = %s. Error was %s\n", + fname, strerror(errno) )); + return -1; + } + + if(S_ISDIR(pst->st_mode)) { + DEBUG(0,("open_file_stat: %s is a directory !\n", fname )); + return -1; + } + + *action = FILE_WAS_OPENED; + + DEBUG(5,("open_file_stat: opening file %s as a stat entry\n", fname)); + + /* + * Setup the files_struct for it. + */ + + fsp->fd_ptr = NULL; + conn->num_files_open++; + fsp->mode = 0; + GetTimeOfDay(&fsp->open_time); + fsp->vuid = current_user.vuid; + fsp->size = 0; + fsp->pos = -1; + fsp->open = True; + fsp->can_lock = False; + fsp->can_read = False; + fsp->can_write = False; + fsp->share_mode = 0; + fsp->print_file = False; + fsp->modified = False; + fsp->oplock_type = NO_OPLOCK; + fsp->sent_oplock_break = NO_BREAK_SENT; + fsp->is_directory = False; + fsp->stat_open = True; + fsp->directory_delete_on_close = False; + fsp->conn = conn; + /* + * Note that the file name here is the *untranslated* name + * ie. it is still in the DOS codepage sent from the client. + * All use of this filename will pass though the sys_xxxx + * functions which will do the dos_to_unix translation before + * mapping into a UNIX filename. JRA. + */ + string_set(&fsp->fsp_name,fname); + fsp->wbmpx_ptr = NULL; + fsp->wcp = NULL; /* Write cache pointer. */ + + return 0; +} + +/**************************************************************************** Open a directory from an NT SMB call. ****************************************************************************/ @@ -1021,26 +1111,55 @@ int open_directory(files_struct *fsp,connection_struct *conn, { extern struct current_user current_user; SMB_STRUCT_STAT st; + BOOL got_stat = False; - if (smb_ofun & 0x10) { - /* - * Create the directory. - */ + if(dos_stat(fname, &st) == 0) { + got_stat = True; + } - if(conn->vfs_ops.mkdir(dos_to_unix(fname,False), - unix_mode(conn,aDIR)) < 0) { - DEBUG(0,("open_directory: unable to create %s. Error was %s\n", - fname, strerror(errno) )); - return -1; - } + if (got_stat && (GET_FILE_OPEN_DISPOSITION(smb_ofun) == FILE_EXISTS_FAIL)) { + errno = EEXIST; /* Setup so correct error is returned to client. */ + return -1; + } + + if (GET_FILE_CREATE_DISPOSITION(smb_ofun) == FILE_CREATE_IF_NOT_EXIST) { + + if (got_stat) { + + if(!S_ISDIR(st.st_mode)) { + DEBUG(0,("open_directory: %s is not a directory !\n", fname )); + errno = EACCES; + return -1; + } + *action = FILE_WAS_OPENED; + + } else { + + /* + * Try and create the directory. + */ + + if(!CAN_WRITE(conn)) { + DEBUG(2,("open_directory: failing create on read-only share\n")); + errno = EACCES; + return -1; + } - *action = FILE_WAS_CREATED; + if(dos_mkdir(fname, unix_mode(conn,aDIR)) < 0) { + DEBUG(0,("open_directory: unable to create %s. Error was %s\n", + fname, strerror(errno) )); + return -1; + } + *action = FILE_WAS_CREATED; + + } } else { + /* - * Check that it *was* a directory. + * Don't create - just check that it *was* a directory. */ - if(conn->vfs_ops.stat(dos_to_unix(fname,False), &st) < 0) { + if(!got_stat) { DEBUG(0,("open_directory: unable to stat name = %s. Error was %s\n", fname, strerror(errno) )); return -1; @@ -1050,6 +1169,7 @@ int open_directory(files_struct *fsp,connection_struct *conn, DEBUG(0,("open_directory: %s is not a directory !\n", fname )); return -1; } + *action = FILE_WAS_OPENED; } @@ -1068,17 +1188,16 @@ int open_directory(files_struct *fsp,connection_struct *conn, fsp->size = 0; fsp->pos = -1; fsp->open = True; - fsp->mmap_ptr = NULL; - fsp->mmap_size = 0; fsp->can_lock = True; fsp->can_read = False; fsp->can_write = False; fsp->share_mode = 0; fsp->print_file = False; fsp->modified = False; - fsp->granted_oplock = False; - fsp->sent_oplock_break = False; + fsp->oplock_type = NO_OPLOCK; + fsp->sent_oplock_break = NO_BREAK_SENT; fsp->is_directory = True; + fsp->directory_delete_on_close = False; fsp->conn = conn; /* * Note that the file name here is the *untranslated* name @@ -1093,10 +1212,9 @@ int open_directory(files_struct *fsp,connection_struct *conn, return 0; } - /******************************************************************* -check if the share mode on a file allows it to be deleted or unlinked -return True if sharing doesn't prevent the operation + Check if the share mode on a file allows it to be deleted or unlinked. + Return True if sharing doesn't prevent the operation. ********************************************************************/ BOOL check_file_sharing(connection_struct *conn,char *fname, BOOL rename_op) @@ -1107,14 +1225,14 @@ BOOL check_file_sharing(connection_struct *conn,char *fname, BOOL rename_op) int num_share_modes; SMB_STRUCT_STAT sbuf; int token; - int pid = getpid(); + pid_t pid = getpid(); SMB_DEV_T dev; SMB_INO_T inode; if(!lp_share_modes(SNUM(conn))) return True; - if (conn->vfs_ops.stat(dos_to_unix(fname,False),&sbuf) == -1) return(True); + if (dos_stat(fname,&sbuf) == -1) return(True); dev = sbuf.st_dev; inode = sbuf.st_ino; @@ -1144,9 +1262,16 @@ BOOL check_file_sharing(connection_struct *conn,char *fname, BOOL rename_op) * Check if someone has an oplock on this file. If so we must * break it before continuing. */ - if(share_entry->op_type & BATCH_OPLOCK) + if(BATCH_OPLOCK_TYPE(share_entry->op_type)) { +#if 0 + +/* JRA. Try removing this code to see if the new oplock changes + fix the problem. I'm dubious, but Andrew is recommending we + try this.... +*/ + /* * It appears that the NT redirector may have a bug, in that * it tries to do an SMBmv on a file that it has open with a @@ -1176,6 +1301,7 @@ batch oplocked file %s, dev = %x, inode = %.0f\n", fname, (unsigned int)dev, (do continue; } else +#endif /* 0 */ { DEBUG(5,("check_file_sharing: breaking oplock (%x) on file %s, \ |