Google
 

Trailing-Edge - PDP-10 Archives - SRI_NIC_PERM_FS_1_19910112 - c/lib/usys/stat.c
There are 9 other files named stat.c in the archive. Click here to see a list.
/*
**	STAT - stat, fstat, xstat, xfstat
**
**	(c) Copyright Ken Harrenstien 1989
**		for all changes after v.146, 20-Sep-1988
**	(c) Copyright Ken Harrenstien, SRI International 1988
**		for all changes after v.37, 28-Mar-1986
**	Edits for ITS:  Copyright (C) 1988 Alan Bawden
**
** Original version by Greg Satz / Stanford University / 12-Sep-84
*/

#include <c-env.h>
#if SYS_T20+SYS_10X+SYS_T10+SYS_CSI+SYS_WTS

#include <errno.h>
#include <stddef.h>		/* for NULL */
#include <string.h>		/* memset() */
#include <sys/types.h>
#include <sys/file.h>
#include <sys/usysio.h>
#include <sys/usysig.h>
#include <sys/stat.h>

#if SYS_T20+SYS_10X
#include <jsys.h>
#include <sys/time.h>	/* For tadl_to_utime() to convert file times */

/* Exported implementation-internal functions */
extern void _rljfn();
extern int _gtjfn(), _get_pio(), _gtfdb(), _rcusr();
extern long _nfbsz();	/* For LSEEK */

static int dostat(), t2u_pro();

#elif SYS_ITS
#include <sysits.h>

#elif SYS_T10+SYS_CSI+SYS_WTS
#include <muuo.h>
#include <macsym.h>
#include <sys/time.h>	/* For tadl_to_utime() to convert file times */

extern int _flookup(), _fparse();	/* From open() */
static int dostat();

#endif

/* Exported functions */
extern int stat(), fstat(), xstat(), xfstat();
extern int _dvtype();

static int _stat(), _fstat();
/*
 *	stat(name, buf)
 */

int
stat(name, buf)
char *name;
struct stat *buf;
{
    return _stat(name, buf, 0);	/* Normal stat buffer */
}

int
xstat(name, buf)
char *name;
struct xstat *buf;
{
    return _stat(name, buf, 1);	/* Extended stat buffer */
}

static int
_stat(name, buf, extf)
char *name;
struct stat *buf;
int extf;
{
    int i;

    USYS_BEG();
#if SYS_T20+SYS_10X
    {	int jfn;

	if ((jfn = _gtjfn(name, O_RDONLY)) == 0)
	    USYS_RETERR(ENOENT);
	i = dostat(buf, (struct _ufile *)NULL, jfn, extf);	/* No UF */
	_rljfn(jfn);
	if (i) USYS_RETERR(i);
	USYS_RET(0);
    }
#elif SYS_ITS
    {	int fd;

	if ((fd = open(name, O_RDONLY, 0)) < 0)
	    USYS_RETERR(ENOENT);
	/* Most device-independent way to avoid setting reference date: */
	SYSCALL1("resrdt", _uffd[fd]->uf_ch);
	i = fstat(fd, buf);
	close(fd);
	USYS_RET(i);
    }
#elif SYS_T10+SYS_CSI+SYS_WTS
    {	struct _filespec fs;
	if ((i = _fparse(&fs, name))
	  || (i = dostat(buf, (struct _ufile *)NULL, &fs, extf)))
	    USYS_RETERR(i);	/* Parsing or dostat error */
	USYS_RET(0);
    }
#else
    USYS_RETERR(EINVAL);	/* Not implemented yet */
#endif
}


int
fstat(fd, buf)
int fd;
struct stat *buf;
{
    return _fstat(fd, buf, 0);	/* Normal stat buffer */
}

int
xfstat(fd, buf)
int fd;
struct xstat *buf;
{
    return _fstat(fd, buf, 1);	/* Extended stat buffer */
}

static int
_fstat(fd, buf, extf)
int fd, extf;
struct stat *buf;
{
    struct _ufile *uf;
    int ret;

    USYS_BEG();
    if (!(uf = _UFGET(fd)))
	USYS_RETERR(EBADF);
#if SYS_T20+SYS_10X
    if (ret = dostat(buf, uf, uf->uf_ch, extf))
	USYS_RETERR(ret);
    USYS_RET(0);
#elif SYS_ITS
    USYS_RETERR(EINVAL);	/* Not really implemented on ITS yet. */
#elif SYS_T10+SYS_CSI+SYS_WTS
    if (ret = dostat(buf, uf, &uf->uf_fs, extf))
	USYS_RETERR(ret);
    USYS_RET(0);
#else
    USYS_RETERR(EINVAL);	/* Not implemented yet. */
#endif
}
/* _DVTYPE(osfd) - Get device type
*/
int
_dvtype(osfd)
int osfd;
{
#if SYS_T20+SYS_10X
    int ablock[5];

    ablock[1] = osfd;		/* JFN */
    return jsys(DVCHR, ablock) > 0 ? FLDGET(ablock[2], monsym("DV%TYP")) : -1;

#elif SYS_ITS
    unsigned status;

    SYSCALL2_LOSE("status", osfd, SC_VAL(&status)); /* can't fail */
    switch (status & 077) {
	case 000:
	case 001:
	case 002:
	    return UIO_DVTTY;
	case 060:
	case 061:
	    return UIO_DVUSR;
	default:
	    return UIO_DVDSK;
    }
#elif SYS_T10+SYS_CSI+SYS_WTS
    int ret;

    if (osfd == UIO_CH_CTTRM)		/* Special case */
	return UIO_DVTTY;
    MUUO_ACVAL("DEVCHR", osfd, &ret);
    if (ret) {
	if (ret & uuosym("DV.DSK")) return UIO_DVDSK;
	if (ret & uuosym("DV.TTY")) return UIO_DVTTY;
    }
    return -1;

#if 0	/* Old code for TOPS-10; doesn't work on CSI or WAITS, so flushed */
    int ret;

    if (osfd == UIO_CH_CTTRM)		/* Special case */
	return UIO_DVTTY;
    if (MUUO_ACVAL("DEVTYP", osfd, &ret) > 0 && ret)
	return FLDGET(ret, uuosym("TY.DEV"));
    return -1;
#endif

#else
    return -1;
#endif
}
#if SYS_T20+SYS_10X

/*
 *	dostat(buf, uf, jfn, extf) - worker routine for stat() and fstat()
 *		returns 0 if succeeded, else error #
 */

static int
dostat(buf, uf, jfn, extf)
struct stat *buf;
struct _ufile *uf;
int jfn, extf;
{
    register struct xstat *xst;
    register int i, bytsiz;
    int fdb[monsym(".FBLEN")];
    char name[50];	/* To hold username (max 40 but be generous) */
    unsigned prot;
    int acs[5];

    if (extf) xst = (struct xstat *)buf;	/* If extended, use ptr */

    if (jfn == _PRIIN) _get_pio(&jfn, 0);	/* Check for redirection */
    else if (jfn == _PRIOU) _get_pio(0, &jfn);

    acs[1] = jfn;
    acs[2] = XWD(monsym(".FBLEN"),0);		/* get the whole FDB */
    acs[3] = (int) fdb;
    if (!jsys(GTFDB, acs)) {
	/* If GTFDB failed, assume dealing with non-disk device. */
	/* Clear entire structure since we won't be setting much of it. */
	if (extf) memset((char *)xst, 0, sizeof(struct xstat));
	else memset((char *)buf, 0, sizeof(struct stat));

	buf->st_mode = S_IFCHR;		/* Pretend "char special" device */
	acs[1] = jfn;
	if (!jsys(DVCHR, acs))		/* Get device info */
	    return ENODEV;		/* Shouldn't fail, actually */
	buf->st_dev = acs[1];		/* Device designator */
	buf->st_rdev = acs[2];		/* Dev characteristics (incl .DVxxx)*/
	if (extf && FLDGET(buf->st_rdev, monsym("DV%TYP")) == _DVTCP) {
	    buf->st_mode = S_IFSOCK;		/* Say "socket" */
	    acs[1] = jfn;
	    if (jsys(GDSTS, acs) > 0) {		/* Fails if not open */
		xst->xst_state = acs[2];	/* Connection state */
		xst->xst_fhost = acs[3];	/* Foreign host netaddr */
		xst->xst_fport = acs[4];	/* Foreign port # */
	    }
	}
	return 0;
    }

    /* If GTFDB succeeded, we're dealing with a disk file. */
    buf->st_nlink = 1;			/* can it be anything else? */
    buf->st_gid = 0;			/* for now */

    acs[1] = jfn;
    if (!jsys(DVCHR, acs))		/* Get device info */
	return ENODEV;			/* Shouldn't fail */
    buf->st_dev = acs[1];		/* Device designator */
    buf->st_rdev = acs[2];		/* Dev characteristics (incl .DVxxx)*/

    buf->st_ino = fdb[monsym(".FBADR")];	/* Disk address */
    buf->st_mode = ((fdb[monsym(".FBCTL")] & FB_DIR) ? S_IFDIR : S_IFREG);
    prot = fdb[monsym(".FBPRT")];		/* Protection */
    buf->st_mode |= (t2u_pro(FLDGET(prot, 0770000)) << 6)	/* Owner */
		  | (t2u_pro(FLDGET(prot,   07700)) << 3)	/* Group */
		  | (t2u_pro(FLDGET(prot,     077)) << 0);	/* World */
#if SYS_10X
    buf->st_uid = FLDGET(fdb[monsym(".FBUSE")], LH);	/* Get directory # */
#elif SYS_T20
    acs[1] = XWD(monsym(".GFLWR"), jfn);	/* <funct>,,<jfn> */
    acs[2] = (int) (name-1);
    jsys(GFUST, acs);				/* Ignore failure */
    buf->st_uid = _rcusr(name);			/* Convert name to user # */
#endif
    buf->st_atime = tadl_to_utime(fdb[monsym(".FBREF")]);
    buf->st_mtime = tadl_to_utime(fdb[monsym(".FBWRT")]);
    buf->st_ctime = tadl_to_utime(fdb[monsym(".FBCRE")]);

    /* Set size vars. */
    /* TOPS-20 has several stupid screws with respect to newly created files,
    ** or files being updated.  Newly created files don't actually exist until
    ** they have been CLOSF%'d, so the FDB size information is all 0.  open()
    ** attempts to circumvent this by doing a quick CLOSF/OPENF; however, then
    ** the update problem comes up, because TOPS-20 doesn't update the FDB
    ** size info until a CLOSF% is done after writing!!  If we are writing the
    ** file ourselves, we look at our own info to see what's up.
    */
    buf->st_size = fdb[monsym(".FBSIZ")];	/* First try what FDB has */
    bytsiz = FLDGET(fdb[monsym(".FBBYV")], monsym("FB%BSZ"));	/* Get FDB bytesize */
    if (bytsiz == 0 || bytsiz == 36) {	/* Monitor assumes 0 means 36 */
	bytsiz = 9;			/* KCC reads words as 4 9-bit bytes */
	buf->st_size *= 4;
    }
    buf->st_blksize = (36/bytsiz)*512;	/* # bytes in page */
    buf->st_blocks =			/* # pages (blocks) in file */
		FLDGET(fdb[monsym(".FBBYV")], monsym("FB%PGC"));

    if (uf) {				/* Have it open ourselves? */
	if (bytsiz != uf->uf_bsize) {	/* Yes, check bytesize info */
	    /* Update length and # bytes in page */
	    buf->st_size = _nfbsz(uf->uf_bsize, bytsiz, buf->st_size);
	    buf->st_blksize = (36/uf->uf_bsize) * 512;
	}
	if (buf->st_size < uf->uf_pos)	/* If our len info is better */
	    buf->st_size = uf->uf_pos;	/* update it! */

	i = (buf->st_size + buf->st_blksize-1) / buf->st_blksize;
	if (buf->st_blocks < i)			/* If our page info better */
	    buf->st_blocks = i;			/* # pages (blocks) in file */
    }

    if (extf) {			/* Set extended vars if desired */
	xst->xst_version = FLDGET(fdb[monsym(".FBGEN")], LH);
	xst->xst_bytsiz = FLDGET(fdb[monsym(".FBBYV")], monsym("FB%BSZ"));
	xst->xst_pagcnt = buf->st_blocks;
    }

    return 0;				/* success */
}
#endif /* T20+10X */
#if SYS_T20+SYS_10X
/*
 *	get primary JFNs for ourself
 */

int
_get_pio(i, o)
int *i, *o;
{
    int ac[5];

    ac[1] = monsym(".FHSLF");		/* "Self" process handle */
    if (jsys(GPJFN, ac)) {
	if (i) *i = FLDGET(ac[2], LH);
	if (o) *o = FLDGET(ac[2], RH);
	return 1;
    } else return 0;
}

/*
 *	_GTFDB() - read (and return) a word from a file's fdb
 *	this routine is exported, don't make it static!
 */

int
_gtfdb(jfn, word)
int jfn, word;
{
    int arg_block[5];

    arg_block[1] = jfn;
    arg_block[2] = XWD(1,word);
    arg_block[3] = 3;				/* put the value in AC3 */
    return (jsys(GTFDB, arg_block)) ? arg_block[3] : 0;
}


/*
 *	Return username number for given user name
 */

int
_rcusr(name)
char *name;
{
    int ablock[5];

    ablock[1] = monsym("RC%EMO");
    ablock[2] = (int) (name - 1);
    if (!jsys(RCUSR, ablock) || (ablock[1] & monsym("RC%NOM")))
	return -1;
    return ablock[3];
}

/* _NFBSZ - convert file length in one bytesize to length in another bytesize.
**	Note we multiply by new bytesize before dividing by old; this prevents
**	integer division from forcing alignment to a word boundary.
*/
long
_nfbsz(ourbsz, filbsz, fillen)
int ourbsz, filbsz;
long fillen;
{
    register int ourbpw = ourbsz ? (36/ourbsz) : 1;	/* # bytes per wd */
    register int filbpw = filbsz ? (36/filbsz) : 1;
    return (ourbpw * fillen + filbpw-1) / filbpw;
}
/*
 *	Takes TOPS-20 protections right justified and returns Unix protections
 *	right justified.
 */
static int t2u_pro(prot)
unsigned prot;
{
    int i = 0;

    if (prot & monsym("FP%RD"))	i |= S_IREAD  >> 6;
    if (prot & monsym("FP%WR"))	i |= S_IWRITE >> 6;
    if (prot & monsym("FP%EX"))	i |= S_IEXEC  >> 6;
    return i;
}

#endif /* T20+10X */
#if SYS_T10+SYS_CSI+SYS_WTS

/* DOSTAT(buf, uf, fs, extf) - Fill out stat structure using parsed filespec.
**	Returns 0 if success, else errno value.
**	Note that fstat gives us a non-NULL uf pointer, but that doesn't
**	help us much since T10 has no good way to provide channel info.
*/
static unsigned t10prot();

static int
dostat(s, uf, fs, extf)
struct stat *s;
struct _ufile *uf;
struct _filespec *fs;
int extf;			/* Flag ignored */
{
    int nbpw;
    int err = 0;
    int typinf = 0, ret;
    int isdirdev;
    struct _filehack f;

    f.fs = *fs;			/* Copy filespec into big hack struct */

    /* Parsed filespec is in fs; check out device first. */
    if (!f.fs.fs_dev)			/* Device specified? */
	f.fs.fs_dev = _SIXWRD("DSK");	/* No, supply default */
    MUUO_ACVAL("DEVCHR", f.fs.fs_dev, &typinf);
    isdirdev = typinf & uuosym("DV.DIR");	/* See if directory device */

    if (!typinf)			/* Returns 0 if failed altogether */
	return ENODEV;

    if (!isdirdev) {			/* Handle non-directory devs */
#if SYS_T10+SYS_CSI
	if (MUUO_ACVAL("DEVNAM", f.fs.fs_dev, &ret) <= 0)
	    return ENODEV;		/* Barf??? */
#elif SYS_WTS
	if (WTSUUO_ACVAL("PNAME", f.fs.fs_dev, &ret) <= 0)
	    return ENODEV;		/* Barf??? */
#endif
	memset((char *)s, 0, sizeof(struct stat));	/* Clear struct */
	s->st_dev = ret;		/* Set SIXBIT phys device name */
	s->st_rdev = typinf;		/* Set device type (or charact) */
	s->st_mode =  S_IFCHR;		/* Say "char special" device */
	return 0;
    }

    /* Directory device, normally disk.  Do an OPEN and LOOKUP on file. */
#if SYS_T10+SYS_CSI
    if (err = _flookup((char *)NULL, &f, LER_RBTIM))	/* Use extended blk */
	return err;
    s->st_dev = f.xrb.s.rb_dev;
    s->st_ino = f.xrb.s.rb_pos;			/* Position on disk (??) */
    s->st_mode = ((f.xrb.s.rb_sts & uuosym("RP.DIR"))	/* Directory file? */
			? S_IFDIR : S_IFREG)
		 | t10prot(f.xrb.s.rb_prv.rb.prv);
    s->st_uid = f.xrb.s.rb_aut;			/* File author */
    s->st_size = f.xrb.s.rb_siz;		/* Get size in words */
    s->st_ctime = tadl_to_utime(f.xrb.s.rb_tim);
    /* Put together absurd T10 creation date/time format */
    s->st_mtime = tad64s_to_utime(XWD(		/* Convert stupid fmt */
	(f.xrb.s.rb_ext.rb.crx << 12) | f.xrb.s.rb_prv.rb.crd,	/* LH date */
	f.xrb.s.rb_prv.rb.crt * 60)		/* RH time in sec */
				 );
    if (s->st_ctime < s->st_mtime)	/* Ensure change date no earlier */
	s->st_ctime = s->st_mtime;	/* than last data-modify date */
    s->st_atime = tad64s_to_utime(XWD(f.xrb.s.rb_ext.rb.acd,0)); /* "ref" date */

#elif SYS_WTS
    if (err = _flookup((char *)NULL, &f, 0))	/* Use old short blk */
	return err;
    WTSUUO_ACVAL("PNAME", f.fs.fs_dev, &s->st_dev);
    s->st_ino = f.orb.arr[0] + f.orb.arr[1]	/* Make up a number */ 
	    + f.orb.arr[2] + f.orb.arr[3];	/* likely to be unique */
    s->st_mode = S_IFREG | t10prot(f.orb.s.rb_prv.rb.prv);
    s->st_uid = f.lerppn;			/* File owner - same as dir */

    s->st_size = ((unsigned) -f.orb.s.rb_ppn) >> 18;	/* Size in wds */

    /* Put together "last-written" time from absurd T10 format */
    s->st_mtime = tad64s_to_utime(XWD(		/* Convert stupid fmt */
	(f.orb.s.rb_ext.rb.crx << 12) | f.orb.s.rb_prv.rb.crd,	/* LH date */
	f.orb.s.rb_prv.rb.crt * 60)		/* RH time in sec */
				 );
    s->st_ctime = s->st_mtime;
    s->st_atime = tad64s_to_utime(XWD(f.orb.s.rb_ext.rb.acd,0)); /* "ref" date */
#endif

    /* Common T10-type code here */
    s->st_rdev = typinf;		/* Either DEVCHR or DEVTYP info */
    s->st_nlink = 1;			/* can it be anything else? */
    s->st_gid = ((unsigned)s->st_uid)>>18;
    if (s->st_atime < s->st_ctime)	/* Ensure access time always */
	s->st_atime = s->st_ctime;	/* has most recent date */

    /* Convert st_size for bytesize here ! */
    nbpw = sizeof(int);		/* Default # bytes per word */
    if (uf) {			/* If doing fstat, then know bytesize! */
	if (uf->uf_nbpw)
	    nbpw = uf->uf_nbpw;
	/* Worth trying to update length with CSI's GTEFS$ call?  Probably
	** not, would confuse block I/O which has to track EOF.
	*/
    }
    s->st_blocks = (s->st_size + UIO_T10_DSKWDS-1) / UIO_T10_DSKWDS;
    s->st_blksize = UIO_T10_DSKWDS * nbpw;	/* Size of a disk block */
    if (uf) s->st_size = uf->uf_flen;		/* If fstat, believe our EOF */
    else s->st_size *= nbpw;			/* Return # bytes */

    return 0;
}
/* T10PROT(prot) - convert a TOPS-10 disk protection code into UNIX format.
*/
#define UP_R 04		/* UNIX Read access */
#define UP_W 02		/* UNIX Write access */
#define UP_X 01		/* UNIX Execute/search access */

static unsigned
t10prot(prot)
unsigned prot;
{
	/* Protection-change, reName, Read, Write, eXecute, Update, Append */
    static unsigned map[8] = {
#if SYS_T10+SYS_CSI
	UP_R|UP_W|UP_X,		/* 0 .PTCPR  PNRWXUA	Full access */
	UP_R|UP_W|UP_X,		/* 1 .PTREN  -NRWXUA	*/
	UP_R|UP_W|UP_X,		/* 2 .PTWRI  --RWXUA	*/
	UP_R|UP_W|UP_X,		/* 3 .PTIPD  --R-XUA	*/
	UP_R|     UP_X,		/* 4 .PTAPP  --R-X-A	*/
	UP_R|     UP_X,		/* 5 .PTRED  --R-X--	Read-only (and xct) */
	          UP_X,		/* 6 .PTEXO  ----X--	Execute-only  */
	0,			/* 7 .PTNON  No access */
#elif SYS_WTS
	UP_R|UP_W|UP_X,		/* 0  PRW No protection */
	UP_R|     UP_X,		/* 1  PR- Write protect */
	     UP_W|UP_X,		/* 2  P-W Read protect */
	          UP_X,		/* 3  P-- R/W protect */
	UP_R|UP_W,		/* 4  -RW Protection protect */
	UP_R,			/* 5  -R-	*/
	     UP_W,		/* 6  --W	*/
	0,			/* 7  --- Full protection */
#endif
    };
    return map[prot&07]		/* Other (WAITS: not-logged-in) */
     | (map[(prot>>3)&07]<< 3)	/* Group (T10: project)(WAITS: logged-in) */
#if SYS_T10+SYS_CSI
     | (map[(prot>>6)&07]<< 6);	/* Owner */
#elif SYS_WTS
     | (map[(prot&0100) ? 1 : 0]<< 6);	/* Owner (only has 1 bit) */
#endif

}
#endif /* SYS_T10+SYS_CSI+SYS_WTS */

#endif /* T20+10X+T10+CSI+WAITS */