summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/smbd/trans2.c815
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);