Personal tools
You are here: Home Projects C++ Cfront releases Release 3.0.3 source libSC Path ksh test.c
Document Actions

test.c

by Michael L Powell last modified 2007-01-26 03:24

Click here to get the file

Size 7.2 kB - File type text/plain

File contents

/*ident "@(#)Path:ksh/test.c	3.1" */
/*
 * Code for test
 * Stolen from ksh
 * Originally written by David Korn
 * Modified by me
 */

/* The values of the enums in ../Path.h
*  must match the values used in this file.
*/

#include "defs.h"

static MSG       e_devfdNN       = "/dev/fd/+([0-9])";

#define	tio(a,f,id)	(_sh_access_Path_ATTLC(a,f,id)==0)
static time_t ftime_compare();
static int test_stat();
static int test_inode();
static int test_type();
static int io_access();
static struct stat statb;

unop_test_Path_ATTLC(op,arg,id)
register int op;
register char *arg;
register int id;
{
	switch(op)
	{
	case 'a':
		return(tio(arg, F_OK, id));
	case 'r':
		return(tio(arg, R_OK, id));
	case 'w':
		return(tio(arg, W_OK, id));
	case 'x':
		return(tio(arg, X_OK, id));
	case 'd':
		return(test_type(arg,S_IFMT,S_IFDIR));
	case 'c':
		return(test_type(arg,S_IFMT,S_IFCHR));
	case 'b':
		return(test_type(arg,S_IFMT,S_IFBLK));
	case 'f':
		return(test_type(arg,S_IFMT,S_IFREG));
	case 'u':
		return(test_type(arg,S_ISUID,S_ISUID));
	case 'g':
		return(test_type(arg,S_ISGID,S_ISGID));
	case 'k':
#ifdef S_ISVTX
		return(test_type(arg,S_ISVTX,S_ISVTX));
#else
		return(0);
#endif /* S_ISVTX */

	case 'V':
#ifdef FS_3D
	{
		struct stat statb;
		if(lstat(arg,&statb)<0)
			return(0);
		return((statb.st_mode&(S_IFMT|S_ISVTX|S_ISUID))==(S_IFDIR|S_ISVTX|S_ISUID));
	}
#else
		return(0);
#endif /* FS_3D */

	case 'L':
#ifdef LSTAT
	{
		struct stat statb;
		if(lstat(arg,&statb)<0)
			return(0);
		return((statb.st_mode&S_IFMT)==S_IFLNK);
	}
#else
		return(0);
#endif	/* S_IFLNK */

	case 'S':
#ifdef S_IFSOCK
		return(test_type(arg,S_IFMT,S_IFSOCK));
#else
		return(0);
#endif	/* S_IFSOCK */

	case 'p':
#ifdef S_IFIFO
		return(test_type(arg,S_IFMT,S_IFIFO));
#else
		return(0);
#endif	/* S_IFIFO */

	case 's':
	case 'O':
	case 'G':
	{
		struct stat statb;
		if(test_stat(arg,&statb)<0)
			return(0);
		if(op=='s')
			return(statb.st_size>0);
		else if(op=='O')
			return(statb.st_uid==geteuid());
		return(statb.st_gid==getegid());
	}

	case 't':
		if(isdigit(*arg) && arg[1]==0)
			 return(isatty(*arg-'0'));
		return(0);
	}
}

binop_test_Path_ATTLC(op,left,right,id)
char *left, *right;
register int op;
register int id;
{
	switch(op)
	{
		/* op must be one of the following values */
		case 0:  /* ef */
			return(test_inode(left,right));
		case 1:  /* nt */
			return(ftime_compare(left,right)>0);
		case 2:  /* ot */
			return(ftime_compare(left,right)<0);
	}
	/* NOTREACHED */
}

/*
 * returns the modification time of f1 - modification time of f2
 */

static time_t ftime_compare(file1,file2)
char *file1,*file2;
{
	struct stat statb1,statb2;
	if(test_stat(file1,&statb1)<0)
		statb1.st_mtime = 0;
	if(test_stat(file2,&statb2)<0)
		statb2.st_mtime = 0;
	return(statb1.st_mtime-statb2.st_mtime);
}

/*
 * return true if inode of two files are the same
 */

static test_inode(file1,file2)
char *file1,*file2;
{
	struct stat stat1,stat2;
	if(test_stat(file1,&stat1)>=0  && test_stat(file2,&stat2)>=0)
		if(stat1.st_dev == stat2.st_dev && stat1.st_ino == stat2.st_ino)
			return(1);
	return(0);
}

/*
/* These are the mode values supplied as argument to access():
/*     #define R_OK    4/* test for read permission */
/*     #define W_OK    2/* test for write permission */
/*     #define X_OK    1/* test for execute (search) permission */
/*     #define F_OK    0/* test for presence of file */
/*
/* And the status information word st_mode (in the info returned by stat()) 
/* has the following bits:
/*     #define    S_IFMT        0170000/* type of file */
/*     #define    S_IFIFO       0010000/* fifo special */
/*     #define    S_IFCHR       0020000/* character special */
/*     #define    S_IFDIR       0040000/* directory */
/*     #define    S_IFBLK       0060000/* block special */
/*     #define    S_IFREG       0100000/* regular file */
/*     #define    S_IFLNK       0120000/* symbolic link */
/*     #define    S_IFSOCK      0140000/* socket */
/*     #define    S_ISUID       0004000/* set user id on execution */
/*     #define    S_ISGID       0002000/* set group id on execution */
/*     #define    S_ISVTX       0001000/* save swapped text even after use */
/*     #define    S_IREAD       0000400/* read permission, owner */
/*     #define    S_IWRITE      0000200/* write permission, owner */
/*     #define    S_IEXEC       0000100/* execute/search permission, owner */
/*
/*     The mode bits 0000070 and 0000007 encode  group  and  others
/*     permissions (see chmod(2)).
*/

/*
 * This version of access checks against the desired uid/gid.
 * This version is guaranteed to match access(2) only in those
 * cases when we're checking against real id other than root.
 * The static buffer statb is shared with test_type.
 */

/* The setting of <realid> shouldn't make a difference in case 
 * <mode> = F_OK, unless access(2) is written screwy.  When <mode>
 * = F_OK, _sh_access should return 1 just if the file can be
 * statted.
 */

int _sh_access_Path_ATTLC(name, mode, realid)
register char	*name;
register int mode;
register int realid;
{
	int uid, gid;
	if (realid)
	{
		uid = getuid();
		gid = getgid();
	}
	else
	{
		uid = geteuid();
		gid = getegid();
	}
	if(strmatch_Path_ATTLC(name,(char*)e_devfdNN))
		return(io_access(atoi(name+8),mode));
	if(uid != 0 && realid)
		return(access(name,mode));
	if(stat(name, &statb) == 0)
	{
		if(mode == F_OK)
			return(0);
		else if(uid == 0)
		{
			if((statb.st_mode&S_IFMT)!=S_IFREG || mode!=X_OK)
				return(0);
		    	/* root needs execute permission for someone */
			mode = (S_IEXEC|(S_IEXEC>>3)|(S_IEXEC>>6));
		}
		else if(uid == statb.st_uid)
			mode <<= 6;
		else if(gid == statb.st_gid)
			mode <<= 3;
#if defined(NGROUPS) && NGROUPS>0
		else
		{
			/* in both the real and effective cases, permission is
			   checked against the groups in the group access list.
			   (if you don't believe me, read the intro(2) and access(2)
			   man pages.)
			*/
			int groups[NGROUPS];
			register int n;
			n = getgroups(NGROUPS,groups);
			while(--n >= 0)
			{
				if(groups[n] == statb.st_gid)
				{
					mode <<= 3;
					break;
				}
			}
		}
#endif /* NGROUPS */
		if(statb.st_mode & mode)
			return(0);
	}
	return(-1);
}


/*
 * Return true if the mode bits of file <f> corresponding to <mask> have
 * the value equal to <field>.  If <f> is null, then the previous stat
 * buffer is used.
 */

static test_type(f,mask,field)
char *f;
int field;
{
	if(f && test_stat(f,&statb)<0)
		return(0);
	return((statb.st_mode&mask)==field);
}

/*
 * do an fstat() for /dev/fd/n, otherwise stat()
 */

static int test_stat(f,buff)
char *f;
struct stat *buff;
{
	if(strmatch_Path_ATTLC(f,(char*)e_devfdNN))
		return(fstat(atoi(f+8),buff));
	else
		return(stat(f,buff));
}


/*
 * returns access information on open file <fd>
 * returns -1 for failure, 0 for success
 * <mode> is the same as for access()
 */

static io_access(fd,mode)
register int mode;
{
	register int flags;
	register struct fileblk *fp;
#ifndef F_GETFL
	struct stat statb;
#endif /* F_GETFL */
	if(mode==X_OK)
		return(-1);
#ifdef F_GETFL
	flags = fcntl(fd,F_GETFL,0);
#else
	flags = fstat(fd,&statb);
#endif /* F_GETFL */
	if(flags < 0)
		return(-1);
#ifdef F_GETFL
	if(mode==R_OK && (flags&1))
		return(-1);
	if(mode==W_OK && !(flags&3))
		return(-1);
#endif /* F_GETFL */
	return(0);
}
« April 2024 »
Su Mo Tu We Th Fr Sa
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
 

Powered by Plone CMS, the Open Source Content Management System

This site conforms to the following standards: