summaryrefslogtreecommitdiffstats
path: root/sys/fs/smbfs
diff options
context:
space:
mode:
Diffstat (limited to 'sys/fs/smbfs')
-rw-r--r--sys/fs/smbfs/smbfs_node.c15
-rw-r--r--sys/fs/smbfs/smbfs_vnops.c65
2 files changed, 70 insertions, 10 deletions
diff --git a/sys/fs/smbfs/smbfs_node.c b/sys/fs/smbfs/smbfs_node.c
index 1b55ff3..05d19e9 100644
--- a/sys/fs/smbfs/smbfs_node.c
+++ b/sys/fs/smbfs/smbfs_node.c
@@ -370,10 +370,13 @@ smbfs_attr_cachelookup(struct vnode *vp, struct vattr *va)
if (diff > 2) /* XXX should be configurable */
return ENOENT;
va->va_type = vp->v_type; /* vnode type (for create) */
+ va->va_flags = 0; /* flags defined for file */
if (vp->v_type == VREG) {
va->va_mode = smp->sm_file_mode; /* files access mode and type */
- if (np->n_dosattr & SMB_FA_RDONLY)
+ if (np->n_dosattr & SMB_FA_RDONLY) {
va->va_mode &= ~(S_IWUSR|S_IWGRP|S_IWOTH);
+ va->va_flags |= UF_READONLY;
+ }
} else if (vp->v_type == VDIR) {
va->va_mode = smp->sm_dir_mode; /* files access mode and type */
} else
@@ -390,7 +393,15 @@ smbfs_attr_cachelookup(struct vnode *vp, struct vattr *va)
va->va_mtime = np->n_mtime;
va->va_atime = va->va_ctime = va->va_mtime; /* time file changed */
va->va_gen = VNOVAL; /* generation number of file */
- va->va_flags = 0; /* flags defined for file */
+ if (np->n_dosattr & SMB_FA_HIDDEN)
+ va->va_flags |= UF_HIDDEN;
+ if (np->n_dosattr & SMB_FA_SYSTEM)
+ va->va_flags |= UF_SYSTEM;
+ /*
+ * We don't set the archive bit for directories.
+ */
+ if ((vp->v_type != VDIR) && (np->n_dosattr & SMB_FA_ARCHIVE))
+ va->va_flags |= UF_ARCHIVE;
va->va_rdev = NODEV; /* device the special file represents */
va->va_bytes = va->va_size; /* bytes of disk space held by file */
va->va_filerev = 0; /* file modification number */
diff --git a/sys/fs/smbfs/smbfs_vnops.c b/sys/fs/smbfs/smbfs_vnops.c
index ef1dc65..8ea1198 100644
--- a/sys/fs/smbfs/smbfs_vnops.c
+++ b/sys/fs/smbfs/smbfs_vnops.c
@@ -305,16 +305,30 @@ smbfs_setattr(ap)
int old_n_dosattr;
SMBVDEBUG("\n");
- if (vap->va_flags != VNOVAL)
- return EOPNOTSUPP;
isreadonly = (vp->v_mount->mnt_flag & MNT_RDONLY);
/*
* Disallow write attempts if the filesystem is mounted read-only.
*/
if ((vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL ||
vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL ||
- vap->va_mode != (mode_t)VNOVAL) && isreadonly)
+ vap->va_mode != (mode_t)VNOVAL || vap->va_flags != VNOVAL) &&
+ isreadonly)
return EROFS;
+
+ /*
+ * We only support setting four flags. Don't allow setting others.
+ *
+ * We map UF_READONLY to SMB_FA_RDONLY, unlike the MacOS X version
+ * of this code, which maps both UF_IMMUTABLE AND SF_IMMUTABLE to
+ * SMB_FA_RDONLY. The immutable flags have different semantics
+ * than readonly, which is the reason for the difference.
+ */
+ if (vap->va_flags != VNOVAL) {
+ if (vap->va_flags & ~(UF_HIDDEN|UF_SYSTEM|UF_ARCHIVE|
+ UF_READONLY))
+ return EINVAL;
+ }
+
scred = smbfs_malloc_scred();
smb_makescred(scred, td, ap->a_cred);
if (vap->va_size != VNOVAL) {
@@ -353,12 +367,47 @@ smbfs_setattr(ap)
goto out;
}
}
- if (vap->va_mode != (mode_t)VNOVAL) {
+ if ((vap->va_flags != VNOVAL) || (vap->va_mode != (mode_t)VNOVAL)) {
old_n_dosattr = np->n_dosattr;
- if (vap->va_mode & S_IWUSR)
- np->n_dosattr &= ~SMB_FA_RDONLY;
- else
- np->n_dosattr |= SMB_FA_RDONLY;
+
+ if (vap->va_mode != (mode_t)VNOVAL) {
+ if (vap->va_mode & S_IWUSR)
+ np->n_dosattr &= ~SMB_FA_RDONLY;
+ else
+ np->n_dosattr |= SMB_FA_RDONLY;
+ }
+
+ if (vap->va_flags != VNOVAL) {
+ if (vap->va_flags & UF_HIDDEN)
+ np->n_dosattr |= SMB_FA_HIDDEN;
+ else
+ np->n_dosattr &= ~SMB_FA_HIDDEN;
+
+ if (vap->va_flags & UF_SYSTEM)
+ np->n_dosattr |= SMB_FA_SYSTEM;
+ else
+ np->n_dosattr &= ~SMB_FA_SYSTEM;
+
+ if (vap->va_flags & UF_ARCHIVE)
+ np->n_dosattr |= SMB_FA_ARCHIVE;
+ else
+ np->n_dosattr &= ~SMB_FA_ARCHIVE;
+
+ /*
+ * We only support setting the immutable / readonly
+ * bit for regular files. According to comments in
+ * the MacOS X version of this code, supporting the
+ * readonly bit on directories doesn't do the same
+ * thing in Windows as in Unix.
+ */
+ if (vp->v_type == VREG) {
+ if (vap->va_flags & UF_READONLY)
+ np->n_dosattr |= SMB_FA_RDONLY;
+ else
+ np->n_dosattr &= ~SMB_FA_RDONLY;
+ }
+ }
+
if (np->n_dosattr != old_n_dosattr) {
error = smbfs_smb_setpattr(np, np->n_dosattr, NULL, scred);
if (error)
OpenPOWER on IntegriCloud