From owner-freebsd-fs@FreeBSD.ORG Fri Apr 26 22:10:26 2013 Return-Path: Delivered-To: fs@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by hub.freebsd.org (Postfix) with ESMTP id B5BD8BE8; Fri, 26 Apr 2013 22:10:26 +0000 (UTC) (envelope-from ken@kdm.org) Received: from nargothrond.kdm.org (nargothrond.kdm.org [70.56.43.81]) by mx1.freebsd.org (Postfix) with ESMTP id E785F10EC; Fri, 26 Apr 2013 22:10:25 +0000 (UTC) Received: from nargothrond.kdm.org (localhost [127.0.0.1]) by nargothrond.kdm.org (8.14.2/8.14.2) with ESMTP id r3QMANCJ087741; Fri, 26 Apr 2013 16:10:23 -0600 (MDT) (envelope-from ken@nargothrond.kdm.org) Received: (from ken@localhost) by nargothrond.kdm.org (8.14.2/8.14.2/Submit) id r3QMANeU087740; Fri, 26 Apr 2013 16:10:23 -0600 (MDT) (envelope-from ken) Date: Fri, 26 Apr 2013 16:10:23 -0600 From: "Kenneth D. Merry" To: Bruce Evans Subject: Re: patches to add new stat(2) file flags Message-ID: <20130426221023.GA86767@nargothrond.kdm.org> References: <20130307000533.GA38950@nargothrond.kdm.org> <20130307222553.P981@besplex.bde.org> <20130308232155.GA47062@nargothrond.kdm.org> <20130310181127.D2309@besplex.bde.org> <20130409190838.GA60733@nargothrond.kdm.org> <20130418184951.GA18777@nargothrond.kdm.org> <20130419215624.L1262@besplex.bde.org> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="oyUTqETQ0mS9luUI" Content-Disposition: inline In-Reply-To: <20130419215624.L1262@besplex.bde.org> User-Agent: Mutt/1.4.2i Cc: arch@FreeBSD.org, fs@FreeBSD.org X-BeenThere: freebsd-fs@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: Filesystems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 26 Apr 2013 22:10:26 -0000 --oyUTqETQ0mS9luUI Content-Type: text/plain; charset=us-ascii Content-Disposition: inline On Fri, Apr 19, 2013 at 22:53:50 +1000, Bruce Evans wrote: > On Thu, 18 Apr 2013, Kenneth D. Merry wrote: > > >On Tue, Apr 09, 2013 at 13:08:38 -0600, Kenneth D. Merry wrote: > >>... > >>Okay, I think these issues should now be fixed. We now refuse to change > >>attributes only on the root directory. And I updatd deupdat() to do the > >>same. > >> > >>When a directory is created or a file is added, the archive bit is not > >>changed on the directory. Not sure if we need to do that or not. (Simply > >>changing msdosfs_mkdir() to set ATTR_ARCHIVE was not enough to get the > >>archive bit set on directory creation.) > > > >Bruce, any comment on this? > > I didn't get around to looking at it closely. Just had a quick look at > the msdosfs parts. > > Apparently we are already doing the same as WinXP for ATTR_ARCHIVE on > directories. Not the right thing, but: > - don't set it on directory creation > - don't set it on directory modification > - allow setting and clearing it (with your changes). > > @ *** src/lib/libc/sys/chflags.2.orig > @ --- src/lib/libc/sys/chflags.2 > @ *************** > @ *** 112,137 **** > @ ... > @ --- 112,170 ---- > @ ... > @ + .It Dv UF_IMMUTABLE > @ + The file may not be changed. > @ + Filesystems may use this flag to maintain compatibility with the DOS, > Windows > @ + and CIFS FILE_ATTRIBUTE_READONLY attribute. > > msdosfs doesn't use this yet. It uses ATTR_READONLY, and doesn't map this > to or from UF_IMMUTABLE. I think I want ATTR_READONLY to be a flag and > not affect the file permissions (just like immutable flags normally don't > affect the file permissions. Okay, done. The permissions are now always 755, and writeability is controlled by ATTR_READONLY. > Does CIFS FILE_ATTRIBUTE_READONLY have exactly the same semantics as > IMMUTABLE? That is, does it prevent all operations on the file and the > file's metadata except read()? For IMMUTABLE, the other operations that > it disallows include setattr(), rename() and unlink(). > > Well it doesn't in WinXP using Cygwin. I made a directory with attributes > +R, and this didn't prevent creating files in the directory or rmdir of > the directory. Even attributes +R +H +S didn't prevent these operations. > Maybe +R isn't really used for directories, like +A. Then for a file with > +R +H +S: > - rm asked before deleting it (+R changed its fake permissions from > rw-r--r-- to r--r--r--). > - touching it succeeded > - attrib on it succeeded > - writing it failed. > So it seems that in WinXP, ATTR_READONLY is ignored for directories, and > more like the !writeable permission than the immutable flag. Okay. I added a new flag, UF_READONLY that maps to ATTR_READONLY directly instead of using an immutable flag. > @ *** src/sys/fs/msdosfs/msdosfs_denode.c.orig > @ --- src/sys/fs/msdosfs/msdosfs_denode.c > @ *************** > @ *** 300,307 **** > @ if ((dep->de_flag & DE_MODIFIED) == 0) > @ return (0); > @ dep->de_flag &= ~DE_MODIFIED; > @ ! if (dep->de_Attributes & ATTR_DIRECTORY) > @ ! return (0); > @ if (dep->de_refcnt <= 0) > @ return (0); > @ error = readde(dep, &bp, &dirp); > @ --- 300,309 ---- > @ if ((dep->de_flag & DE_MODIFIED) == 0) > @ return (0); > @ dep->de_flag &= ~DE_MODIFIED; > @ ! /* Was: silently ignore attribute changes for all dirs. */ > @ ! if (DETOV(dep)->v_vflag & VV_ROOT) > @ ! return (EINVAL); > @ ! /* Otherwise valid. */ > > Clean up the comments a bit. Say nothing, or that all attributes apply > to all directories except the root directory. Okay, I took them out. > Perhaps the VV_ROOT case is unreachable because callers filter out this > case. I have a debugger trap for it. Maybe. I left it in there just in case. > @ if (dep->de_refcnt <= 0) > @ return (0); > @ error = readde(dep, &bp, &dirp); > @ *** src/sys/fs/msdosfs/msdosfs_vnops.c.orig > @ --- src/sys/fs/msdosfs/msdosfs_vnops.c > @ *************** > @ *** 398,403 **** > @ --- 402,418 ---- > @ if (vap->va_flags != VNOVAL) { > @ if (vp->v_mount->mnt_flag & MNT_RDONLY) > @ return (EROFS); > @ + /* > @ + * We don't allow setting attributes on the root directory, > @ + * because according to Bruce Evans: "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 (cred->cr_uid != pmp->pm_uid) { > @ error = priv_check_cred(cred, PRIV_VFS_ADMIN, 0); > @ if (error) > > No need to give the source. Fixed. > I prefer the do this check after the permissions check, but if it is done > early then it is best done as a single check for all attributes in > msdosfs_settattr() and not just for flags. Currently there is: > - no check for ownerships. We only allow null changes to ownerships. With > no check like the above, we allow them even for the root directory, while > the above disallows null changes to flags for the root directory. > - for truncate(), the error is EISDIR for all directories. > - for file times, we silently ignore changes for all directories, after > doing > permissions checks. Only the root directory should be special. > - for file permissions, we handle directories as for file times. Now the > only possible non-null change is of ATTR_READONLY, and since this > apparently has no effect in WinXP, ignorig changing it for directories > is best. I think these should all be fixed with the attached patch. Take a look and let me know. The other outstanding issue is the suggestion by Gordon Ross on the Illumos developers list to make ZFS not enforce the readonly bit. It looks like it has not yet gone into Illumos. We may not want to make the change in FreeBSD since it hasn't gone in upstream yet. Ken -- Kenneth Merry ken@FreeBSD.ORG --oyUTqETQ0mS9luUI Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="file_flags_head.20130426.1.txt" *** src/bin/chflags/chflags.1.orig --- src/bin/chflags/chflags.1 *************** *** 32,38 **** .\" @(#)chflags.1 8.4 (Berkeley) 5/2/95 .\" $FreeBSD: head/bin/chflags/chflags.1 213573 2010-10-08 12:40:16Z uqs $ .\" ! .Dd March 3, 2006 .Dt CHFLAGS 1 .Os .Sh NAME --- 32,38 ---- .\" @(#)chflags.1 8.4 (Berkeley) 5/2/95 .\" $FreeBSD: head/bin/chflags/chflags.1 213573 2010-10-08 12:40:16Z uqs $ .\" ! .Dd April 8, 2013 .Dt CHFLAGS 1 .Os .Sh NAME *************** *** 101,120 **** .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 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 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 uchg , uchange , uimmutable set the user immutable flag (owner or super-user only) .It Cm uunlnk , uunlink set the user undeletable flag (owner or super-user only) .El --- 101,136 ---- .Bl -tag -offset indent -width ".Cm opaque" .It Cm arch , archived set the archived flag (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 *** src/bin/ls/ls.1.orig --- src/bin/ls/ls.1 *************** *** 232,237 **** --- 232,240 ---- 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 / *** src/lib/libc/gen/strtofflags.c.orig --- src/lib/libc/gen/strtofflags.c *************** *** 62,74 **** #endif { "nouappnd", 0, UF_APPEND }, { "nouappend", 0, UF_APPEND }, { "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 } }; #define nmappings (sizeof(mapping) / sizeof(mapping[0])) --- 62,90 ---- #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 }, + { "nouunlnk", 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])) *** src/lib/libc/sys/chflags.2.orig --- src/lib/libc/sys/chflags.2 *************** *** 112,137 **** 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 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. .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. .El .Pp If one of --- 112,172 ---- the following values .Pp .Bl -tag -width ".Dv SF_IMMUTABLE" -compact -offset indent ! .It Dv SF_APPEND The file may only be appended to. .It Dv SF_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_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,167 **** --- 197,209 ---- .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. *** src/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c.orig --- src/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c *************** *** 6067,6072 **** --- 6067,6080 ---- 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); *************** *** 6082,6089 **** --- 6090,6112 ---- 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; *************** *** 6121,6127 **** return (EOPNOTSUPP); fflags = vap->va_flags; ! if ((fflags & ~(SF_IMMUTABLE|SF_APPEND|SF_NOUNLINK|UF_NODUMP)) != 0) return (EOPNOTSUPP); /* * Unprivileged processes are not permitted to unset system --- 6144,6159 ---- return (EOPNOTSUPP); fflags = vap->va_flags; ! /* ! * 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 *************** *** 6173,6180 **** --- 6205,6226 ---- 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)); *** src/sys/fs/msdosfs/msdosfs_denode.c.orig --- src/sys/fs/msdosfs/msdosfs_denode.c *************** *** 300,307 **** if ((dep->de_flag & DE_MODIFIED) == 0) return (0); dep->de_flag &= ~DE_MODIFIED; ! if (dep->de_Attributes & ATTR_DIRECTORY) ! return (0); if (dep->de_refcnt <= 0) return (0); error = readde(dep, &bp, &dirp); --- 300,307 ---- if ((dep->de_flag & DE_MODIFIED) == 0) return (0); dep->de_flag &= ~DE_MODIFIED; ! if (DETOV(dep)->v_vflag & VV_ROOT) ! return (EINVAL); if (dep->de_refcnt <= 0) return (0); error = readde(dep, &bp, &dirp); *** src/sys/fs/msdosfs/msdosfs_vnops.c.orig --- src/sys/fs/msdosfs/msdosfs_vnops.c *************** *** 172,179 **** if (error) goto bad; ! ndirent.de_Attributes = (ap->a_vap->va_mode & VWRITE) ? ! ATTR_ARCHIVE : ATTR_ARCHIVE | ATTR_READONLY; ndirent.de_LowerCase = 0; ndirent.de_StartCluster = 0; ndirent.de_FileSize = 0; --- 172,178 ---- if (error) goto bad; ! ndirent.de_Attributes = ATTR_ARCHIVE; ndirent.de_LowerCase = 0; ndirent.de_StartCluster = 0; ndirent.de_FileSize = 0; *************** *** 256,273 **** 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 &= (vp->v_type == VDIR ? pmp->pm_dirmask : pmp->pm_mask); /* * Disallow writing to directories and regular files if the ! * filesystem is read-only. */ if (accmode & VWRITE) { switch (vp->v_type) { case VDIR: - case VREG: if (vp->v_mount->mnt_flag & MNT_RDONLY) return (EROFS); break; --- 255,274 ---- mode_t file_mode; accmode_t accmode = ap->a_accmode; ! file_mode = S_IRWXU|S_IRWXG|S_IRWXO; file_mode &= (vp->v_type == VDIR ? pmp->pm_dirmask : pmp->pm_mask); /* * Disallow writing to directories and regular files if the ! * filesystem is read-only. Check the readonly attribute for ! * regular files and refuse to allow writing. */ if (accmode & VWRITE) { switch (vp->v_type) { + case VREG: + if (dep->de_Attributes & ATTR_READONLY) + return (EACCES); case VDIR: if (vp->v_mount->mnt_flag & MNT_RDONLY) return (EROFS); break; *************** *** 322,331 **** 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; vap->va_mode = mode & (ap->a_vp->v_type == VDIR ? pmp->pm_dirmask : pmp->pm_mask); vap->va_uid = pmp->pm_uid; --- 323,329 ---- else vap->va_fileid = (long)fileid; ! 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,352 **** vap->va_birthtime.tv_nsec = 0; } vap->va_flags = 0; ! if ((dep->de_Attributes & ATTR_ARCHIVE) == 0) ! vap->va_flags |= SF_ARCHIVED; vap->va_gen = 0; vap->va_blocksize = pmp->pm_bpcluster; vap->va_bytes = --- 343,356 ---- vap->va_birthtime.tv_nsec = 0; } vap->va_flags = 0; ! 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,400 **** --- 399,416 ---- #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,431 **** * 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) return EOPNOTSUPP; ! if (vap->va_flags & SF_ARCHIVED) dep->de_Attributes &= ~ATTR_ARCHIVE; ! else if (!(dep->de_Attributes & ATTR_DIRECTORY)) ! dep->de_Attributes |= ATTR_ARCHIVE; dep->de_flag |= DE_MODIFIED; } --- 424,452 ---- * attributes. We ignored the access time and the * read and execute bits. We were strict for the other * attributes. */ ! if (vap->va_flags & ~(UF_ARCHIVE | UF_HIDDEN | UF_READONLY | ! UF_SYSTEM)) return EOPNOTSUPP; ! 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,509 **** 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; } } /* * DOS files only have the ability to have their writability --- 510,528 ---- error = VOP_ACCESS(vp, VWRITE, cred, td); } else error = VOP_ACCESS(vp, VADMIN, cred, td); ! 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; } /* * DOS files only have the ability to have their writability *** src/sys/fs/smbfs/smbfs_node.c.orig --- src/sys/fs/smbfs/smbfs_node.c *************** *** 370,379 **** if (diff > 2) /* XXX should be configurable */ return ENOENT; va->va_type = vp->v_type; /* vnode type (for create) */ if (vp->v_type == VREG) { va->va_mode = smp->sm_file_mode; /* files access mode and type */ ! if (np->n_dosattr & SMB_FA_RDONLY) va->va_mode &= ~(S_IWUSR|S_IWGRP|S_IWOTH); } else if (vp->v_type == VDIR) { va->va_mode = smp->sm_dir_mode; /* files access mode and type */ } else --- 370,382 ---- 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) { 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,396 **** 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 */ 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 */ --- 393,407 ---- 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 */ ! 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 */ *** src/sys/fs/smbfs/smbfs_vnops.c.orig --- src/sys/fs/smbfs/smbfs_vnops.c *************** *** 305,320 **** 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) return EROFS; scred = smbfs_malloc_scred(); smb_makescred(scred, td, ap->a_cred); if (vap->va_size != VNOVAL) { --- 305,334 ---- int old_n_dosattr; SMBVDEBUG("\n"); 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 || 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,364 **** goto out; } } ! if (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 (np->n_dosattr != old_n_dosattr) { error = smbfs_smb_setpattr(np, np->n_dosattr, NULL, scred); if (error) --- 367,413 ---- goto out; } } ! if ((vap->va_flags != VNOVAL) || (vap->va_mode != (mode_t)VNOVAL)) { old_n_dosattr = np->n_dosattr; ! ! 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) *** src/sys/sys/stat.h.orig --- src/sys/sys/stat.h *************** *** 265,272 **** #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 */ /* * Super-user changeable flags. */ --- 265,290 ---- #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 */ ! /* ! * 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. */ *** src/sys/ufs/ufs/ufs_vnops.c.orig --- src/sys/ufs/ufs/ufs_vnops.c *************** *** 528,536 **** 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) return (EOPNOTSUPP); if (vp->v_mount->mnt_flag & MNT_RDONLY) return (EROFS); --- 528,538 ---- return (EINVAL); } if (vap->va_flags != VNOVAL) { ! 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); --oyUTqETQ0mS9luUI--