diff options
-rw-r--r-- | bin/chflags/chflags.1 | 22 | ||||
-rw-r--r-- | bin/ls/ls.1 | 3 | ||||
-rw-r--r-- | lib/libc/gen/strtofflags.c | 20 | ||||
-rw-r--r-- | lib/libc/sys/chflags.2 | 66 | ||||
-rw-r--r-- | sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c | 48 | ||||
-rw-r--r-- | sys/fs/msdosfs/msdosfs_denode.c | 4 | ||||
-rw-r--r-- | sys/fs/msdosfs/msdosfs_vnops.c | 101 | ||||
-rw-r--r-- | sys/fs/smbfs/smbfs_node.c | 15 | ||||
-rw-r--r-- | sys/fs/smbfs/smbfs_vnops.c | 65 | ||||
-rw-r--r-- | sys/sys/param.h | 2 | ||||
-rw-r--r-- | sys/sys/stat.h | 22 | ||||
-rw-r--r-- | sys/ufs/ufs/ufs_vnops.c | 8 |
12 files changed, 300 insertions, 76 deletions
diff --git a/bin/chflags/chflags.1 b/bin/chflags/chflags.1 index fe9d700..47d5b18 100644 --- a/bin/chflags/chflags.1 +++ b/bin/chflags/chflags.1 @@ -32,7 +32,7 @@ .\" @(#)chflags.1 8.4 (Berkeley) 5/2/95 .\" $FreeBSD$ .\" -.Dd March 3, 2006 +.Dd April 8, 2013 .Dt CHFLAGS 1 .Os .Sh NAME @@ -101,20 +101,36 @@ The following keywords are currently defined: .Bl -tag -offset indent -width ".Cm opaque" .It Cm arch , archived set the archived flag (super-user only) -.It Cm opaque -set the opaque flag (owner or super-user only) .It Cm nodump set the nodump flag (owner or super-user only) +.It Cm opaque +set the opaque flag (owner or super-user only) .It Cm sappnd , sappend set the system append-only flag (super-user only) .It Cm schg , schange , simmutable set the system immutable flag (super-user only) +.It Cm snapshot +set the snapshot flag (filesystems do not allow changing this flag) .It Cm sunlnk , sunlink set the system undeletable flag (super-user only) .It Cm uappnd , uappend set the user append-only flag (owner or super-user only) +.It Cm uarch , uarchive +set the archive flag (owner or super-user only) .It Cm uchg , uchange , uimmutable set the user immutable flag (owner or super-user only) +.It Cm uhidden , hidden +set the hidden file attribute (owner or super-user only) +.It Cm uoffline , offline +set the offline file attribute (owner or super-user only) +.It Cm urdonly , rdonly , readonly +set the DOS, Windows and CIFS readonly flag (owner or super-user only) +.It Cm usparse , sparse +set the sparse file attribute (owner or super-user only) +.It Cm usystem , system +set the DOS, Windows and CIFS system flag (owner or super-user only) +.It Cm ureparse , reparse +set the Windows reparse point file attribute (owner or super-user only) .It Cm uunlnk , uunlink set the user undeletable flag (owner or super-user only) .El diff --git a/bin/ls/ls.1 b/bin/ls/ls.1 index 7c72652..8b7672b 100644 --- a/bin/ls/ls.1 +++ b/bin/ls/ls.1 @@ -232,6 +232,9 @@ output. Include the file flags in a long .Pq Fl l output. +See +.Xr chflags 1 +for a list of file flags and their meanings. .It Fl p Write a slash .Pq Ql / diff --git a/lib/libc/gen/strtofflags.c b/lib/libc/gen/strtofflags.c index 1edaa5a..55e9945 100644 --- a/lib/libc/gen/strtofflags.c +++ b/lib/libc/gen/strtofflags.c @@ -62,13 +62,29 @@ static struct { #endif { "nouappnd", 0, UF_APPEND }, { "nouappend", 0, UF_APPEND }, + { "nouarch", 0, UF_ARCHIVE }, + { "nouarchive", 0, UF_ARCHIVE }, + { "nohidden", 0, UF_HIDDEN }, + { "nouhidden", 0, UF_HIDDEN }, { "nouchg", 0, UF_IMMUTABLE }, { "nouchange", 0, UF_IMMUTABLE }, { "nouimmutable", 0, UF_IMMUTABLE }, { "nodump", 1, UF_NODUMP }, - { "noopaque", 0, UF_OPAQUE }, { "nouunlnk", 0, UF_NOUNLINK }, - { "nouunlink", 0, UF_NOUNLINK } + { "nouunlink", 0, UF_NOUNLINK }, + { "nooffline", 0, UF_OFFLINE }, + { "nouoffline", 0, UF_OFFLINE }, + { "noopaque", 0, UF_OPAQUE }, + { "nordonly", 0, UF_READONLY }, + { "nourdonly", 0, UF_READONLY }, + { "noreadonly", 0, UF_READONLY }, + { "noureadonly", 0, UF_READONLY }, + { "noreparse", 0, UF_REPARSE }, + { "noureparse", 0, UF_REPARSE }, + { "nosparse", 0, UF_SPARSE }, + { "nousparse", 0, UF_SPARSE }, + { "nosystem", 0, UF_SYSTEM }, + { "nousystem", 0, UF_SYSTEM } }; #define nmappings (sizeof(mapping) / sizeof(mapping[0])) diff --git a/lib/libc/sys/chflags.2 b/lib/libc/sys/chflags.2 index 5bc2ba2..9cca54f 100644 --- a/lib/libc/sys/chflags.2 +++ b/lib/libc/sys/chflags.2 @@ -112,26 +112,61 @@ The flags specified are formed by the following values .Pp .Bl -tag -width ".Dv SF_IMMUTABLE" -compact -offset indent -.It Dv UF_NODUMP -Do not dump the file. -.It Dv UF_IMMUTABLE -The file may not be changed. -.It Dv UF_APPEND +.It Dv SF_APPEND The file may only be appended to. -.It Dv UF_NOUNLINK -The file may not be renamed or deleted. -.It Dv UF_OPAQUE -The directory is opaque when viewed through a union stack. .It Dv SF_ARCHIVED -The file may be archived. +The file has been archived. +This flag means the opposite of the DOS, Windows and CIFS +FILE_ATTRIBUTE_ARCHIVE attribute. +This flag has been deprecated, and may be removed in a future release. .It Dv SF_IMMUTABLE The file may not be changed. -.It Dv SF_APPEND -The file may only be appended to. .It Dv SF_NOUNLINK The file may not be renamed or deleted. .It Dv SF_SNAPSHOT The file is a snapshot file. +.It Dv UF_APPEND +The file may only be appended to. +.It Dv UF_ARCHIVE +The file needs to be archived. +This flag has the same meaning as the DOS, Windows and CIFS +FILE_ATTRIBUTE_ARCHIVE attribute. +Filesystems in FreeBSD may or may not have special handling for this flag. +For instance, ZFS tracks changes to files and will set this bit when a +file is updated. +UFS only stores the flag, and relies on the application to change it when +needed. +.It Dv UF_HIDDEN +The file may be hidden from directory listings at the application's +discretion. +The file has the DOS, Windows and CIFS FILE_ATTRIBUTE_HIDDEN attribute. +.It Dv UF_IMMUTABLE +The file may not be changed. +.It Dv UF_NODUMP +Do not dump the file. +.It Dv UF_NOUNLINK +The file may not be renamed or deleted. +.It Dv UF_OFFLINE +The file is offline, or has the Windows and CIFS FILE_ATTRIBUTE_OFFLINE +attribute. +Filesystems in FreeBSD store and display this flag, but do not provide any +special handling when it is set. +.It Dv UF_OPAQUE +The directory is opaque when viewed through a union stack. +.It Dv UF_READONLY +The file is read only, and may not be written or appended. +Filesystems may use this flag to maintain compatibility with the DOS, Windows +and CIFS FILE_ATTRIBUTE_READONLY attribute. +.It Dv UF_REPARSE +The file contains a Windows reparse point and has the Windows and CIFS +FILE_ATTRIBUTE_REPARSE_POINT attribute. +.It Dv UF_SPARSE +The file has the Windows FILE_ATTRIBUTE_SPARSE_FILE attribute. +This may also be used by a filesystem to indicate a sparse file. +.It Dv UF_SYSTEM +The file has the DOS, Windows and CIFS FILE_ATTRIBUTE_SYSTEM attribute. +Filesystems in FreeBSD may store and display this flag, but do not provide +any special handling when it is set. .El .Pp If one of @@ -162,6 +197,13 @@ the system is in single-user mode. .Xr init 8 for details.) .Pp +The implementation of all flags is filesystem-dependent. +See the description of the +.Dv UF_ARCHIVE +flag above for one example of the differences in behavior. +Care should be exercised when writing applications to account for +support or lack of support of these flags in various filesystems. +.Pp The .Dv SF_SNAPSHOT flag is maintained by the system and cannot be toggled. diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c index 9a109c7..6dfca35 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c @@ -6071,6 +6071,14 @@ zfs_freebsd_getattr(ap) XVA_SET_REQ(&xvap, XAT_APPENDONLY); XVA_SET_REQ(&xvap, XAT_NOUNLINK); XVA_SET_REQ(&xvap, XAT_NODUMP); + XVA_SET_REQ(&xvap, XAT_READONLY); + XVA_SET_REQ(&xvap, XAT_ARCHIVE); + XVA_SET_REQ(&xvap, XAT_SYSTEM); + XVA_SET_REQ(&xvap, XAT_HIDDEN); + XVA_SET_REQ(&xvap, XAT_REPARSE); + XVA_SET_REQ(&xvap, XAT_OFFLINE); + XVA_SET_REQ(&xvap, XAT_SPARSE); + error = zfs_getattr(ap->a_vp, (vattr_t *)&xvap, 0, ap->a_cred, NULL); if (error != 0) return (error); @@ -6086,8 +6094,23 @@ zfs_freebsd_getattr(ap) xvap.xva_xoptattrs.xoa_appendonly); FLAG_CHECK(SF_NOUNLINK, XAT_NOUNLINK, xvap.xva_xoptattrs.xoa_nounlink); + FLAG_CHECK(UF_ARCHIVE, XAT_ARCHIVE, + xvap.xva_xoptattrs.xoa_archive); FLAG_CHECK(UF_NODUMP, XAT_NODUMP, xvap.xva_xoptattrs.xoa_nodump); + FLAG_CHECK(UF_READONLY, XAT_READONLY, + xvap.xva_xoptattrs.xoa_readonly); + FLAG_CHECK(UF_SYSTEM, XAT_SYSTEM, + xvap.xva_xoptattrs.xoa_system); + FLAG_CHECK(UF_HIDDEN, XAT_HIDDEN, + xvap.xva_xoptattrs.xoa_hidden); + FLAG_CHECK(UF_REPARSE, XAT_REPARSE, + xvap.xva_xoptattrs.xoa_reparse); + FLAG_CHECK(UF_OFFLINE, XAT_OFFLINE, + xvap.xva_xoptattrs.xoa_offline); + FLAG_CHECK(UF_SPARSE, XAT_SPARSE, + xvap.xva_xoptattrs.xoa_sparse); + #undef FLAG_CHECK *vap = xvap.xva_vattr; vap->va_flags = fflags; @@ -6125,7 +6148,16 @@ zfs_freebsd_setattr(ap) return (EOPNOTSUPP); fflags = vap->va_flags; - if ((fflags & ~(SF_IMMUTABLE|SF_APPEND|SF_NOUNLINK|UF_NODUMP)) != 0) + /* + * XXX KDM + * We need to figure out whether it makes sense to allow + * UF_REPARSE through, since we don't really have other + * facilities to handle reparse points and zfs_setattr() + * doesn't currently allow setting that attribute anyway. + */ + if ((fflags & ~(SF_IMMUTABLE|SF_APPEND|SF_NOUNLINK|UF_ARCHIVE| + UF_NODUMP|UF_SYSTEM|UF_HIDDEN|UF_READONLY|UF_REPARSE| + UF_OFFLINE|UF_SPARSE)) != 0) return (EOPNOTSUPP); /* * Unprivileged processes are not permitted to unset system @@ -6177,8 +6209,22 @@ zfs_freebsd_setattr(ap) xvap.xva_xoptattrs.xoa_appendonly); FLAG_CHANGE(SF_NOUNLINK, ZFS_NOUNLINK, XAT_NOUNLINK, xvap.xva_xoptattrs.xoa_nounlink); + FLAG_CHANGE(UF_ARCHIVE, ZFS_ARCHIVE, XAT_ARCHIVE, + xvap.xva_xoptattrs.xoa_archive); FLAG_CHANGE(UF_NODUMP, ZFS_NODUMP, XAT_NODUMP, xvap.xva_xoptattrs.xoa_nodump); + FLAG_CHANGE(UF_READONLY, ZFS_READONLY, XAT_READONLY, + xvap.xva_xoptattrs.xoa_readonly); + FLAG_CHANGE(UF_SYSTEM, ZFS_SYSTEM, XAT_SYSTEM, + xvap.xva_xoptattrs.xoa_system); + FLAG_CHANGE(UF_HIDDEN, ZFS_HIDDEN, XAT_HIDDEN, + xvap.xva_xoptattrs.xoa_hidden); + FLAG_CHANGE(UF_REPARSE, ZFS_REPARSE, XAT_REPARSE, + xvap.xva_xoptattrs.xoa_hidden); + FLAG_CHANGE(UF_OFFLINE, ZFS_OFFLINE, XAT_OFFLINE, + xvap.xva_xoptattrs.xoa_offline); + FLAG_CHANGE(UF_SPARSE, ZFS_SPARSE, XAT_SPARSE, + xvap.xva_xoptattrs.xoa_sparse); #undef FLAG_CHANGE } return (zfs_setattr(vp, (vattr_t *)&xvap, 0, cred, NULL)); diff --git a/sys/fs/msdosfs/msdosfs_denode.c b/sys/fs/msdosfs/msdosfs_denode.c index 501604a..b2a51ea 100644 --- a/sys/fs/msdosfs/msdosfs_denode.c +++ b/sys/fs/msdosfs/msdosfs_denode.c @@ -304,8 +304,8 @@ deupdat(dep, waitfor) if ((dep->de_flag & DE_MODIFIED) == 0 && waitfor == 0) return (0); dep->de_flag &= ~DE_MODIFIED; - if (dep->de_Attributes & ATTR_DIRECTORY) - return (0); + if (DETOV(dep)->v_vflag & VV_ROOT) + return (EINVAL); if (dep->de_refcnt <= 0) return (0); error = readde(dep, &bp, &dirp); diff --git a/sys/fs/msdosfs/msdosfs_vnops.c b/sys/fs/msdosfs/msdosfs_vnops.c index da9a5df..04cb372 100644 --- a/sys/fs/msdosfs/msdosfs_vnops.c +++ b/sys/fs/msdosfs/msdosfs_vnops.c @@ -172,8 +172,7 @@ msdosfs_create(ap) if (error) goto bad; - ndirent.de_Attributes = (ap->a_vap->va_mode & VWRITE) ? - ATTR_ARCHIVE : ATTR_ARCHIVE | ATTR_READONLY; + ndirent.de_Attributes = ATTR_ARCHIVE; ndirent.de_LowerCase = 0; ndirent.de_StartCluster = 0; ndirent.de_FileSize = 0; @@ -256,8 +255,7 @@ msdosfs_access(ap) mode_t file_mode; accmode_t accmode = ap->a_accmode; - file_mode = (S_IXUSR|S_IXGRP|S_IXOTH) | (S_IRUSR|S_IRGRP|S_IROTH) | - ((dep->de_Attributes & ATTR_READONLY) ? 0 : (S_IWUSR|S_IWGRP|S_IWOTH)); + file_mode = S_IRWXU|S_IRWXG|S_IRWXO; file_mode &= (vp->v_type == VDIR ? pmp->pm_dirmask : pmp->pm_mask); /* @@ -266,8 +264,8 @@ msdosfs_access(ap) */ if (accmode & VWRITE) { switch (vp->v_type) { - case VDIR: case VREG: + case VDIR: if (vp->v_mount->mnt_flag & MNT_RDONLY) return (EROFS); break; @@ -322,10 +320,7 @@ msdosfs_getattr(ap) else vap->va_fileid = (long)fileid; - if ((dep->de_Attributes & ATTR_READONLY) == 0) - mode = S_IRWXU|S_IRWXG|S_IRWXO; - else - mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH; + mode = S_IRWXU|S_IRWXG|S_IRWXO; vap->va_mode = mode & (ap->a_vp->v_type == VDIR ? pmp->pm_dirmask : pmp->pm_mask); vap->va_uid = pmp->pm_uid; @@ -345,8 +340,14 @@ msdosfs_getattr(ap) vap->va_birthtime.tv_nsec = 0; } vap->va_flags = 0; - if ((dep->de_Attributes & ATTR_ARCHIVE) == 0) - vap->va_flags |= SF_ARCHIVED; + if (dep->de_Attributes & ATTR_ARCHIVE) + vap->va_flags |= UF_ARCHIVE; + if (dep->de_Attributes & ATTR_HIDDEN) + vap->va_flags |= UF_HIDDEN; + if (dep->de_Attributes & ATTR_READONLY) + vap->va_flags |= UF_READONLY; + if (dep->de_Attributes & ATTR_SYSTEM) + vap->va_flags |= UF_SYSTEM; vap->va_gen = 0; vap->va_blocksize = pmp->pm_bpcluster; vap->va_bytes = @@ -395,6 +396,18 @@ msdosfs_setattr(ap) #endif return (EINVAL); } + + /* + * We don't allow setting attributes on the root directory. + * The special case for the root directory is because before + * FAT32, the root directory didn't have an entry for itself + * (and was otherwise special). With FAT32, the root + * directory is not so special, but still doesn't have an + * entry for itself. + */ + if (vp->v_vflag & VV_ROOT) + return (EINVAL); + if (vap->va_flags != VNOVAL) { if (vp->v_mount->mnt_flag & MNT_RDONLY) return (EROFS); @@ -408,24 +421,29 @@ msdosfs_setattr(ap) * attributes. We ignored the access time and the * read and execute bits. We were strict for the other * attributes. - * - * Here we are strict, stricter than ufs in not allowing - * users to attempt to set SF_SETTABLE bits or anyone to - * set unsupported bits. However, we ignore attempts to - * set ATTR_ARCHIVE for directories `cp -pr' from a more - * sensible filesystem attempts it a lot. */ - if (vap->va_flags & SF_SETTABLE) { - error = priv_check_cred(cred, PRIV_VFS_SYSFLAGS, 0); - if (error) - return (error); - } - if (vap->va_flags & ~SF_ARCHIVED) + if (vap->va_flags & ~(UF_ARCHIVE | UF_HIDDEN | UF_READONLY | + UF_SYSTEM)) return EOPNOTSUPP; - if (vap->va_flags & SF_ARCHIVED) - dep->de_Attributes &= ~ATTR_ARCHIVE; - else if (!(dep->de_Attributes & ATTR_DIRECTORY)) + if (vap->va_flags & UF_ARCHIVE) dep->de_Attributes |= ATTR_ARCHIVE; + else + dep->de_Attributes &= ~ATTR_ARCHIVE; + if (vap->va_flags & UF_HIDDEN) + dep->de_Attributes |= ATTR_HIDDEN; + else + dep->de_Attributes &= ~ATTR_HIDDEN; + /* We don't allow changing the readonly bit on directories. */ + if (vp->v_type != VDIR) { + if (vap->va_flags & UF_READONLY) + dep->de_Attributes |= ATTR_READONLY; + else + dep->de_Attributes &= ~ATTR_READONLY; + } + if (vap->va_flags & UF_SYSTEM) + dep->de_Attributes |= ATTR_SYSTEM; + else + dep->de_Attributes &= ~ATTR_SYSTEM; dep->de_flag |= DE_MODIFIED; } @@ -489,21 +507,24 @@ msdosfs_setattr(ap) error = VOP_ACCESS(vp, VWRITE, cred, td); } else error = VOP_ACCESS(vp, VADMIN, cred, td); - if (vp->v_type != VDIR) { - if ((pmp->pm_flags & MSDOSFSMNT_NOWIN95) == 0 && - vap->va_atime.tv_sec != VNOVAL) { - dep->de_flag &= ~DE_ACCESS; - timespec2fattime(&vap->va_atime, 0, - &dep->de_ADate, NULL, NULL); - } - if (vap->va_mtime.tv_sec != VNOVAL) { - dep->de_flag &= ~DE_UPDATE; - timespec2fattime(&vap->va_mtime, 0, - &dep->de_MDate, &dep->de_MTime, NULL); - } - dep->de_Attributes |= ATTR_ARCHIVE; - dep->de_flag |= DE_MODIFIED; + if ((pmp->pm_flags & MSDOSFSMNT_NOWIN95) == 0 && + vap->va_atime.tv_sec != VNOVAL) { + dep->de_flag &= ~DE_ACCESS; + timespec2fattime(&vap->va_atime, 0, + &dep->de_ADate, NULL, NULL); } + if (vap->va_mtime.tv_sec != VNOVAL) { + dep->de_flag &= ~DE_UPDATE; + timespec2fattime(&vap->va_mtime, 0, + &dep->de_MDate, &dep->de_MTime, NULL); + } + /* + * We don't set the archive bit when modifying the time of + * a directory to emulate the Windows/DOS behavior. + */ + if (vp->v_type != VDIR) + dep->de_Attributes |= ATTR_ARCHIVE; + dep->de_flag |= DE_MODIFIED; } /* * DOS files only have the ability to have their writability 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) diff --git a/sys/sys/param.h b/sys/sys/param.h index d18cc15..e157354 100644 --- a/sys/sys/param.h +++ b/sys/sys/param.h @@ -58,7 +58,7 @@ * in the range 5 to 9. */ #undef __FreeBSD_version -#define __FreeBSD_version 1000046 /* Master, propagated to newvers */ +#define __FreeBSD_version 1000047 /* Master, propagated to newvers */ /* * __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD, diff --git a/sys/sys/stat.h b/sys/sys/stat.h index f430a9a..0f3284f 100644 --- a/sys/sys/stat.h +++ b/sys/sys/stat.h @@ -265,8 +265,26 @@ struct nstat { #define UF_NODUMP 0x00000001 /* do not dump file */ #define UF_IMMUTABLE 0x00000002 /* file may not be changed */ #define UF_APPEND 0x00000004 /* writes to file may only append */ -#define UF_OPAQUE 0x00000008 /* directory is opaque wrt. union */ -#define UF_NOUNLINK 0x00000010 /* file may not be removed or renamed */ +#define UF_OPAQUE 0x00000008 /* directory is opaque wrt. union */ +#define UF_NOUNLINK 0x00000010 /* file may not be removed or renamed */ +/* + * These two bits are defined in MacOS X. They are not currently used in + * FreeBSD. + */ +#if 0 +#define UF_COMPRESSED 0x00000020 /* file is compressed */ +#define UF_TRACKED 0x00000040 /* renames and deletes are tracked */ +#endif + +#define UF_SYSTEM 0x00000080 /* Windows system file bit */ +#define UF_SPARSE 0x00000100 /* sparse file */ +#define UF_OFFLINE 0x00000200 /* file is offline */ +#define UF_REPARSE 0x00000400 /* Windows reparse point file bit */ +#define UF_ARCHIVE 0x00000800 /* file needs to be archived */ +#define UF_READONLY 0x00001000 /* Windows readonly file bit */ +/* This is the same as the MacOS X definition of UF_HIDDEN. */ +#define UF_HIDDEN 0x00008000 /* file is hidden */ + /* * Super-user changeable flags. */ diff --git a/sys/ufs/ufs/ufs_vnops.c b/sys/ufs/ufs/ufs_vnops.c index 729e967..56e24a3 100644 --- a/sys/ufs/ufs/ufs_vnops.c +++ b/sys/ufs/ufs/ufs_vnops.c @@ -528,9 +528,11 @@ ufs_setattr(ap) return (EINVAL); } if (vap->va_flags != VNOVAL) { - if ((vap->va_flags & ~(UF_NODUMP | UF_IMMUTABLE | UF_APPEND | - UF_OPAQUE | UF_NOUNLINK | SF_ARCHIVED | SF_IMMUTABLE | - SF_APPEND | SF_NOUNLINK | SF_SNAPSHOT)) != 0) + if ((vap->va_flags & ~(SF_APPEND | SF_ARCHIVED | SF_IMMUTABLE | + SF_NOUNLINK | SF_SNAPSHOT | UF_APPEND | UF_ARCHIVE | + UF_HIDDEN | UF_IMMUTABLE | UF_NODUMP | UF_NOUNLINK | + UF_OFFLINE | UF_OPAQUE | UF_READONLY | UF_REPARSE | + UF_SPARSE | UF_SYSTEM)) != 0) return (EOPNOTSUPP); if (vp->v_mount->mnt_flag & MNT_RDONLY) return (EROFS); |