[comp.lang.c] What is wrong with this code ?

nrg@nsscb.UUCP (G.Narotham Reddy) (12/10/89)

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>

main(argc,argv)
int argc;
char *argv[];
{
struct stat nfile;
stat(argv[1], &nfile);
if (nfile.st_mode & S_IFMT == S_IFREG) 
printf("%s regular file\n", argv[1]);    
else if (nfile.st_mode & S_IFMT == S_IEXEC) 
printf("%s executable\n", argv[1]);    
else if (nfile.st_mode & S_IFMT == S_IWRITE) 
printf("%s writable\n", argv[1]);    
else if (nfile.st_mode & S_IFMT == S_IREAD) 
printf("%s readable\n", argv[1]);    
else if (nfile.st_mode & S_IFMT == S_IFDIR)
printf("%s dir\n", argv[1]);    
}


Thanks
-- 
_________________________________________________________________________
Narotham Reddy    reddy@attctc.Dallas.TX.US	 reddy@nucleus.mi.org
			       reddy@pooh.att.com
-------------------------------------------------------------------------

jxh@phobos.cis.ksu.edu (James Hu) (12/10/89)

In article <1156@nsscb.UUCP> nrg@nsscb.UUCP (G.Narotham Reddy) writes:
[...]

>stat(argv[1], &nfile);
>if (nfile.st_mode & S_IFMT == S_IFREG) 
>printf("%s regular file\n", argv[1]);    
 
[...]

The problem is in the order of precedence of the == and & operation.
Just add parentheses :

if ((nfile.st_mode & S_IFMT) == S_IFREG)
 ...

--
| James Hu             | jxh@phobos.cis.ksu.edu     | Kansas State University |
| 642 Haymaker Hall    | SIRIUS@KSUVM.BITNET        | Dept. of Computing and  |
| Manhattan, KS 66502  | ...!phobos.cis.ksu.edu!jxh | Information Sciences    |
`-----------------------------------------------------------------------------'

lint@mimsy.umd.edu (The Lint Program) (12/11/89)

In article <1156@nsscb.UUCP> nrg@nsscb.UUCP (G.Narotham Reddy) writes:
	main(argc,argv)
	int argc;
	char *argv[];
	{
	struct stat nfile;
	stat(argv[1], &nfile);
	if (nfile.st_mode & S_IFMT == S_IFREG) 
	printf("%s regular file\n", argv[1]);    
	else if (nfile.st_mode & S_IFMT == S_IEXEC) 
	printf("%s executable\n", argv[1]);    
	else if (nfile.st_mode & S_IFMT == S_IWRITE) 
	printf("%s writable\n", argv[1]);    
	else if (nfile.st_mode & S_IFMT == S_IREAD) 
	printf("%s readable\n", argv[1]);    
	else if (nfile.st_mode & S_IFMT == S_IFDIR)
	printf("%s dir\n", argv[1]);    
	}

t.c(11): warning: constant in conditional context
t.c(11): warning: null effect
t.c(13): warning: constant in conditional context
t.c(13): warning: null effect
t.c(15): warning: constant in conditional context
t.c(15): warning: null effect
t.c(17): warning: constant in conditional context
t.c(17): warning: null effect
t.c(19): warning: constant in conditional context
t.c(19): warning: null effect
t.c(6): warning: argument argc unused in function main
stat returns value which is always ignored
printf returns value which is always ignored

desj@idacrd.UUCP (David desJardins) (12/11/89)

From article <1156@nsscb.UUCP>, by nrg@nsscb.UUCP (G.Narotham Reddy):
> if (nfile.st_mode & S_IFMT == S_IFREG) 

   What is wrong with this code is that, in this as in so many other
examples, C has the world's stupidest precedence for its operators.

   -- David desJardins

darcy@druid.uucp (D'Arcy J.M. Cain) (12/11/89)

In article <1156@nsscb.UUCP> nrg@nsscb.UUCP (G.Narotham Reddy) writes:
>
>#include <stdio.h>
>#include <sys/types.h>
>#include <sys/stat.h>
>
>main(argc,argv)
>int argc;
>char *argv[];
>{
>struct stat nfile;
>stat(argv[1], &nfile);
>if (nfile.st_mode & S_IFMT == S_IFREG) 
>printf("%s regular file\n", argv[1]);    
>else if (nfile.st_mode & S_IFMT == S_IEXEC) 
>printf("%s executable\n", argv[1]);    
>else if (nfile.st_mode & S_IFMT == S_IWRITE) 
>printf("%s writable\n", argv[1]);    
>else if (nfile.st_mode & S_IFMT == S_IREAD) 
>printf("%s readable\n", argv[1]);    
>else if (nfile.st_mode & S_IFMT == S_IFDIR)
>printf("%s dir\n", argv[1]);    
>}
>

You forgot to put a smiley in this message (I hope).  In case this is
a serious question here is my $0.02

  1: There is no indentation.
  2: There isn't enough white space.
  3: It's inefficient.
  4: It's rather useless.

P.S: :-)

-- 
D'Arcy J.M. Cain (darcy@druid)     |   "You mean druid wasn't taken yet???"
D'Arcy Cain Consulting             |                    - Everybody -
West Hill, Ontario, Canada         |
No disclaimers.  I agree with me   |

dold@mitisft.Convergent.COM (Clarence Dold) (12/11/89)

in article <1156@nsscb.UUCP>, nrg@nsscb.UUCP (G.Narotham Reddy) says:

Oh, so judgemental!  Who says it's stupid precedence?
True, we do need a couple of parens to make it work, "it" being this 
one line, but don't we also need some logic in the program?

> if (nfile.st_mode & S_IFMT == S_IFREG) 
> else if (nfile.st_mode & S_IFMT == S_IEXEC) 

all these "else if" are self-defeating.  Might argv[1] not point to a file 
that satisfies more than one?  How will any of them ever display, if we
else if the permissions against S_IFREG to begin with?  (only for a special).
Additionally, we don't want to mask permissions against S_IFMT.
For that matter, we don't 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(...);

followed by several
if (nfile.st_mode & S_IWRITE) 
	printf(...);
if (nfile.st_mode & S_IREAD) 
	printf(...);
...
-- 
---
Clarence A Dold - dold@tsmiti.Convergent.COM            (408) 435-5293
               ...pyramid!ctnews!tsmiti!dold        FAX (408) 435-3105
               P.O.Box 6685, San Jose, CA 95150-6685         MS#10-007

chris@mimsy.umd.edu (Chris Torek) (12/12/89)

It has come to my attention that people are not reading their news
carefully.  (Big surprise, eh?)  In article <21198@mimsy.umd.edu>
lint@mimsy.umd.edu (The Lint Program) quoted someone else's faulty
C program, and included the lint output as a lesson in `use lint
before posting to USENET'.  Unfortunately, many of you are replying
to Dr. Lint via the good graces of the Wonder Dog, and to put it
simply, the Wonder Dog's good graces have run out.

Now, this is not something you would want to happen to *you*.  This
dog, for instance, thinks that -20 degree weather is `just right'.
He eats squirrels more or less whole.  He has *very* strong teeth.
*Big* teeth.  You might even call them `fangs'.

Dogs do not harbour grudges, so you can get those good graces back
by not replying any more.

This has been a private service annoucement.  (Well, it can hardly
be called `public service', now can it?)  Thank you.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@cs.umd.edu	Path:	uunet!mimsy!chris

jws@hpcljws.HP.COM (John Stafford) (12/14/89)

Clarence Dold writes...
 .
 .
 .
> Additionally, we don't want to mask permissions against S_IFMT.
> For that matter, we don't 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(...);
> 
> followed by several
> if (nfile.st_mode & S_IWRITE) 
> 	printf(...);
> if (nfile.st_mode & S_IREAD) 
> 	printf(...);

I've seen this mistake in two fairly professionally written pieces of
code, written by well meaning folks who simply aren't that familiar with
Unix.

The problem is that the various S_...  items have, in some cases, more
than one bit on.  Guess what happens if one of the S_...  items has a
bit on that is also in one of the other items?  For example on my
system...

#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_IFIFO	0010000	/* fifo */
#define		S_IFNWK 0110000 /* network special */
#define		S_IFLNK	0120000	/* symbolic link */
#define		S_IFSOCK 0140000/* socket */

Hence (nfile.st_mode & S_IFDIR) will be true for directories, block
special files, and sockets.  This is likely to lead to incorrect program
results.

Please mask with S_IFMT and compare for equality with the S_...  of your
choice, it doesn't hurt that much.  Thank you for your support.

dold@mitisft.Convergent.COM (Clarence Dold) (12/16/89)

in article <660067@hpcljws.HP.COM>, jws@hpcljws.HP.COM (John Stafford) says:

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

- The problem is that the various S_...  items have, in some cases, more
- than one bit on.  Guess what happens if one of the S_...  items has a
- bit on that is also in one of the other items?  For example on my
- system...
- 
- #define	S_IFMT	0170000		/* type of file */
- #define		S_IFLNK	0120000	/* symbolic link */
- #define		S_IFSOCK 0140000/* socket */

Notice when I said 'we' I used lower case, not the big We :-(

My SysV doesn't have any cases of needing S_IFMT, but then it doesn't
have symbolic links either.  I got e-mail chastising me, but no explanation.

- choice, it doesn't hurt that much.  Thank you for your support.
Thanks, and you're welcome to my support.
-- 
---
Clarence A Dold - dold@tsmiti.Convergent.COM            (408) 435-5293
               ...pyramid!ctnews!tsmiti!dold        FAX (408) 435-3105
               P.O.Box 6685, San Jose, CA 95150-6685         MS#10-007

guy@auspex.UUCP (Guy Harris) (12/17/89)

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