smb_fname_new);
}
+/****************************************************************************
+ Allow a UNIX info mknod.
+****************************************************************************/
+
+static NTSTATUS smb_unix_mknod(connection_struct *conn,
+ const char *pdata,
+ int total_data,
+ const struct smb_filename *smb_fname)
+{
+ uint32_t file_type = IVAL(pdata,56);
+#if defined(HAVE_MAKEDEV)
+ uint32_t dev_major = IVAL(pdata,60);
+ uint32_t dev_minor = IVAL(pdata,68);
+#endif
+ SMB_DEV_T dev = (SMB_DEV_T)0;
+ uint32_t raw_unixmode = IVAL(pdata,84);
+ NTSTATUS status;
+ mode_t unixmode;
+ int ret;
+ struct smb_filename *parent_fname = NULL;
+ struct smb_filename *base_name = NULL;
+
+ if (total_data < 100) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode,
+ PERM_NEW_FILE, &unixmode);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+#if defined(HAVE_MAKEDEV)
+ dev = makedev(dev_major, dev_minor);
+#endif
+
+ switch (file_type) {
+ /* We can't create other objects here. */
+ case UNIX_TYPE_FILE:
+ case UNIX_TYPE_DIR:
+ case UNIX_TYPE_SYMLINK:
+ return NT_STATUS_ACCESS_DENIED;
+#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:
+ /* This is only allowed for root. */
+ if (get_current_uid(conn) != sec_initial_uid()) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ unixmode |= S_IFCHR;
+ break;
+#endif
+#if defined(S_IFBLK)
+ case UNIX_TYPE_BLKDEV:
+ if (get_current_uid(conn) != sec_initial_uid()) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ 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, smb_fname_str_dbg(smb_fname)));
+
+ status = parent_pathref(talloc_tos(),
+ conn->cwd_fsp,
+ smb_fname,
+ &parent_fname,
+ &base_name);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /* Ok - do the mknod. */
+ ret = SMB_VFS_MKNODAT(conn,
+ parent_fname->fsp,
+ base_name,
+ unixmode,
+ dev);
+
+ if (ret != 0) {
+ TALLOC_FREE(parent_fname);
+ 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_permissions(SNUM(conn))) {
+ inherit_access_posix_acl(conn,
+ parent_fname->fsp,
+ smb_fname,
+ unixmode);
+ }
+ TALLOC_FREE(parent_fname);
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Deal with SMB_SET_FILE_UNIX_BASIC.
+****************************************************************************/
+
+static NTSTATUS smb_set_file_unix_basic(connection_struct *conn,
+ struct smb_request *req,
+ const char *pdata,
+ int total_data,
+ files_struct *fsp,
+ struct smb_filename *smb_fname)
+{
+ struct smb_file_time ft;
+ uint32_t raw_unixmode;
+ mode_t unixmode;
+ off_t size = 0;
+ uid_t set_owner = (uid_t)SMB_UID_NO_CHANGE;
+ gid_t set_grp = (uid_t)SMB_GID_NO_CHANGE;
+ NTSTATUS status = NT_STATUS_OK;
+ enum perm_type ptype;
+ files_struct *all_fsps = NULL;
+ bool modify_mtime = true;
+ struct file_id id;
+ SMB_STRUCT_STAT sbuf;
+
+ if (!CAN_WRITE(conn)) {
+ return NT_STATUS_DOS(ERRSRV, ERRaccess);
+ }
+
+ init_smb_file_time(&ft);
+
+ if (total_data < 100) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if(IVAL(pdata, 0) != SMB_SIZE_NO_CHANGE_LO &&
+ IVAL(pdata, 4) != SMB_SIZE_NO_CHANGE_HI) {
+ size=IVAL(pdata,0); /* first 8 Bytes are size */
+ size |= (((off_t)IVAL(pdata,4)) << 32);
+ }
+
+ ft.atime = pull_long_date_full_timespec(pdata+24); /* access_time */
+ ft.mtime = pull_long_date_full_timespec(pdata+32); /* modification_time */
+ set_owner = (uid_t)IVAL(pdata,40);
+ set_grp = (gid_t)IVAL(pdata,48);
+ raw_unixmode = IVAL(pdata,84);
+
+ if (VALID_STAT(smb_fname->st)) {
+ if (S_ISDIR(smb_fname->st.st_ex_mode)) {
+ ptype = PERM_EXISTING_DIR;
+ } else {
+ ptype = PERM_EXISTING_FILE;
+ }
+ } else {
+ ptype = PERM_NEW_FILE;
+ }
+
+ status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode,
+ ptype, &unixmode);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ 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",
+ smb_fname_str_dbg(smb_fname), (double)size,
+ (unsigned int)set_owner, (unsigned int)set_grp,
+ (int)raw_unixmode));
+
+ sbuf = smb_fname->st;
+
+ if (!VALID_STAT(sbuf)) {
+ /*
+ * 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.
+ */
+
+ return smb_unix_mknod(conn,
+ pdata,
+ total_data,
+ smb_fname);
+ }
+
+#if 1
+ /* Horrible backwards compatibility hack as an old server bug
+ * allowed a CIFS client bug to remain unnoticed :-(. JRA.
+ * */
+
+ if (!size) {
+ size = get_file_size_stat(&sbuf);
+ }
+#endif
+
+ /*
+ * Deal with the UNIX specific mode set.
+ */
+
+ if (raw_unixmode != SMB_MODE_NO_CHANGE) {
+ int ret;
+
+ if (fsp == NULL || S_ISLNK(smb_fname->st.st_ex_mode)) {
+ DBG_WARNING("Can't set mode on symlink %s\n",
+ smb_fname_str_dbg(smb_fname));
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC "
+ "setting mode 0%o for file %s\n",
+ (unsigned int)unixmode,
+ smb_fname_str_dbg(smb_fname)));
+ ret = SMB_VFS_FCHMOD(fsp, unixmode);
+ if (ret != 0) {
+ return map_nt_error_from_unix(errno);
+ }
+ }
+
+ /*
+ * Deal with the UNIX specific uid set.
+ */
+
+ if ((set_owner != (uid_t)SMB_UID_NO_CHANGE) &&
+ (sbuf.st_ex_uid != set_owner)) {
+ int ret;
+
+ DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC "
+ "changing owner %u for path %s\n",
+ (unsigned int)set_owner,
+ smb_fname_str_dbg(smb_fname)));
+
+ if (fsp &&
+ !fsp->fsp_flags.is_pathref &&
+ fsp_get_io_fd(fsp) != -1)
+ {
+ ret = SMB_VFS_FCHOWN(fsp, set_owner, (gid_t)-1);
+ } else {
+ /*
+ * UNIX extensions calls must always operate
+ * on symlinks.
+ */
+ ret = SMB_VFS_LCHOWN(conn, smb_fname,
+ set_owner, (gid_t)-1);
+ }
+
+ if (ret != 0) {
+ status = map_nt_error_from_unix(errno);
+ return status;
+ }
+ }
+
+ /*
+ * Deal with the UNIX specific gid set.
+ */
+
+ if ((set_grp != (uid_t)SMB_GID_NO_CHANGE) &&
+ (sbuf.st_ex_gid != set_grp)) {
+ int ret;
+
+ DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC "
+ "changing group %u for file %s\n",
+ (unsigned int)set_grp,
+ smb_fname_str_dbg(smb_fname)));
+ if (fsp &&
+ !fsp->fsp_flags.is_pathref &&
+ fsp_get_io_fd(fsp) != -1)
+ {
+ ret = SMB_VFS_FCHOWN(fsp, (uid_t)-1, set_grp);
+ } else {
+ /*
+ * UNIX extensions calls must always operate
+ * on symlinks.
+ */
+ ret = SMB_VFS_LCHOWN(conn, smb_fname, (uid_t)-1,
+ set_grp);
+ }
+ if (ret != 0) {
+ status = map_nt_error_from_unix(errno);
+ return status;
+ }
+ }
+
+ /* Deal with any size changes. */
+
+ if (S_ISREG(sbuf.st_ex_mode)) {
+ status = smb_set_file_size(conn, req,
+ fsp,
+ smb_fname,
+ &sbuf,
+ size,
+ false);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
+ /* Deal with any time changes. */
+ if (is_omit_timespec(&ft.mtime) && is_omit_timespec(&ft.atime)) {
+ /* No change, don't cancel anything. */
+ return status;
+ }
+
+ id = vfs_file_id_from_sbuf(conn, &sbuf);
+ for(all_fsps = file_find_di_first(conn->sconn, id, true); all_fsps;
+ all_fsps = file_find_di_next(all_fsps, true)) {
+ /*
+ * We're setting the time explicitly for UNIX.
+ * Cancel any pending changes over all handles.
+ */
+ all_fsps->fsp_flags.update_write_time_on_close = false;
+ TALLOC_FREE(all_fsps->update_write_time_event);
+ }
+
+ /*
+ * Override the "setting_write_time"
+ * parameter here as it almost does what
+ * we need. Just remember if we modified
+ * mtime and send the notify ourselves.
+ */
+ if (is_omit_timespec(&ft.mtime)) {
+ modify_mtime = false;
+ }
+
+ status = smb_set_file_time(conn,
+ fsp,
+ smb_fname,
+ &ft,
+ false);
+ if (modify_mtime) {
+ notify_fname(conn, NOTIFY_ACTION_MODIFIED,
+ FILE_NOTIFY_CHANGE_LAST_WRITE, smb_fname->base_name);
+ }
+ return status;
+}
+
+/****************************************************************************
+ Deal with SMB_SET_FILE_UNIX_INFO2.
+****************************************************************************/
+
+static NTSTATUS smb_set_file_unix_info2(connection_struct *conn,
+ struct smb_request *req,
+ const char *pdata,
+ int total_data,
+ files_struct *fsp,
+ struct smb_filename *smb_fname)
+{
+ NTSTATUS status;
+ uint32_t smb_fflags;
+ uint32_t smb_fmask;
+
+ if (!CAN_WRITE(conn)) {
+ return NT_STATUS_DOS(ERRSRV, ERRaccess);
+ }
+
+ if (total_data < 116) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* Start by setting all the fields that are common between UNIX_BASIC
+ * and UNIX_INFO2.
+ */
+ status = smb_set_file_unix_basic(conn, req, pdata, total_data,
+ fsp, smb_fname);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ smb_fflags = IVAL(pdata, 108);
+ smb_fmask = IVAL(pdata, 112);
+
+ /* NB: We should only attempt to alter the file flags if the client
+ * sends a non-zero mask.
+ */
+ if (smb_fmask != 0) {
+ int stat_fflags = 0;
+
+ if (!map_info2_flags_to_sbuf(&smb_fname->st, smb_fflags,
+ smb_fmask, &stat_fflags)) {
+ /* Client asked to alter a flag we don't understand. */
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (fsp == NULL || S_ISLNK(smb_fname->st.st_ex_mode)) {
+ DBG_WARNING("Can't change flags on symlink %s\n",
+ smb_fname_str_dbg(smb_fname));
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+ if (SMB_VFS_FCHFLAGS(fsp, stat_fflags) != 0) {
+ return map_nt_error_from_unix(errno);
+ }
+ }
+
+ /* XXX: need to add support for changing the create_time here. You
+ * can do this for paths on Darwin with setattrlist(2). The right way
+ * to hook this up is probably by extending the VFS utimes interface.
+ */
+
+ return NT_STATUS_OK;
+}
+
static void call_trans2setpathinfo(
connection_struct *conn,
struct smb_request *req,
status = smb_set_file_unix_hlink(
conn, req, *ppdata, total_data, smb_fname);
break;
+
+ case SMB_SET_FILE_UNIX_BASIC:
+ status = smb_set_file_unix_basic(
+ conn,
+ req,
+ *ppdata,
+ total_data,
+ smb_fname->fsp,
+ smb_fname);
+ break;
+
+ case SMB_SET_FILE_UNIX_INFO2:
+ status = smb_set_file_unix_info2(
+ conn,
+ req,
+ *ppdata,
+ total_data,
+ smb_fname->fsp,
+ smb_fname);
+ break;
}
if (info_level_handled) {
info_level_handled = false;
break;
+ case SMB_SET_FILE_UNIX_BASIC:
+ status = smb_set_file_unix_basic(
+ conn, req, pdata, total_data, fsp, smb_fname);
+ break;
+
+ case SMB_SET_FILE_UNIX_INFO2:
+ status = smb_set_file_unix_info2(
+ conn, req, pdata, total_data, fsp, smb_fname);
+ break;
+
case SMB_SET_POSIX_LOCK:
status = smb_set_posix_lock(
conn, req, *ppdata, total_data, fsp);
fail_after_createfile);
}
-/****************************************************************************
- Allow a UNIX info mknod.
-****************************************************************************/
-
-static NTSTATUS smb_unix_mknod(connection_struct *conn,
- const char *pdata,
- int total_data,
- const struct smb_filename *smb_fname)
-{
- uint32_t file_type = IVAL(pdata,56);
-#if defined(HAVE_MAKEDEV)
- uint32_t dev_major = IVAL(pdata,60);
- uint32_t dev_minor = IVAL(pdata,68);
-#endif
- SMB_DEV_T dev = (SMB_DEV_T)0;
- uint32_t raw_unixmode = IVAL(pdata,84);
- NTSTATUS status;
- mode_t unixmode;
- int ret;
- struct smb_filename *parent_fname = NULL;
- struct smb_filename *base_name = NULL;
-
- if (total_data < 100) {
- return NT_STATUS_INVALID_PARAMETER;
- }
-
- status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode,
- PERM_NEW_FILE, &unixmode);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
- }
-
-#if defined(HAVE_MAKEDEV)
- dev = makedev(dev_major, dev_minor);
-#endif
-
- switch (file_type) {
- /* We can't create other objects here. */
- case UNIX_TYPE_FILE:
- case UNIX_TYPE_DIR:
- case UNIX_TYPE_SYMLINK:
- return NT_STATUS_ACCESS_DENIED;
-#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:
- /* This is only allowed for root. */
- if (get_current_uid(conn) != sec_initial_uid()) {
- return NT_STATUS_ACCESS_DENIED;
- }
- unixmode |= S_IFCHR;
- break;
-#endif
-#if defined(S_IFBLK)
- case UNIX_TYPE_BLKDEV:
- if (get_current_uid(conn) != sec_initial_uid()) {
- return NT_STATUS_ACCESS_DENIED;
- }
- 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, smb_fname_str_dbg(smb_fname)));
-
- status = parent_pathref(talloc_tos(),
- conn->cwd_fsp,
- smb_fname,
- &parent_fname,
- &base_name);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
- }
-
- /* Ok - do the mknod. */
- ret = SMB_VFS_MKNODAT(conn,
- parent_fname->fsp,
- base_name,
- unixmode,
- dev);
-
- if (ret != 0) {
- TALLOC_FREE(parent_fname);
- 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_permissions(SNUM(conn))) {
- inherit_access_posix_acl(conn,
- parent_fname->fsp,
- smb_fname,
- unixmode);
- }
- TALLOC_FREE(parent_fname);
-
- return NT_STATUS_OK;
-}
-
-/****************************************************************************
- Deal with SMB_SET_FILE_UNIX_BASIC.
-****************************************************************************/
-
-static NTSTATUS smb_set_file_unix_basic(connection_struct *conn,
- struct smb_request *req,
- const char *pdata,
- int total_data,
- files_struct *fsp,
- struct smb_filename *smb_fname)
-{
- struct smb_file_time ft;
- uint32_t raw_unixmode;
- mode_t unixmode;
- off_t size = 0;
- uid_t set_owner = (uid_t)SMB_UID_NO_CHANGE;
- gid_t set_grp = (uid_t)SMB_GID_NO_CHANGE;
- NTSTATUS status = NT_STATUS_OK;
- enum perm_type ptype;
- files_struct *all_fsps = NULL;
- bool modify_mtime = true;
- struct file_id id;
- SMB_STRUCT_STAT sbuf;
-
- init_smb_file_time(&ft);
-
- if (total_data < 100) {
- return NT_STATUS_INVALID_PARAMETER;
- }
-
- if(IVAL(pdata, 0) != SMB_SIZE_NO_CHANGE_LO &&
- IVAL(pdata, 4) != SMB_SIZE_NO_CHANGE_HI) {
- size=IVAL(pdata,0); /* first 8 Bytes are size */
- size |= (((off_t)IVAL(pdata,4)) << 32);
- }
-
- ft.atime = pull_long_date_full_timespec(pdata+24); /* access_time */
- ft.mtime = pull_long_date_full_timespec(pdata+32); /* modification_time */
- set_owner = (uid_t)IVAL(pdata,40);
- set_grp = (gid_t)IVAL(pdata,48);
- raw_unixmode = IVAL(pdata,84);
-
- if (VALID_STAT(smb_fname->st)) {
- if (S_ISDIR(smb_fname->st.st_ex_mode)) {
- ptype = PERM_EXISTING_DIR;
- } else {
- ptype = PERM_EXISTING_FILE;
- }
- } else {
- ptype = PERM_NEW_FILE;
- }
-
- status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode,
- ptype, &unixmode);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
- }
-
- 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",
- smb_fname_str_dbg(smb_fname), (double)size,
- (unsigned int)set_owner, (unsigned int)set_grp,
- (int)raw_unixmode));
-
- sbuf = smb_fname->st;
-
- if (!VALID_STAT(sbuf)) {
- /*
- * 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.
- */
-
- return smb_unix_mknod(conn,
- pdata,
- total_data,
- smb_fname);
- }
-
-#if 1
- /* Horrible backwards compatibility hack as an old server bug
- * allowed a CIFS client bug to remain unnoticed :-(. JRA.
- * */
-
- if (!size) {
- size = get_file_size_stat(&sbuf);
- }
-#endif
-
- /*
- * Deal with the UNIX specific mode set.
- */
-
- if (raw_unixmode != SMB_MODE_NO_CHANGE) {
- int ret;
-
- if (fsp == NULL || S_ISLNK(smb_fname->st.st_ex_mode)) {
- DBG_WARNING("Can't set mode on symlink %s\n",
- smb_fname_str_dbg(smb_fname));
- return NT_STATUS_OBJECT_NAME_NOT_FOUND;
- }
-
- DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC "
- "setting mode 0%o for file %s\n",
- (unsigned int)unixmode,
- smb_fname_str_dbg(smb_fname)));
- ret = SMB_VFS_FCHMOD(fsp, unixmode);
- if (ret != 0) {
- return map_nt_error_from_unix(errno);
- }
- }
-
- /*
- * Deal with the UNIX specific uid set.
- */
-
- if ((set_owner != (uid_t)SMB_UID_NO_CHANGE) &&
- (sbuf.st_ex_uid != set_owner)) {
- int ret;
-
- DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC "
- "changing owner %u for path %s\n",
- (unsigned int)set_owner,
- smb_fname_str_dbg(smb_fname)));
-
- if (fsp &&
- !fsp->fsp_flags.is_pathref &&
- fsp_get_io_fd(fsp) != -1)
- {
- ret = SMB_VFS_FCHOWN(fsp, set_owner, (gid_t)-1);
- } else {
- /*
- * UNIX extensions calls must always operate
- * on symlinks.
- */
- ret = SMB_VFS_LCHOWN(conn, smb_fname,
- set_owner, (gid_t)-1);
- }
-
- if (ret != 0) {
- status = map_nt_error_from_unix(errno);
- return status;
- }
- }
-
- /*
- * Deal with the UNIX specific gid set.
- */
-
- if ((set_grp != (uid_t)SMB_GID_NO_CHANGE) &&
- (sbuf.st_ex_gid != set_grp)) {
- int ret;
-
- DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC "
- "changing group %u for file %s\n",
- (unsigned int)set_grp,
- smb_fname_str_dbg(smb_fname)));
- if (fsp &&
- !fsp->fsp_flags.is_pathref &&
- fsp_get_io_fd(fsp) != -1)
- {
- ret = SMB_VFS_FCHOWN(fsp, (uid_t)-1, set_grp);
- } else {
- /*
- * UNIX extensions calls must always operate
- * on symlinks.
- */
- ret = SMB_VFS_LCHOWN(conn, smb_fname, (uid_t)-1,
- set_grp);
- }
- if (ret != 0) {
- status = map_nt_error_from_unix(errno);
- return status;
- }
- }
-
- /* Deal with any size changes. */
-
- if (S_ISREG(sbuf.st_ex_mode)) {
- status = smb_set_file_size(conn, req,
- fsp,
- smb_fname,
- &sbuf,
- size,
- false);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
- }
- }
-
- /* Deal with any time changes. */
- if (is_omit_timespec(&ft.mtime) && is_omit_timespec(&ft.atime)) {
- /* No change, don't cancel anything. */
- return status;
- }
-
- id = vfs_file_id_from_sbuf(conn, &sbuf);
- for(all_fsps = file_find_di_first(conn->sconn, id, true); all_fsps;
- all_fsps = file_find_di_next(all_fsps, true)) {
- /*
- * We're setting the time explicitly for UNIX.
- * Cancel any pending changes over all handles.
- */
- all_fsps->fsp_flags.update_write_time_on_close = false;
- TALLOC_FREE(all_fsps->update_write_time_event);
- }
-
- /*
- * Override the "setting_write_time"
- * parameter here as it almost does what
- * we need. Just remember if we modified
- * mtime and send the notify ourselves.
- */
- if (is_omit_timespec(&ft.mtime)) {
- modify_mtime = false;
- }
-
- status = smb_set_file_time(conn,
- fsp,
- smb_fname,
- &ft,
- false);
- if (modify_mtime) {
- notify_fname(conn, NOTIFY_ACTION_MODIFIED,
- FILE_NOTIFY_CHANGE_LAST_WRITE, smb_fname->base_name);
- }
- return status;
-}
-
-/****************************************************************************
- Deal with SMB_SET_FILE_UNIX_INFO2.
-****************************************************************************/
-
-static NTSTATUS smb_set_file_unix_info2(connection_struct *conn,
- struct smb_request *req,
- const char *pdata,
- int total_data,
- files_struct *fsp,
- struct smb_filename *smb_fname)
-{
- NTSTATUS status;
- uint32_t smb_fflags;
- uint32_t smb_fmask;
-
- if (total_data < 116) {
- return NT_STATUS_INVALID_PARAMETER;
- }
-
- /* Start by setting all the fields that are common between UNIX_BASIC
- * and UNIX_INFO2.
- */
- status = smb_set_file_unix_basic(conn, req, pdata, total_data,
- fsp, smb_fname);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
- }
-
- smb_fflags = IVAL(pdata, 108);
- smb_fmask = IVAL(pdata, 112);
-
- /* NB: We should only attempt to alter the file flags if the client
- * sends a non-zero mask.
- */
- if (smb_fmask != 0) {
- int stat_fflags = 0;
-
- if (!map_info2_flags_to_sbuf(&smb_fname->st, smb_fflags,
- smb_fmask, &stat_fflags)) {
- /* Client asked to alter a flag we don't understand. */
- return NT_STATUS_INVALID_PARAMETER;
- }
-
- if (fsp == NULL || S_ISLNK(smb_fname->st.st_ex_mode)) {
- DBG_WARNING("Can't change flags on symlink %s\n",
- smb_fname_str_dbg(smb_fname));
- return NT_STATUS_OBJECT_NAME_NOT_FOUND;
- }
- if (SMB_VFS_FCHFLAGS(fsp, stat_fflags) != 0) {
- return map_nt_error_from_unix(errno);
- }
- }
-
- /* XXX: need to add support for changing the create_time here. You
- * can do this for paths on Darwin with setattrlist(2). The right way
- * to hook this up is probably by extending the VFS utimes interface.
- */
-
- return NT_STATUS_OK;
-}
-
static NTSTATUS smbd_do_posix_setfilepathinfo(struct connection_struct *conn,
struct smb_request *req,
TALLOC_CTX *mem_ctx,
total_data);
switch (info_level) {
- case SMB_SET_FILE_UNIX_BASIC:
- {
- status = smb_set_file_unix_basic(conn, req,
- pdata,
- total_data,
- fsp,
- smb_fname);
- break;
- }
-
- case SMB_SET_FILE_UNIX_INFO2:
- {
- status = smb_set_file_unix_info2(conn, req,
- pdata,
- total_data,
- fsp,
- smb_fname);
- break;
- }
#if defined(HAVE_POSIX_ACLS)
case SMB_SET_POSIX_ACL: