diff options
author | Jeremy Allison <jra@samba.org> | 2007-01-31 00:49:49 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 12:17:32 -0500 |
commit | 44da8a6907882bd90d56daf4b712ebb073869596 (patch) | |
tree | 6bbe91fd794f77de6adb5c3f61563028deb89002 /source3/smbd | |
parent | caf8c6a76be051559ffcfe97084edca43e0a3cee (diff) | |
download | samba-44da8a6907882bd90d56daf4b712ebb073869596.tar.gz samba-44da8a6907882bd90d56daf4b712ebb073869596.tar.bz2 samba-44da8a6907882bd90d56daf4b712ebb073869596.zip |
r21067: Finished refactoring setqpathinfo to be readable
and modifiable by other people. Now to look over
the build farm and fix any breakage.
Jeremy.
(This used to be commit 997259f2479842ee888621ae2d5446797b3a7cb6)
Diffstat (limited to 'source3/smbd')
-rw-r--r-- | source3/smbd/trans2.c | 815 |
1 files changed, 430 insertions, 385 deletions
diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index 826ccd3f92..9af25d95d6 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -3742,6 +3742,162 @@ NTSTATUS hardlink_internals(connection_struct *conn, pstring oldname, pstring ne } /**************************************************************************** + Deal with setting the time from any of the setfilepathinfo functions. +****************************************************************************/ + +static NTSTATUS smb_set_file_time(connection_struct *conn, + files_struct *fsp, + const char *fname, + const SMB_STRUCT_STAT *psbuf, + struct utimbuf tvs) +{ + if (!VALID_STAT(*psbuf)) { + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + } + + /* get some defaults (no modifications) if any info is zero or -1. */ + if (null_mtime(tvs.actime)) { + tvs.actime = psbuf->st_atime; + } + + if (null_mtime(tvs.modtime)) { + tvs.modtime = psbuf->st_mtime; + } + + DEBUG(6,("smb_set_file_time: actime: %s " , ctime(&tvs.actime))); + DEBUG(6,("smb_set_file_time: modtime: %s ", ctime(&tvs.modtime))); + + /* + * Try and set the times of this file if + * they are different from the current values. + */ + + if (psbuf->st_mtime == tvs.modtime && psbuf->st_atime == tvs.actime) { + return NT_STATUS_OK; + } + + if(fsp != NULL) { + /* + * This was a setfileinfo on an open file. + * NT does this a lot. We also need to + * set the time here, as it can be read by + * FindFirst/FindNext and with the patch for bug #2045 + * in smbd/fileio.c it ensures that this timestamp is + * kept sticky even after a write. We save the request + * away and will set it on file close and after a write. JRA. + */ + + if (tvs.modtime != (time_t)0 && tvs.modtime != (time_t)-1) { + DEBUG(10,("smb_set_file_time: setting pending modtime to %s\n", ctime(&tvs.modtime) )); + fsp_set_pending_modtime(fsp, tvs.modtime); + } + + } + DEBUG(10,("smb_set_file_time: setting utimes to modified values.\n")); + + if(file_utime(conn, fname, &tvs)!=0) { + return map_nt_error_from_unix(errno); + } + return NT_STATUS_OK; +} + +/**************************************************************************** + Deal with setting the dosmode from any of the setfilepathinfo functions. +****************************************************************************/ + +static NTSTATUS smb_set_file_dosmode(connection_struct *conn, + const char *fname, + SMB_STRUCT_STAT *psbuf, + uint32 dosmode) +{ + if (!VALID_STAT(*psbuf)) { + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + } + + if (dosmode) { + if (S_ISDIR(psbuf->st_mode)) { + dosmode |= aDIR; + } else { + dosmode &= ~aDIR; + } + } + + DEBUG(6,("smb_set_file_dosmode: dosmode: 0x%x\n", (unsigned int)dosmode)); + + /* check the mode isn't different, before changing it */ + if ((dosmode != 0) && (dosmode != dos_mode(conn, fname, psbuf))) { + + DEBUG(10,("smb_set_file_dosmode: file %s : setting dos mode 0x%x\n", + fname, (unsigned int)dosmode )); + + if(file_set_dosmode(conn, fname, dosmode, psbuf, False)) { + DEBUG(2,("smb_set_file_dosmode: file_set_dosmode of %s failed (%s)\n", + fname, strerror(errno))); + return map_nt_error_from_unix(errno); + } + } + return NT_STATUS_OK; +} + +/**************************************************************************** + Deal with setting the size from any of the setfilepathinfo functions. +****************************************************************************/ + +static NTSTATUS smb_set_file_size(connection_struct *conn, + files_struct *fsp, + const char *fname, + SMB_STRUCT_STAT *psbuf, + SMB_OFF_T size) +{ + NTSTATUS status = NT_STATUS_OK; + files_struct *new_fsp = NULL; + + if (!VALID_STAT(*psbuf)) { + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + } + + DEBUG(6,("smb_set_file_size: size: %.0f ", (double)size)); + + if (size == get_file_size(*psbuf)) { + return NT_STATUS_OK; + } + + DEBUG(10,("call_trans2setfilepathinfo: file %s : setting new size to %.0f\n", + fname, (double)size )); + + if (fsp && fsp->fh->fd != -1) { + /* Handle based call. */ + if (vfs_set_filelen(fsp, size) == -1) { + return map_nt_error_from_unix(errno); + } + return NT_STATUS_OK; + } + + status = open_file_ntcreate(conn, fname, psbuf, + FILE_WRITE_DATA, + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, + FILE_OPEN, + 0, + FILE_ATTRIBUTE_NORMAL, + FORCE_OPLOCK_BREAK_TO_NONE, + NULL, &new_fsp); + + if (!NT_STATUS_IS_OK(status)) { + /* NB. We check for open_was_deferred in the caller. */ + return status; + } + + if (vfs_set_filelen(new_fsp, size) == -1) { + status = map_nt_error_from_unix(errno); + close_file(new_fsp,NORMAL_CLOSE); + return status; + } + + close_file(new_fsp,NORMAL_CLOSE); + return NT_STATUS_OK; +} + +/**************************************************************************** Deal with SMB_INFO_SET_EA. ****************************************************************************/ @@ -3797,10 +3953,12 @@ static NTSTATUS smb_set_file_disposition_info(connection_struct *conn, const char *pdata, int total_data, files_struct *fsp, - int dosmode) + const char *fname, + SMB_STRUCT_STAT *psbuf) { NTSTATUS status = NT_STATUS_OK; BOOL delete_on_close; + uint32 dosmode = 0; if (total_data < 1) { return NT_STATUS_INVALID_PARAMETER; @@ -3811,6 +3969,7 @@ static NTSTATUS smb_set_file_disposition_info(connection_struct *conn, } delete_on_close = (CVAL(pdata,0) ? True : False); + dosmode = dos_mode(conn, fname, psbuf); status = can_set_delete_on_close(fsp, delete_on_close, dosmode); @@ -4049,8 +4208,8 @@ static NTSTATUS smb_set_posix_acl(connection_struct *conn, const char *pdata, int total_data, files_struct *fsp, - SMB_STRUCT_STAT *psbuf, - const char *fname) + const char *fname, + SMB_STRUCT_STAT *psbuf) { uint16 posix_acl_version; uint16 num_file_acls; @@ -4211,59 +4370,86 @@ static NTSTATUS smb_set_posix_lock(connection_struct *conn, Deal with SMB_INFO_STANDARD. ****************************************************************************/ -static NTSTATUS smb_set_info_standard(const char *pdata, +static NTSTATUS smb_set_info_standard(connection_struct *conn, + const char *pdata, int total_data, - struct utimbuf *p_tvs) + files_struct *fsp, + const char *fname, + const SMB_STRUCT_STAT *psbuf) { + struct utimbuf tvs; + if (total_data < 12) { return NT_STATUS_INVALID_PARAMETER; } /* access time */ - p_tvs->actime = srv_make_unix_date2(pdata+l1_fdateLastAccess); + tvs.actime = srv_make_unix_date2(pdata+l1_fdateLastAccess); /* write time */ - p_tvs->modtime = srv_make_unix_date2(pdata+l1_fdateLastWrite); - return NT_STATUS_OK; + tvs.modtime = srv_make_unix_date2(pdata+l1_fdateLastWrite); + + return smb_set_file_time(conn, + fsp, + fname, + psbuf, + tvs); } /**************************************************************************** Deal with SMB_SET_FILE_BASIC_INFO. ****************************************************************************/ -static NTSTATUS smb_set_file_basic_info(const char *pdata, +static NTSTATUS smb_set_file_basic_info(connection_struct *conn, + const char *pdata, int total_data, - struct utimbuf *p_tvs, - int *p_dosmode) + files_struct *fsp, + const char *fname, + SMB_STRUCT_STAT *psbuf) { /* Patch to do this correctly from Paul Eggert <eggert@twinsun.com>. */ time_t write_time; time_t changed_time; + uint32 dosmode = 0; + struct utimbuf tvs; + NTSTATUS status = NT_STATUS_OK; if (total_data < 36) { return NT_STATUS_INVALID_PARAMETER; } + /* Set the attributes */ + dosmode = IVAL(pdata,32); + status = smb_set_file_dosmode(conn, + fname, + psbuf, + dosmode); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + /* Ignore create time at offset pdata. */ /* access time */ - p_tvs->actime = convert_timespec_to_time_t(interpret_long_date(pdata+8)); + tvs.actime = convert_timespec_to_time_t(interpret_long_date(pdata+8)); write_time = convert_timespec_to_time_t(interpret_long_date(pdata+16)); changed_time = convert_timespec_to_time_t(interpret_long_date(pdata+24)); - p_tvs->modtime = MIN(write_time, changed_time); + tvs.modtime = MIN(write_time, changed_time); - if (write_time > p_tvs->modtime && write_time != (time_t)-1) { - p_tvs->modtime = write_time; + if (write_time > tvs.modtime && write_time != (time_t)-1) { + tvs.modtime = write_time; } /* Prefer a defined time to an undefined one. */ - if (null_mtime(p_tvs->modtime)) { - p_tvs->modtime = null_mtime(write_time) ? changed_time : write_time; + if (null_mtime(tvs.modtime)) { + tvs.modtime = null_mtime(write_time) ? changed_time : write_time; } - /* attributes */ - *p_dosmode = IVAL(pdata,32); - return NT_STATUS_OK; + return smb_set_file_time(conn, + fsp, + fname, + psbuf, + tvs); } /**************************************************************************** @@ -4275,10 +4461,15 @@ static NTSTATUS smb_set_file_allocation_info(connection_struct *conn, int total_data, files_struct *fsp, const char *fname, - SMB_STRUCT_STAT *psbuf, - SMB_OFF_T *p_size) + SMB_STRUCT_STAT *psbuf) { - SMB_BIG_UINT allocation_size; + SMB_BIG_UINT allocation_size = 0; + NTSTATUS status = NT_STATUS_OK; + files_struct *new_fsp = NULL; + + if (!VALID_STAT(*psbuf)) { + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + } if (total_data < 8) { return NT_STATUS_INVALID_PARAMETER; @@ -4301,61 +4492,43 @@ static NTSTATUS smb_set_file_allocation_info(connection_struct *conn, allocation_size = smb_roundup(conn, allocation_size); } - if(allocation_size != get_file_size(*psbuf)) { - int ret = -1; - SMB_STRUCT_STAT new_sbuf; + if(allocation_size == get_file_size(*psbuf)) { + return NT_STATUS_OK; + } - DEBUG(10,("smb_set_file_allocation_info: file %s : setting new allocation size to %.0f\n", + DEBUG(10,("smb_set_file_allocation_info: file %s : setting new allocation size to %.0f\n", fname, (double)allocation_size )); - if (fsp && fsp->fh->fd != -1) { - /* Open file. */ - ret = vfs_allocate_file_space(fsp, allocation_size); - if (ret == -1) { - return map_nt_error_from_unix(errno); - } - if (SMB_VFS_FSTAT(fsp,fsp->fh->fd,&new_sbuf) != 0) { - DEBUG(3,("smb_set_file_allocation_info: fstat of fnum %d failed (%s)\n", - fsp->fnum, strerror(errno))); - return map_nt_error_from_unix(errno); - } - } else { - /* Pathname or stat or directory file. */ - files_struct *new_fsp = NULL; - NTSTATUS status; - - status = open_file_ntcreate(conn, fname, psbuf, - FILE_WRITE_DATA, - FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, - FILE_OPEN, - 0, - FILE_ATTRIBUTE_NORMAL, - FORCE_OPLOCK_BREAK_TO_NONE, - NULL, &new_fsp); - - if (!NT_STATUS_IS_OK(status)) { - /* NB. We check for open_was_deferred in the caller. */ - return status; - } - ret = vfs_allocate_file_space(new_fsp, allocation_size); - if (ret == -1) { - status = map_nt_error_from_unix(errno); - close_file(new_fsp,NORMAL_CLOSE); - return status; - } - if (SMB_VFS_FSTAT(new_fsp,new_fsp->fh->fd,&new_sbuf) != 0) { - DEBUG(3,("smb_set_file_allocation_info: fstat of fnum %d failed (%s)\n", - new_fsp->fnum, strerror(errno))); - status = map_nt_error_from_unix(errno); - close_file(new_fsp,NORMAL_CLOSE); - return status; - } - close_file(new_fsp,NORMAL_CLOSE); + if (fsp && fsp->fh->fd != -1) { + /* Open file handle. */ + if (vfs_allocate_file_space(fsp, allocation_size) == -1) { + return map_nt_error_from_unix(errno); } + return NT_STATUS_OK; + } + + /* Pathname or stat or directory file. */ - /* Allocate can truncate size... */ - *p_size = get_file_size(new_sbuf); + status = open_file_ntcreate(conn, fname, psbuf, + FILE_WRITE_DATA, + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, + FILE_OPEN, + 0, + FILE_ATTRIBUTE_NORMAL, + FORCE_OPLOCK_BREAK_TO_NONE, + NULL, &new_fsp); + + if (!NT_STATUS_IS_OK(status)) { + /* NB. We check for open_was_deferred in the caller. */ + return status; } + if (vfs_allocate_file_space(new_fsp, allocation_size) == -1) { + status = map_nt_error_from_unix(errno); + close_file(new_fsp,NORMAL_CLOSE); + return status; + } + + close_file(new_fsp,NORMAL_CLOSE); return NT_STATUS_OK; } @@ -4366,16 +4539,19 @@ static NTSTATUS smb_set_file_allocation_info(connection_struct *conn, static NTSTATUS smb_set_file_end_of_file_info(connection_struct *conn, const char *pdata, int total_data, + files_struct *fsp, const char *fname, - SMB_OFF_T *p_size) + SMB_STRUCT_STAT *psbuf) { + SMB_OFF_T size; + if (total_data < 8) { return NT_STATUS_INVALID_PARAMETER; } - *p_size = IVAL(pdata,0); + size = IVAL(pdata,0); #ifdef LARGE_SMB_OFF_T - *p_size |= (((SMB_OFF_T)IVAL(pdata,4)) << 32); + size |= (((SMB_OFF_T)IVAL(pdata,4)) << 32); #else /* LARGE_SMB_OFF_T */ if (IVAL(pdata,4) != 0) { /* more than 32 bits? */ @@ -4383,7 +4559,96 @@ static NTSTATUS smb_set_file_end_of_file_info(connection_struct *conn, } #endif /* LARGE_SMB_OFF_T */ DEBUG(10,("smb_set_file_end_of_file_info: Set end of file info for " - "file %s to %.0f\n", fname, (double)*p_size )); + "file %s to %.0f\n", fname, (double)size )); + + return smb_set_file_size(conn, + fsp, + fname, + psbuf, + size); +} + +/**************************************************************************** + Allow a UNIX info mknod. +****************************************************************************/ + +static NTSTATUS smb_unix_mknod(connection_struct *conn, + const char *pdata, + int total_data, + const char *fname, + SMB_STRUCT_STAT *psbuf) +{ + uint32 file_type = IVAL(pdata,56); +#if defined(HAVE_MAKEDEV) + uint32 dev_major = IVAL(pdata,60); + uint32 dev_minor = IVAL(pdata,68); +#endif + SMB_DEV_T dev = (SMB_DEV_T)0; + uint32 raw_unixmode = IVAL(pdata,84); + mode_t unixmode; + + if (total_data < 100) { + return NT_STATUS_INVALID_PARAMETER; + } + + if (raw_unixmode == SMB_MODE_NO_CHANGE) { + return NT_STATUS_INVALID_PARAMETER; + } + + unixmode = unix_perms_from_wire(conn, psbuf, raw_unixmode); + +#if defined(HAVE_MAKEDEV) + dev = makedev(dev_major, dev_minor); +#endif + + switch (file_type) { +#if defined(S_IFIFO) + case UNIX_TYPE_FIFO: + unixmode |= S_IFIFO; + break; +#endif +#if defined(S_IFSOCK) + case UNIX_TYPE_SOCKET: + unixmode |= S_IFSOCK; + break; +#endif +#if defined(S_IFCHR) + case UNIX_TYPE_CHARDEV: + unixmode |= S_IFCHR; + break; +#endif +#if defined(S_IFBLK) + case UNIX_TYPE_BLKDEV: + unixmode |= S_IFBLK; + break; +#endif + default: + return NT_STATUS_INVALID_PARAMETER; + } + + DEBUG(10,("smb_unix_mknod: SMB_SET_FILE_UNIX_BASIC doing mknod dev %.0f mode \ +0%o for file %s\n", (double)dev, (unsigned int)unixmode, fname )); + + /* Ok - do the mknod. */ + if (SMB_VFS_MKNOD(conn, fname, unixmode, dev) != 0) { + return map_nt_error_from_unix(errno); + } + + /* If any of the other "set" calls fail we + * don't want to end up with a half-constructed mknod. + */ + + if (lp_inherit_perms(SNUM(conn))) { + inherit_access_acl( + conn, parent_dirname(fname), + fname, unixmode); + } + + if (SMB_VFS_STAT(conn, fname, psbuf) != 0) { + NTSTATUS status = map_nt_error_from_unix(errno); + SMB_VFS_UNLINK(conn,fname); + return status; + } return NT_STATUS_OK; } @@ -4396,30 +4661,26 @@ static NTSTATUS smb_set_file_unix_basic(connection_struct *conn, int total_data, files_struct *fsp, const char *fname, - SMB_STRUCT_STAT *psbuf, - SMB_OFF_T *p_size, - struct utimbuf *p_tvs, - mode_t *p_unixmode, - int *p_dosmode) + SMB_STRUCT_STAT *psbuf) { + struct utimbuf tvs; + uint32 raw_unixmode; + mode_t unixmode; + SMB_OFF_T size = 0; uid_t set_owner = (uid_t)SMB_UID_NO_CHANGE; gid_t set_grp = (uid_t)SMB_GID_NO_CHANGE; - uint32 raw_unixmode; - BOOL delete_on_fail = False; NTSTATUS status = NT_STATUS_OK; + BOOL delete_on_fail = False; if (total_data < 100) { return NT_STATUS_INVALID_PARAMETER; } - set_owner = VALID_STAT(*psbuf) ? psbuf->st_uid : (uid_t)SMB_UID_NO_CHANGE; - set_grp = VALID_STAT(*psbuf) ? psbuf->st_gid : (gid_t)SMB_GID_NO_CHANGE; - if(IVAL(pdata, 0) != SMB_SIZE_NO_CHANGE_LO && IVAL(pdata, 4) != SMB_SIZE_NO_CHANGE_HI) { - *p_size=IVAL(pdata,0); /* first 8 Bytes are size */ + size=IVAL(pdata,0); /* first 8 Bytes are size */ #ifdef LARGE_SMB_OFF_T - *p_size |= (((SMB_OFF_T)IVAL(pdata,4)) << 32); + size |= (((SMB_OFF_T)IVAL(pdata,4)) << 32); #else /* LARGE_SMB_OFF_T */ if (IVAL(pdata,4) != 0) { /* more than 32 bits? */ @@ -4428,102 +4689,43 @@ static NTSTATUS smb_set_file_unix_basic(connection_struct *conn, #endif /* LARGE_SMB_OFF_T */ } - pdata+=24; /* ctime & st_blocks are not changed */ - p_tvs->actime = convert_timespec_to_time_t(interpret_long_date(pdata)); /* access_time */ - p_tvs->modtime = convert_timespec_to_time_t(interpret_long_date(pdata+8)); /* modification_time */ - pdata+=16; - set_owner = (uid_t)IVAL(pdata,0); - pdata += 8; - set_grp = (gid_t)IVAL(pdata,0); - pdata += 8; - raw_unixmode = IVAL(pdata,28); - *p_unixmode = unix_perms_from_wire(conn, psbuf, raw_unixmode); - *p_dosmode = 0; /* Ensure dos mode change doesn't override this. */ + tvs.actime = convert_timespec_to_time_t(interpret_long_date(pdata+24)); /* access_time */ + tvs.modtime = convert_timespec_to_time_t(interpret_long_date(pdata+32)); /* modification_time */ + set_owner = (uid_t)IVAL(pdata,40); + set_grp = (gid_t)IVAL(pdata,48); + raw_unixmode = IVAL(pdata,84); + unixmode = unix_perms_from_wire(conn, psbuf, raw_unixmode); DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC: name = %s \ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n", - fname, (double)*p_size, (unsigned int)set_owner, (unsigned int)set_grp, (int)raw_unixmode)); + fname, (double)size, (unsigned int)set_owner, (unsigned int)set_grp, (int)raw_unixmode)); if (!VALID_STAT(*psbuf)) { - /* * The only valid use of this is to create character and block * devices, and named pipes. This is deprecated (IMHO) and * a new info level should be used for mknod. JRA. */ - uint32 file_type = IVAL(pdata,0); -#if defined(HAVE_MAKEDEV) - uint32 dev_major = IVAL(pdata,4); - uint32 dev_minor = IVAL(pdata,12); -#endif - - SMB_DEV_T dev = (SMB_DEV_T)0; - - if (raw_unixmode == SMB_MODE_NO_CHANGE) { - return NT_STATUS_INVALID_PARAMETER; - } - -#if defined(HAVE_MAKEDEV) - dev = makedev(dev_major, dev_minor); -#endif - - switch (file_type) { -#if defined(S_IFIFO) - case UNIX_TYPE_FIFO: - *p_unixmode |= S_IFIFO; - break; -#endif -#if defined(S_IFSOCK) - case UNIX_TYPE_SOCKET: - *p_unixmode |= S_IFSOCK; - break; -#endif -#if defined(S_IFCHR) - case UNIX_TYPE_CHARDEV: - *p_unixmode |= S_IFCHR; - break; -#endif -#if defined(S_IFBLK) - case UNIX_TYPE_BLKDEV: - *p_unixmode |= S_IFBLK; - break; -#endif - default: - return NT_STATUS_INVALID_PARAMETER; - } - - DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC doing mknod dev %.0f mode \ -0%o for file %s\n", (double)dev, *p_unixmode, fname )); - - /* Ok - do the mknod. */ - if (SMB_VFS_MKNOD(conn, fname, *p_unixmode, dev) != 0) { - return map_nt_error_from_unix(errno); - } - - /* If any of the other "set" calls fail we - * don't want to end up with a half-constructed mknod. - */ - - delete_on_fail = True; - - if (lp_inherit_perms(SNUM(conn))) { - inherit_access_acl( - conn, parent_dirname(fname), - fname, *p_unixmode); - } - - if (SMB_VFS_STAT(conn, fname, psbuf) != 0) { - status = map_nt_error_from_unix(errno); - SMB_VFS_UNLINK(conn,fname); + status = smb_unix_mknod(conn, + pdata, + total_data, + fname, + psbuf); + if (!NT_STATUS_IS_OK(status)) { return status; } /* Ensure we don't try and change anything else. */ raw_unixmode = SMB_MODE_NO_CHANGE; - *p_size = get_file_size(*psbuf); - p_tvs->modtime = psbuf->st_mtime; - p_tvs->actime = psbuf->st_atime; + size = get_file_size(*psbuf); + tvs.modtime = psbuf->st_mtime; + tvs.actime = psbuf->st_atime; + /* + * We continue here as we might want to change the + * owner uid/gid. + */ + delete_on_fail = True; } /* @@ -4532,8 +4734,8 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n", if (raw_unixmode != SMB_MODE_NO_CHANGE) { DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC setting mode 0%o for file %s\n", - (unsigned int)*p_unixmode, fname )); - if (SMB_VFS_CHMOD(conn,fname,*p_unixmode) != 0) { + (unsigned int)unixmode, fname )); + if (SMB_VFS_CHMOD(conn, fname, unixmode) != 0) { return map_nt_error_from_unix(errno); } } @@ -4569,7 +4771,25 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n", return status; } } - return NT_STATUS_OK; + + /* Deal with any size changes. */ + + status = smb_set_file_size(conn, + fsp, + fname, + psbuf, + size); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + /* Deal with any time changes. */ + + return smb_set_file_time(conn, + fsp, + fname, + psbuf, + tvs); } /**************************************************************************** @@ -4584,14 +4804,9 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char char *params = *pparams; char *pdata = *ppdata; uint16 info_level; - int dosmode=0; - SMB_OFF_T size=0; - struct utimbuf tvs; SMB_STRUCT_STAT sbuf; pstring fname; - int fd = -1; files_struct *fsp = NULL; - mode_t unixmode = 0; NTSTATUS status = NT_STATUS_OK; if (!params) { @@ -4599,7 +4814,6 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char } ZERO_STRUCT(sbuf); - ZERO_STRUCT(tvs); if (tran_call == TRANSACT2_SETFILEINFO) { if (total_params < 4) { @@ -4641,9 +4855,8 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char CHECK_FSP(fsp,conn); pstrcpy(fname, fsp->fsp_name); - fd = fsp->fh->fd; - if (SMB_VFS_FSTAT(fsp,fd,&sbuf) != 0) { + if (SMB_VFS_FSTAT(fsp, fsp->fh->fd, &sbuf) != 0) { DEBUG(3,("call_trans2setfilepathinfo: fstat of fnum %d failed (%s)\n",fsp->fnum, strerror(errno))); return(UNIXERROR(ERRDOS,ERRbadfid)); } @@ -4680,17 +4893,14 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char } - if (!CAN_WRITE(conn)) + if (!CAN_WRITE(conn)) { return ERROR_DOS(ERRSRV,ERRaccess); + } if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) { return ERROR_NT(NT_STATUS_INVALID_LEVEL); } - if (VALID_STAT(sbuf)) { - unixmode = sbuf.st_mode; - } - DEBUG(3,("call_trans2setfilepathinfo(%d) %s (fnum %d) info_level=%d totdata=%d\n", tran_call,fname, fsp ? fsp->fnum : -1, info_level,total_data)); @@ -4708,22 +4918,16 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char sbuf.st_mtime = fsp->pending_modtime; } - size = get_file_size(sbuf); - tvs.modtime = sbuf.st_mtime; - tvs.actime = sbuf.st_atime; - dosmode = dos_mode(conn,fname,&sbuf); - unixmode = sbuf.st_mode; - switch (info_level) { case SMB_INFO_STANDARD: { - status = smb_set_info_standard(pdata, - total_data, - &tvs); - if (!NT_STATUS_IS_OK(status)) { - return ERROR_NT(status); - } + status = smb_set_info_standard(conn, + pdata, + total_data, + fsp, + fname, + &sbuf); break; } @@ -4734,22 +4938,18 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char total_data, fsp, fname); - if (!NT_STATUS_IS_OK(status)) { - return ERROR_NT(status); - } - goto out; + break; } case SMB_SET_FILE_BASIC_INFO: case SMB_FILE_BASIC_INFORMATION: { - status = smb_set_file_basic_info(pdata, + status = smb_set_file_basic_info(conn, + pdata, total_data, - &tvs, - &dosmode); - if (!NT_STATUS_IS_OK(status)) { - return ERROR_NT(status); - } + fsp, + fname, + &sbuf); break; } @@ -4761,15 +4961,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char total_data, fsp, fname, - &sbuf, - &size); - if (!NT_STATUS_IS_OK(status)) { - if (open_was_deferred(SVAL(inbuf,smb_mid))) { - /* We have re-scheduled this call. */ - return -1; - } - return ERROR_NT(status); - } + &sbuf); break; } @@ -4779,11 +4971,9 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char status = smb_set_file_end_of_file_info(conn, pdata, total_data, + fsp, fname, - &size); - if (!NT_STATUS_IS_OK(status)) { - return ERROR_NT(status); - } + &sbuf); break; } @@ -4803,11 +4993,9 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char pdata, total_data, fsp, - dosmode); - if (!NT_STATUS_IS_OK(status)) { - return ERROR_NT(status); - } - goto out; + fname, + &sbuf); + break; } case SMB_FILE_POSITION_INFORMATION: @@ -4816,10 +5004,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char pdata, total_data, fsp); - if (!NT_STATUS_IS_OK(status)) { - return ERROR_NT(status); - } - goto out; + break; } /* From tridge Samba4 : @@ -4833,10 +5018,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char status = smb_file_mode_information(conn, pdata, total_data); - if (!NT_STATUS_IS_OK(status)) { - return ERROR_NT(status); - } - goto out; + break; } /* @@ -4854,14 +5036,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char total_data, fsp, fname, - &sbuf, - &size, - &tvs, - &unixmode, - &dosmode); - if (!NT_STATUS_IS_OK(status)) { - return ERROR_NT(status); - } + &sbuf); break; } @@ -4876,10 +5051,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char pdata, total_data, fname); - if (!NT_STATUS_IS_OK(status)) { - return ERROR_NT(status); - } - goto out; + break; } case SMB_SET_FILE_UNIX_HLINK: @@ -4893,10 +5065,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char pdata, total_data, fname); - if (!NT_STATUS_IS_OK(status)) { - return ERROR_NT(status); - } - goto out; + break; } case SMB_FILE_RENAME_INFORMATION: @@ -4908,17 +5077,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char total_data, fsp, fname); - if (!NT_STATUS_IS_OK(status)) { - if (open_was_deferred(SVAL(inbuf,smb_mid))) { - /* We have re-scheduled this call. */ - return -1; - } - if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { - return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath); - } - return ERROR_NT(status); - } - goto out; + break; } #if defined(HAVE_POSIX_ACLS) @@ -4930,10 +5089,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char fsp, &sbuf, fname); - if (!NT_STATUS_IS_OK(status)) { - return ERROR_NT(status); - } - goto out; + break; } #endif @@ -4945,140 +5101,29 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char pdata, total_data, fsp); - if (!NT_STATUS_IS_OK(status)) { - if (blocking_lock_was_deferred(SVAL(inbuf,smb_mid))) { - /* We have re-scheduled this call. */ - return -1; - } - return ERROR_NT(status); - } - goto out; + break; } default: return ERROR_NT(NT_STATUS_INVALID_LEVEL); } - /* get some defaults (no modifications) if any info is zero or -1. */ - if (null_mtime(tvs.actime)) { - tvs.actime = sbuf.st_atime; - } - - if (null_mtime(tvs.modtime)) { - tvs.modtime = sbuf.st_mtime; - } - - DEBUG(6,("actime: %s " , ctime(&tvs.actime))); - DEBUG(6,("modtime: %s ", ctime(&tvs.modtime))); - DEBUG(6,("size: %.0f ", (double)size)); - - if (dosmode) { - if (S_ISDIR(sbuf.st_mode)) { - dosmode |= aDIR; - } else { - dosmode &= ~aDIR; - } - } - - DEBUG(6,("dosmode: %x\n" , dosmode)); - - if(!((info_level == SMB_SET_FILE_END_OF_FILE_INFO) || - (info_level == SMB_SET_FILE_ALLOCATION_INFO) || - (info_level == SMB_FILE_ALLOCATION_INFORMATION) || - (info_level == SMB_FILE_END_OF_FILE_INFORMATION))) { - - /* - * Only do this test if we are not explicitly - * changing the size of a file. - */ - if (!size) - size = get_file_size(sbuf); - } - - /* - * Try and set the times, size and mode of this file - - * if they are different from the current values - */ - - /* check the mode isn't different, before changing it */ - if ((dosmode != 0) && (dosmode != dos_mode(conn, fname, &sbuf))) { - - DEBUG(10,("call_trans2setfilepathinfo: file %s : setting dos mode %x\n", fname, dosmode )); - - if(file_set_dosmode(conn, fname, dosmode, &sbuf, False)) { - DEBUG(2,("file_set_dosmode of %s failed (%s)\n", fname, strerror(errno))); - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } - } - - /* Now the size. */ - if (size != get_file_size(sbuf)) { - - int ret; - - DEBUG(10,("call_trans2setfilepathinfo: file %s : setting new size to %.0f\n", - fname, (double)size )); - - if (fd == -1) { - files_struct *new_fsp = NULL; - - status = open_file_ntcreate(conn, fname, &sbuf, - FILE_WRITE_DATA, - FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, - FILE_OPEN, - 0, - FILE_ATTRIBUTE_NORMAL, - FORCE_OPLOCK_BREAK_TO_NONE, - NULL, &new_fsp); - if (!NT_STATUS_IS_OK(status)) { - if (open_was_deferred(SVAL(inbuf,smb_mid))) { - /* We have re-scheduled this call. */ - return -1; - } - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } - ret = vfs_set_filelen(new_fsp, size); - close_file(new_fsp,NORMAL_CLOSE); - } else { - ret = vfs_set_filelen(fsp, size); - } - - if (ret == -1) { - return (UNIXERROR(ERRHRD,ERRdiskfull)); + if (!NT_STATUS_IS_OK(status)) { + if (open_was_deferred(SVAL(inbuf,smb_mid))) { + /* We have re-scheduled this call. */ + return -1; } - } - - /* - * Finally the times. - */ - if (sbuf.st_mtime != tvs.modtime || sbuf.st_atime != tvs.actime) { - if(fsp != NULL) { - /* - * This was a setfileinfo on an open file. - * NT does this a lot. We also need to - * set the time here, as it can be read by - * FindFirst/FindNext and with the patch for bug #2045 - * in smbd/fileio.c it ensures that this timestamp is - * kept sticky even after a write. We save the request - * away and will set it on file close and after a write. JRA. - */ - - if (tvs.modtime != (time_t)0 && tvs.modtime != (time_t)-1) { - DEBUG(10,("call_trans2setfilepathinfo: setting pending modtime to %s\n", ctime(&tvs.modtime) )); - fsp_set_pending_modtime(fsp, tvs.modtime); - } - + if (blocking_lock_was_deferred(SVAL(inbuf,smb_mid))) { + /* We have re-scheduled this call. */ + return -1; } - DEBUG(10,("call_trans2setfilepathinfo: setting utimes to modified values.\n")); - - if(file_utime(conn, fname, &tvs)!=0) { - return(UNIXERROR(ERRDOS,ERRnoaccess)); + if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { + return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath); } + return ERROR_NT(status); } - out: - SSVAL(params,0,0); send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0, max_data_bytes); |