Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 26 Apr 2013 16:10:23 -0600
From:      "Kenneth D. Merry" <ken@FreeBSD.org>
To:        Bruce Evans <brde@optusnet.com.au>
Cc:        arch@FreeBSD.org, fs@FreeBSD.org
Subject:   Re: patches to add new stat(2) file flags
Message-ID:  <20130426221023.GA86767@nargothrond.kdm.org>
In-Reply-To: <20130419215624.L1262@besplex.bde.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>

next in thread | previous in thread | raw e-mail | index | archive | help

--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--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20130426221023.GA86767>