Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 17 Jan 2011 16:32:18 -0800
From:      Garrett Cooper <yanegomi@gmail.com>
To:        fs@freebsd.org
Subject:   Inconsistency and bug with *chflags functions
Message-ID:  <AANLkTintj_eM=aRF4pO8PcT8VXvVJ=Booxag%2BwBg3gaX@mail.gmail.com>

index | next in thread | raw e-mail

[-- Attachment #1 --]
Hi FS folks,

    Originally I did this to determine why lchflags had an int
argument and chflags/fchflags had unsigned long arguments, and I ran
into an interesting mini-project (by accident) after I found a few
bugs lurking in the vfs_syscalls.c layer of the kernel.

    So here's the deal...

Problems:
1. chflags/fchflags claim that the flags argument is an unsigned long,
whereas lchflags claims it's an int. This is inconsistent.
2. The kernel interfaces are all implicitly downcasting the flags
argument to int.
3. There's a sizing/signedness discrepancy in a few other structures
with fixed-width data types (uint32_t).

Solution:
1. I opted to convert fflags_t to uint32_t and convert all references
which did direct conversions to and from st_flags to fflags_t to avoid
32-bit / 64-bit biarch issues. I downgraded it to uint32_t as we're no
where near the limit for the number of usable flags to *chflags(2).
2. *chflags now uses fflags_t instead of int/unsigned long.
3. c_file_flags in dumprestore.h was changed to be in sync with st_flags.
4. di_flags in ufs/ufs/dinode.h was changed to be in sync with st_flags.

Compatibility:
1. NetBSD uses unsigned long in their chflags calls (both in kernel
and userland) so they're more consistent than we are by not having
mixed flags calling convention like us, but uses uint32_t in their
data structures (like we do), so they have a 32-bit/64-bit biarch bug
(again like we do).
2. OpenBSD is using unsigned int, so I assume that their kernel layer
is also using unsigned int (I am basing this purely off the manpage as
I haven't looked at their sources, but I could be wrong).

    I'm running make universe just to see if it will barf in the
build, but would someone please review this change (I made the change
as minimal as possible for ease of review) and provide feedback?
Thanks,
-Garrett

PS Please CC me on all replies as I'm not subscribed to the list.

[-- Attachment #2 --]
Index: include/protocols/dumprestore.h
===================================================================
--- include/protocols/dumprestore.h	(revision 217362)
+++ include/protocols/dumprestore.h	(working copy)
@@ -95,7 +95,7 @@
 		int64_t	c_mtime;	    /* last modified time, seconds */
 		int32_t	c_extsize;	    /* external attribute size */
 		int32_t	c_spare4[6];	    /* old block pointers */
-		u_int32_t c_file_flags;	    /* status flags (chflags) */
+		fflags_t c_file_flags;	    /* status flags (chflags) */
 		int32_t	c_spare5[2];	    /* old blocks, generation number */
 		u_int32_t c_uid;	    /* file owner */
 		u_int32_t c_gid;	    /* file group */
Index: lib/libc/sys/chflags.2
===================================================================
--- lib/libc/sys/chflags.2	(revision 217362)
+++ lib/libc/sys/chflags.2	(working copy)
@@ -42,11 +42,11 @@
 .In sys/stat.h
 .In unistd.h
 .Ft int
-.Fn chflags "const char *path" "u_long flags"
+.Fn chflags "const char *path" "fflags_t flags"
 .Ft int
-.Fn lchflags "const char *path" "int flags"
+.Fn lchflags "const char *path" "fflags_t flags"
 .Ft int
-.Fn fchflags "int fd" "u_long flags"
+.Fn fchflags "int fd" "fflags_t flags"
 .Sh DESCRIPTION
 The file whose name
 is given by
Index: sbin/restore/tape.c
===================================================================
--- sbin/restore/tape.c	(revision 217362)
+++ sbin/restore/tape.c	(working copy)
@@ -558,7 +558,7 @@
 int
 extractfile(char *name)
 {
-	int flags;
+	fflags_t flags;
 	uid_t uid;
 	gid_t gid;
 	mode_t mode;
Index: sys/kern/vfs_syscalls.c
===================================================================
--- sys/kern/vfs_syscalls.c	(revision 217362)
+++ sys/kern/vfs_syscalls.c	(working copy)
@@ -96,7 +96,7 @@
 static int getutimes(const struct timeval *, enum uio_seg, struct timespec *);
 static int setfown(struct thread *td, struct vnode *, uid_t, gid_t);
 static int setfmode(struct thread *td, struct vnode *, int);
-static int setfflags(struct thread *td, struct vnode *, int);
+static int setfflags(struct thread *td, struct vnode *, fflags_t);
 static int setutimes(struct thread *td, struct vnode *,
     const struct timespec *, int, int);
 static int vn_access(struct vnode *vp, int user_flags, struct ucred *cred,
@@ -2657,7 +2657,7 @@
 setfflags(td, vp, flags)
 	struct thread *td;
 	struct vnode *vp;
-	int flags;
+	fflags_t flags;
 {
 	int error;
 	struct mount *mp;
@@ -2695,8 +2695,8 @@
  */
 #ifndef _SYS_SYSPROTO_H_
 struct chflags_args {
-	char	*path;
-	int	flags;
+	char		*path;
+	fflags_t	flags;
 };
 #endif
 int
@@ -2704,7 +2704,7 @@
 	struct thread *td;
 	register struct chflags_args /* {
 		char *path;
-		int flags;
+		fflags_t flags;
 	} */ *uap;
 {
 	int error;
@@ -2732,7 +2732,7 @@
 	struct thread *td;
 	register struct lchflags_args /* {
 		char *path;
-		int flags;
+		fflags_t flags;
 	} */ *uap;
 {
 	int error;
@@ -2757,8 +2757,8 @@
  */
 #ifndef _SYS_SYSPROTO_H_
 struct fchflags_args {
-	int	fd;
-	int	flags;
+	int		fd;
+	fflags_t	flags;
 };
 #endif
 int
@@ -2766,7 +2766,7 @@
 	struct thread *td;
 	register struct fchflags_args /* {
 		int fd;
-		int flags;
+		fflags_t flags;
 	} */ *uap;
 {
 	struct file *fp;
Index: sys/sys/stat.h
===================================================================
--- sys/sys/stat.h	(revision 217362)
+++ sys/sys/stat.h	(working copy)
@@ -292,11 +292,11 @@
 #ifndef _KERNEL
 __BEGIN_DECLS
 #if __BSD_VISIBLE
-int	chflags(const char *, unsigned long);
+int	chflags(const char *, fflags_t);
 #endif
 int	chmod(const char *, mode_t);
 #if __BSD_VISIBLE
-int	fchflags(int, unsigned long);
+int	fchflags(int, fflags_t);
 #endif
 #if __POSIX_VISIBLE >= 200112
 int	fchmod(int, mode_t);
@@ -306,7 +306,7 @@
 #endif
 int	fstat(int, struct stat *);
 #if __BSD_VISIBLE
-int	lchflags(const char *, int);
+int	lchflags(const char *, fflags_t);
 int	lchmod(const char *, mode_t);
 #endif
 #if __POSIX_VISIBLE >= 200112
Index: sys/ufs/ufs/dinode.h
===================================================================
--- sys/ufs/ufs/dinode.h	(revision 217362)
+++ sys/ufs/ufs/dinode.h	(working copy)
@@ -140,7 +140,7 @@
 	int32_t		di_birthnsec;	/*  76: Inode creation time. */
 	int32_t		di_gen;		/*  80: Generation number. */
 	u_int32_t	di_kernflags;	/*  84: Kernel flags. */
-	u_int32_t	di_flags;	/*  88: Status flags (chflags). */
+	fflags_t	di_flags;	/*  88: Status flags (chflags). */
 	int32_t		di_extsize;	/*  92: External attributes block. */
 	ufs2_daddr_t	di_extb[NXADDR];/*  96: External attributes block. */
 	ufs2_daddr_t	di_db[NDADDR];	/* 112: Direct disk blocks. */
Index: tools/regression/pjdfstest/pjdfstest.c
===================================================================
--- tools/regression/pjdfstest/pjdfstest.c	(revision 217362)
+++ tools/regression/pjdfstest/pjdfstest.c	(working copy)
@@ -578,12 +577,14 @@
 		break;
 #ifdef HAS_CHFLAGS
 	case ACTION_CHFLAGS:
-		rval = chflags(STR(0), (unsigned long)str2flags(chflags_flags, STR(1)));
+		rval = chflags(STR(0),
+		    (fflags_t)str2flags(chflags_flags, STR(1)));
 		break;
 #endif
 #ifdef HAS_LCHFLAGS
 	case ACTION_LCHFLAGS:
-		rval = lchflags(STR(0), (int)str2flags(chflags_flags, STR(1)));
+		rval = lchflags(STR(0),
+		    (fflags_t)str2flags(chflags_flags, STR(1)));
 		break;
 #endif
 	case ACTION_TRUNCATE:
help

Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?AANLkTintj_eM=aRF4pO8PcT8VXvVJ=Booxag%2BwBg3gaX>