Author: jerry Date: 2007-05-23 22:46:30 +0000 (Wed, 23 May 2007) New Revision: 23101
WebSVN: http://websvn.samba.org/cgi-bin/viewcvs.cgi?view=rev&root=samba&rev=23101 Log: grab remainder of rename fixes Modified: branches/SAMBA_3_0_RELEASE/source/include/smb.h branches/SAMBA_3_0_RELEASE/source/locking/locking.c branches/SAMBA_3_0_RELEASE/source/smbd/open.c branches/SAMBA_3_0_RELEASE/source/smbd/reply.c branches/SAMBA_3_0_RELEASE/source/smbd/trans2.c Changeset: Modified: branches/SAMBA_3_0_RELEASE/source/include/smb.h =================================================================== --- branches/SAMBA_3_0_RELEASE/source/include/smb.h 2007-05-23 21:32:10 UTC (rev 23100) +++ branches/SAMBA_3_0_RELEASE/source/include/smb.h 2007-05-23 22:46:30 UTC (rev 23101) @@ -748,6 +748,7 @@ }; #define SHARE_MODE_FLAG_POSIX_OPEN 0x1 +#define SHARE_MODE_ALLOW_INITIAL_DELETE_ON_CLOSE 0x2 /* struct returned by get_share_modes */ struct share_mode_entry { @@ -765,7 +766,7 @@ SMB_INO_T inode; unsigned long share_file_id; uint32 uid; /* uid of file opener. */ - uint16 flags; /* POSIX_OPEN only defined so far... */ + uint16 flags; /* See SHARE_MODE_XX above. */ }; /* oplock break message definition - linearization of share_mode_entry. Modified: branches/SAMBA_3_0_RELEASE/source/locking/locking.c =================================================================== --- branches/SAMBA_3_0_RELEASE/source/locking/locking.c 2007-05-23 21:32:10 UTC (rev 23100) +++ branches/SAMBA_3_0_RELEASE/source/locking/locking.c 2007-05-23 22:46:30 UTC (rev 23101) @@ -993,10 +993,13 @@ } void set_share_mode(struct share_mode_lock *lck, files_struct *fsp, - uid_t uid, uint16 mid, uint16 op_type) + uid_t uid, uint16 mid, uint16 op_type, BOOL initial_delete_on_close_allowed) { struct share_mode_entry entry; fill_share_mode_entry(&entry, fsp, uid, mid, op_type); + if (initial_delete_on_close_allowed) { + entry.flags |= SHARE_MODE_ALLOW_INITIAL_DELETE_ON_CLOSE; + } add_share_mode_entry(lck, &entry); } @@ -1196,6 +1199,22 @@ return NT_STATUS_OK; } +/**************************************************************************** + Do we have an open file handle that created this entry ? +****************************************************************************/ + +BOOL can_set_initial_delete_on_close(const struct share_mode_lock *lck) +{ + int i; + + for (i=0; i<lck->num_share_modes; i++) { + if (lck->share_modes[i].flags & SHARE_MODE_ALLOW_INITIAL_DELETE_ON_CLOSE) { + return True; + } + } + return False; +} + /************************************************************************* Return a talloced copy of a UNIX_USER_TOKEN. NULL on fail. (Should this be in locking.c.... ?). @@ -1296,6 +1315,31 @@ return True; } +/**************************************************************************** + Sets the allow initial delete on close flag for this share mode. +****************************************************************************/ + +BOOL set_allow_initial_delete_on_close(struct share_mode_lock *lck, files_struct *fsp, BOOL delete_on_close) +{ + struct share_mode_entry entry, *e; + + /* Don't care about the pid owner being correct here - just a search. */ + fill_share_mode_entry(&entry, fsp, (uid_t)-1, 0, NO_OPLOCK); + + e = find_share_mode_entry(lck, &entry); + if (e == NULL) { + return False; + } + + if (delete_on_close) { + e->flags |= SHARE_MODE_ALLOW_INITIAL_DELETE_ON_CLOSE; + } else { + e->flags &= ~SHARE_MODE_ALLOW_INITIAL_DELETE_ON_CLOSE; + } + lck->modified = True; + return True; +} + struct forall_state { void (*fn)(const struct share_mode_entry *entry, const char *sharepath, Modified: branches/SAMBA_3_0_RELEASE/source/smbd/open.c =================================================================== --- branches/SAMBA_3_0_RELEASE/source/smbd/open.c 2007-05-23 21:32:10 UTC (rev 23100) +++ branches/SAMBA_3_0_RELEASE/source/smbd/open.c 2007-05-23 22:46:30 UTC (rev 23101) @@ -47,7 +47,12 @@ NTSTATUS status = NT_STATUS_OK; #ifdef O_NOFOLLOW - if (!lp_symlinks(SNUM(conn))) { + /* + * Never follow symlinks on a POSIX client. The + * client should be doing this. + */ + + if (fsp->posix_open || !lp_symlinks(SNUM(conn))) { flags |= O_NOFOLLOW; } #endif @@ -1120,6 +1125,7 @@ BOOL file_existed = VALID_STAT(*psbuf); BOOL def_acl = False; BOOL posix_open = False; + BOOL new_file_created = False; SMB_DEV_T dev = 0; SMB_INO_T inode = 0; NTSTATUS fsp_open = NT_STATUS_ACCESS_DENIED; @@ -1760,28 +1766,31 @@ fsp->oplock_type = NO_OPLOCK; } } - set_share_mode(lck, fsp, current_user.ut.uid, 0, fsp->oplock_type); - if (info == FILE_WAS_OVERWRITTEN || info == FILE_WAS_CREATED || - info == FILE_WAS_SUPERSEDED) { + if (info == FILE_WAS_OVERWRITTEN || info == FILE_WAS_CREATED || info == FILE_WAS_SUPERSEDED) { + new_file_created = True; + } - /* Handle strange delete on close create semantics. */ - if (create_options & FILE_DELETE_ON_CLOSE) { - status = can_set_delete_on_close(fsp, True, new_dos_attributes); + set_share_mode(lck, fsp, current_user.ut.uid, 0, fsp->oplock_type, new_file_created); - if (!NT_STATUS_IS_OK(status)) { - /* Remember to delete the mode we just added. */ - del_share_mode(lck, fsp); - TALLOC_FREE(lck); - fd_close(conn,fsp); - file_free(fsp); - return status; - } - /* Note that here we set the *inital* delete on close flag, - not the regular one. The magic gets handled in close. */ - fsp->initial_delete_on_close = True; + /* Handle strange delete on close create semantics. */ + if ((create_options & FILE_DELETE_ON_CLOSE) && can_set_initial_delete_on_close(lck)) { + status = can_set_delete_on_close(fsp, True, new_dos_attributes); + + if (!NT_STATUS_IS_OK(status)) { + /* Remember to delete the mode we just added. */ + del_share_mode(lck, fsp); + TALLOC_FREE(lck); + fd_close(conn,fsp); + file_free(fsp); + return status; } + /* Note that here we set the *inital* delete on close flag, + not the regular one. The magic gets handled in close. */ + fsp->initial_delete_on_close = True; + } + if (new_file_created) { /* Files should be initially set as archive */ if (lp_map_archive(SNUM(conn)) || lp_store_dos_attributes(SNUM(conn))) { @@ -2139,7 +2148,7 @@ return status; } - set_share_mode(lck, fsp, current_user.ut.uid, 0, NO_OPLOCK); + set_share_mode(lck, fsp, current_user.ut.uid, 0, NO_OPLOCK, True); /* For directories the delete on close bit at open time seems always to be honored on close... See test 19 in Samba4 BASE-DELETE. */ Modified: branches/SAMBA_3_0_RELEASE/source/smbd/reply.c =================================================================== --- branches/SAMBA_3_0_RELEASE/source/smbd/reply.c 2007-05-23 21:32:10 UTC (rev 23100) +++ branches/SAMBA_3_0_RELEASE/source/smbd/reply.c 2007-05-23 22:46:30 UTC (rev 23101) @@ -1790,7 +1790,7 @@ Check if a user is allowed to rename a file. ********************************************************************/ -static NTSTATUS can_rename(connection_struct *conn, char *fname, uint16 dirtype, SMB_STRUCT_STAT *pst) +static NTSTATUS can_rename(connection_struct *conn, char *fname, uint16 dirtype, SMB_STRUCT_STAT *pst, BOOL self_open) { files_struct *fsp; uint32 fmode; @@ -1811,7 +1811,10 @@ status = open_file_ntcreate(conn, fname, pst, DELETE_ACCESS, - FILE_SHARE_READ|FILE_SHARE_WRITE, + /* If we're checking our fsp don't deny for delete. */ + self_open ? + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE : + FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN, 0, FILE_ATTRIBUTE_NORMAL, @@ -4192,7 +4195,9 @@ ZERO_STRUCT(sbuf); status = unix_convert(conn, newname, False, newname_last_component, &sbuf); - if (!NT_STATUS_IS_OK(status)) { + /* We expect this to be NT_STATUS_OBJECT_PATH_NOT_FOUND */ + if (!NT_STATUS_EQUAL(NT_STATUS_OBJECT_PATH_NOT_FOUND, status)) { + return NT_STATUS_OBJECT_NAME_COLLISION; return status; } @@ -4260,9 +4265,20 @@ return NT_STATUS_OBJECT_NAME_COLLISION; } - status = can_rename(conn,fsp->fsp_name,attrs,&sbuf); + /* Ensure we have a valid stat struct for the source. */ + if (fsp->fh->fd != -1) { + if (SMB_VFS_FSTAT(fsp,fsp->fh->fd,&sbuf) == -1) { + return map_nt_error_from_unix(errno); + } + } else { + if (SMB_VFS_STAT(conn,fsp->fsp_name,&sbuf) == -1) { + return map_nt_error_from_unix(errno); + } + } - if (dest_exists && !NT_STATUS_IS_OK(status)) { + status = can_rename(conn,fsp->fsp_name,attrs,&sbuf,True); + + if (!NT_STATUS_IS_OK(status)) { DEBUG(3,("rename_internals_fsp: Error %s rename %s -> %s\n", nt_errstr(status), fsp->fsp_name,newname)); if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION)) @@ -4277,9 +4293,33 @@ lck = get_share_mode_lock(NULL, fsp->dev, fsp->inode, NULL, NULL); if(SMB_VFS_RENAME(conn,fsp->fsp_name, newname) == 0) { + uint32 create_options = fsp->fh->private_options; + DEBUG(3,("rename_internals_fsp: succeeded doing rename on %s -> %s\n", fsp->fsp_name,newname)); + rename_open_files(conn, lck, fsp->dev, fsp->inode, newname); + + /* + * A rename acts as a new file create w.r.t. allowing an initial delete + * on close, probably because in Windows there is a new handle to the + * new file. If initial delete on close was requested but not + * originally set, we need to set it here. This is probably not 100% correct, + * but will work for the CIFSFS client which in non-posix mode + * depends on these semantics. JRA. + */ + + set_allow_initial_delete_on_close(lck, fsp, True); + + if (create_options & FILE_DELETE_ON_CLOSE) { + status = can_set_delete_on_close(fsp, True, 0); + + if (NT_STATUS_IS_OK(status)) { + /* Note that here we set the *inital* delete on close flag, + * not the regular one. The magic gets handled in close. */ + fsp->initial_delete_on_close = True; + } + } TALLOC_FREE(lck); return NT_STATUS_OK; } @@ -4530,7 +4570,7 @@ return status; } - status = can_rename(conn,directory,attrs,&sbuf1); + status = can_rename(conn,directory,attrs,&sbuf1,False); if (!NT_STATUS_IS_OK(status)) { DEBUG(3,("rename_internals: Error %s rename %s -> " @@ -4658,7 +4698,7 @@ fname, nt_errstr(status))); continue; } - status = can_rename(conn,fname,attrs,&sbuf1); + status = can_rename(conn,fname,attrs,&sbuf1,False); if (!NT_STATUS_IS_OK(status)) { DEBUG(6, ("rename %s refused\n", fname)); continue; Modified: branches/SAMBA_3_0_RELEASE/source/smbd/trans2.c =================================================================== --- branches/SAMBA_3_0_RELEASE/source/smbd/trans2.c 2007-05-23 21:32:10 UTC (rev 23100) +++ branches/SAMBA_3_0_RELEASE/source/smbd/trans2.c 2007-05-23 22:46:30 UTC (rev 23101) @@ -4507,10 +4507,11 @@ pstrcpy(base_name, fname); p = strrchr_m(base_name, '/'); if (p) { - *p = '\0'; + p[1] = '\0'; + } else { + pstrcpy(base_name, "./"); } /* Append the new name. */ - pstrcat(base_name, "/"); pstrcat(base_name, newname); if (fsp) { @@ -5632,9 +5633,17 @@ * to do this call. JRA. */ pstrcpy(fname, fsp->fsp_name); - if (SMB_VFS_STAT(conn,fname,&sbuf) != 0) { - DEBUG(3,("call_trans2setfilepathinfo: fileinfo of %s failed (%s)\n",fname,strerror(errno))); - return UNIXERROR(ERRDOS,ERRbadpath); + if (INFO_LEVEL_IS_UNIX(info_level)) { + /* Always do lstat for UNIX calls. */ + if (SMB_VFS_LSTAT(conn,fname,&sbuf)) { + DEBUG(3,("call_trans2setfilepathinfo: SMB_VFS_LSTAT of %s failed (%s)\n",fname,strerror(errno))); + return UNIXERROR(ERRDOS,ERRbadpath); + } + } else { + if (SMB_VFS_STAT(conn,fname,&sbuf) != 0) { + DEBUG(3,("call_trans2setfilepathinfo: fileinfo of %s failed (%s)\n",fname,strerror(errno))); + return UNIXERROR(ERRDOS,ERRbadpath); + } } } else if (fsp && fsp->print_file) { /* @@ -5693,14 +5702,18 @@ return ERROR_NT(status); } - /* - * For CIFS UNIX extensions the target name may not exist. - */ + if (INFO_LEVEL_IS_UNIX(info_level)) { + /* + * For CIFS UNIX extensions the target name may not exist. + */ - if(!VALID_STAT(sbuf) && !INFO_LEVEL_IS_UNIX(info_level)) { - DEBUG(3,("call_trans2setfilepathinfo: stat of %s failed (%s)\n", fname, strerror(errno))); + /* Always do lstat for UNIX calls. */ + SMB_VFS_LSTAT(conn,fname,&sbuf); + + } else if (!VALID_STAT(sbuf) && SMB_VFS_STAT(conn,fname,&sbuf)) { + DEBUG(3,("call_trans2setfilepathinfo: SMB_VFS_STAT of %s failed (%s)\n",fname,strerror(errno))); return UNIXERROR(ERRDOS,ERRbadpath); - } + } } if (!CAN_WRITE(conn)) {