Alternative to access() (was: Bug in tempnam(3) function)
Kim F. Storm
storm at texas.dk
Wed Jun 13 02:58:22 AEST 1990
In article <2077 at polari.UUCP> 6sigma2 at polari.UUCP (Brian Matthews) writes:
>In article <433 at mtndew.UUCP> friedl at mtndew.UUCP (Stephen J. Friedl) writes:
>|Email will get a pretty detailed note on why
>|access(2) is evil.
del at thrush.mlb.semi.harris.com (Don Lewis) writes:
> Would using stat(2), and checking if the uids/gids match and looking
> at the permission bits have been better? Should the effective or
> real ids have be used?
Here is the "file_exist()" function which I wrote to make all sorts
of file checking easy. It is extracted from the nn distribution, so
it may need a little hacking to be used out of context:
/*
* (c) Copyright 1990, Kim Fabricius Storm. All rights reserved.
*/
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifdef HAVE_MULTIGROUP
#ifndef NGROUPS
#include <sys/param.h>
#endif
#ifndef GIDSET_TYPE
#define GIDSET_TYPE int
#endif
static int ngroups;
static GIDSET_TYPE gidset[NGROUPS];
static in_grplist(gid)
GIDSET_TYPE gid;
{
int n;
for (n = 0; n < ngroups; ++n)
if (gidset[n] == gid) return 1;
return 0;
}
#define group_access(gpid) in_grplist((GIDSET_TYPE)(gpid))
#else
#define group_access(gid) ((gid) == group_id)
#endif
/*
* Test existence and access modes of a file or directory
*
* mode is a string composed of the following characters
* f -- name is a file
* d -- name is a directory
* r -- name is readable
* w -- name is writeable
* x -- name is executeable/searchable
*
* 0 is returned if file does not exist or any of the requested
* permissions are not present; the actual cause is returned in
* errno (EACCESS, EISDIR, ENOTDIR).
* Otherwise, the modification time of the file is returned.
*
* Examples:
* file_exist("/usr", "dwr")
* -- is /usr a directory, writeable AND readable?
*
* file_exist(file, "fx")
* -- is file an executeable file?
*
* file_exist(file, (char *)NULL)
* -- does file exist?
*/
time_t file_exist(name, mode)
char *name;
char *mode;
{
static unsigned short user_id, group_id;
static init = 1;
struct stat statb;
extern int errno;
if (init) {
user_id = geteuid();
#ifdef HAVE_MULTIGROUP
ngroups = getgroups(NGROUPS, gidset); /* Get users's group set */
group_id = gidset[0]; /* not used, but just in case... */
#else
group_id = getegid();
#endif
init = 0;
}
if (stat(name, &statb)) return 0;
if (mode == NULL) return statb.st_mtime;
while (*mode) {
switch (*mode++) {
case 'd':
if ((statb.st_mode & S_IFMT) == S_IFDIR) continue;
errno = ENOTDIR;
return 0;
case 'f':
if ((statb.st_mode & S_IFMT) == S_IFREG) continue;
if ((statb.st_mode & S_IFMT) == 0000000) continue;
if ((statb.st_mode & S_IFMT) == S_IFDIR) {
errno = EISDIR;
return 0;
}
break;
case 'r':
if ((statb.st_mode & 0400) && statb.st_uid == user_id) continue;
if ((statb.st_mode & 0040) && group_access(statb.st_gid)) continue;
if ((statb.st_mode & 0004)) continue;
break;
case 'w':
if ((statb.st_mode & 0200) && statb.st_uid == user_id) continue;
if ((statb.st_mode & 0020) && group_access(statb.st_gid)) continue;
if ((statb.st_mode & 0002)) continue;
break;
case 'x':
if ((statb.st_mode & 0100) && statb.st_uid == user_id) continue;
if ((statb.st_mode & 0010) && group_access(statb.st_gid)) continue;
if ((statb.st_mode & 0001)) continue;
break;
}
errno = EACCES;
return 0;
}
/* all modes are ok */
return statb.st_mtime;
}
--
Kim F. Storm <storm at texas.dk> No news is good news,
Texas Instruments A/S, Denmark but nn is better!
More information about the Comp.bugs.sys5
mailing list