Trailing-Edge
-
PDP-10 Archives
-
SRI_NIC_PERM_FS_1_19910112
-
c/lib5/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
**
** Initial version by Greg Satz / Stanford University / 12-Sep-84
** All changes after version 41 are
** Copyright (c) 1988 by Ken Harrenstien, SRI International
** Edits for ITS: Copyright (C) 1988 Alan Bawden
*/
#include "c-env.h"
#include "errno.h"
#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 _stat(), _fstat(), dostat();
static int t2u_pro(), _gdsts();
#elif SYS_ITS
#include "sysits.h"
#endif
/* Exported functions */
extern int stat(), xstat(), _dvtype();
/*
* 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;
{
#if SYS_T20+SYS_10X
int jfn, i;
USYS_BEG();
if ((jfn = _gtjfn(name, O_RDONLY)) == 0)
USYS_RETERR(ENOENT);
i = dostat(jfn, buf, 0, extf); /* No UFX */
_rljfn(jfn);
USYS_RET(i);
#elif SYS_ITS
int fd, i;
USYS_BEG();
if ((fd = open(name, O_RDONLY, 0)) < 0)
USYS_RETERR(ENOENT);
/* Most device-independent way to avoid setting reference date: */
SYSCALL1("resrdt", _uioch[_uioufx[fd]]);
i = fstat(fd,buf);
close(fd);
USYS_RET(i);
#else
#error stat() not supported for this system.
#endif /* Not T20+10X+ITS */
}
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;
{
int ufx;
USYS_BEG();
if (fd < 0 || fd >= OPEN_MAX || !(ufx = _uioufx[fd]))
USYS_RETERR(EBADF);
#if SYS_T20+SYS_10X
USYS_RETVOLATILE(dostat(_uioch[ufx], buf, ufx, extf));
#elif SYS_ITS
return -1; /* Not really implemented on ITS yet. */
#else
#error fstat() not supported for this system.
#endif /* not T20+10X+ITS */
}
#if SYS_T20+SYS_10X
/*
* dostat(jfn, buf, ufx, extf) - worker routine for stat() and fstat()
*/
static int
dostat(jfn, buf, ufx, extf)
int jfn, ufx, extf;
struct stat *buf;
{
register struct xstat *xst;
register int i, bytsiz;
int fdb[monsym(".FBLEN")];
char name[FILEPART_SIZE];
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 */
buf->st_rdev = buf->st_dev = _dvtype(jfn); /* Set device type */
if (extf && buf->st_rdev == ST_DEV_TCP) {
buf->st_mode = S_IFSOCK; /* Say "socket" */
_gdsts(jfn, &xst->xst_state, &xst->xst_fhost, &xst->xst_fport);
}
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 */
buf->st_rdev = buf->st_dev = _dvtype(jfn); /* Set device type */
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, T20_OWNER_MASK)) >> UNIX_OWNER_OFFSET;
buf->st_mode |= t2u_pro(FLDGET(prot, T20_GROUP_MASK)) >> UNIX_GROUP_OFFSET;
buf->st_mode |= t2u_pro(FLDGET(prot, T20_WORLD_MASK)) >> UNIX_WORLD_OFFSET;
#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 (ufx) { /* Have it open ourselves? */
if (bytsiz != _uiobsize[ufx]) { /* Yes, check bytesize info */
/* Update length and # bytes in page */
buf->st_size = _nfbsz(_uiobsize[ufx], bytsiz, buf->st_size);
buf->st_blksize = (36/_uiobsize[ufx]) * 512;
}
if (buf->st_size < _uiopos[ufx]) /* If our len info is better */
buf->st_size = _uiopos[ufx]; /* 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 */
/*
* 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 _DVTTY;
case 060:
case 061:
return _DVUSR;
default:
return _DVDSK;
}
#endif
}
#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 & FP_READ) i |= S_IREAD;
if (prot & FP_WRITE) i |= S_IWRITE;
if (prot & FP_EXECUTE) i |= S_IEXEC;
return i;
}
/*
* _gdsts(jfn, a, b, c) - get device status stuff.
* int jfn, *a, *b, *c;
*
* Stores the ACs returned by GDSTS%
*/
static int _gdsts(jfn, a, b, c)
int jfn, *a, *b, *c;
{
int ablock[5];
ablock[1] = jfn;
if (!jsys(GDSTS, ablock)) return 0;
if (a) *a = ablock[2];
if (b) *b = ablock[3];
if (c) *c = ablock[4];
return 1;
}
#endif /* T20+10X */