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.c386
1 files changed, 256 insertions, 130 deletions
diff --git a/source3/smbd/open.c b/source3/smbd/open.c
index 2c12d425b9..4491082b2c 100644
--- a/source3/smbd/open.c
+++ b/source3/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, \