What is wrong with this code ?

Guy Harris guy at auspex.UUCP
Sun Dec 17 06:35:18 AEST 1989


(What's wrong with the original code is an error in using C; what's
wrong with the reply to which I'm following up is an error in using UNIX
- a real doozy at that, and one that I see all too often - so I'm moving
that particular thread of the discussion to "comp.unix.questions".)

>> if (nfile.st_mode & S_IFMT == S_IFREG) 
>> else if (nfile.st_mode & S_IFMT == S_IEXEC) 
>
>Additionally, we don't want to mask permissions against S_IFMT.

That is true, but:

>For that matter, we don't need to mask type against S_IFMT.

Bzzzt!  Sorry, wrong answer.  You *do* need to mask type against S_IFMT:

>Don't we really want
>if (nfile.st_mode & S_IFREG) 
>	printf(...);
>else if (nfile.st_mode & S_IFDIR)
>	printf(...);

No, we don't - not one bit (no pun intended :-)).  From the SunOS 4.0.3
<sys/stat.h>, the values in which reflect those in every other
AT&T-derived UNIX I know of (except possibly for some of the newer mode
bits, but I suspect that S_IFLNK is the same in S5R4 and 4.xBSD....)

	#define	S_IFMT	0170000		/* type of file */
	#define		S_IFDIR	0040000	/* directory */
	#define		S_IFCHR	0020000	/* character special */
	#define		S_IFBLK	0060000	/* block special */
	#define		S_IFREG	0100000	/* regular */
	#define		S_IFLNK	0120000	/* symbolic link */
	#define		S_IFSOCK 0140000/* socket */
	#define		S_IFIFO	0010000	/* fifo */

The astute reader will note that

	if (nfile.st_mode & S_IFREG)

will test whether the 0100000 bit is on in "st_mode".  The astute reader
will *also* note that this bit is on in the following values:

	S_IFLNK
	S_IFSOCK

so the test above will say "true" for symbolic links and "socket files".
They don't count as regular files in *my* book....

The astute reader will further node that

	else if (nfile.st_mode & S_IFDIR)

will test whether the 004000 bit is on in "st_mode", and that said bit
is on in the following values:

	S_IFBLK
	S_IFSOCK

and will, in addition, note that a block special file is *not* a directory.

Folks, the S_IF... values are *NOT* flag bits!  They are values for a
bit field, said bit field being defined by the S_IFMT value.  You must
*NOT* test whether a file is of type S_IFXXX by doing

	if (xxx.st_mode & S_IFXXX)

because you run the risk of getting false positives.  You must test
whether a file is of type S_IFXXX by doing

	if ((xxx.st_mode & S_IFMT) == S_IFXXX)



More information about the Comp.unix.questions mailing list