V10/netfs/serv/f11sub.c
/*
* files-11 subroutines,
* mostly concerned directly with
* filesystem structures
*/
#include <time.h>
#include <ctype.h>
#include <rf.h>
#include "files11.h"
#include "f11.h"
#define NULL 0
/*
* convert files-11 ascii time to unix binary time
* 13 bytes: DDMMMYYhhmmss
*/
static char *months[] = {
"JAN", "FEB", "MAR", "APR", "MAY", "JUN",
"JUL", "AUG", "SEP", "OCT", "NOV", "DEC", 0
};
static int i2val();
long
htoutime(ht)
register char *ht;
{
struct tm tm;
register int mon;
if (*ht == 0)
return (0);
tm.tm_yday = 0;
tm.tm_mday = i2val(ht);
ht += 2;
for (mon = 0; months[mon]; mon++)
if (strncmp(ht, months[mon], 3) == 0)
break;
tm.tm_mon = mon;
ht += 3;
tm.tm_year = i2val(ht);
ht += 2;
tm.tm_hour = i2val(ht);
ht += 2;
tm.tm_min = i2val(ht);
ht += 2;
tm.tm_sec = i2val(ht);
return (timelocal(&tm, (char *)NULL));
}
static int
i2val(s)
register char *s;
{
if (!isdigit(s[0]) || !isdigit(s[1]))
return (0);
return ((s[0]-'0') * 10 + (s[1]-'0'));
}
/*
* convert f11 protection to unix permissions
* information is lost, most importantly the delete flag
*/
int
htouperm(hp)
register int hp;
{
register int up;
register int i;
hp >>= 4; /* discard `system' field */
up = 0;
for (i = 0; i < 3; i++) { /* and do owner, group, world */
up <<= 3;
if ((hp & 1) == 0) /* read */
up |= 4;
if ((hp & 2) == 0) /* write */
up |= 2;
if ((hp & 4) == 0) /* execute */
up |= 1;
hp >>= 4;
}
return (up);
}
/*
* compute the file size
* use the FCS attributes if they look valid,
* else just count the blocks
*/
long
hfilesize(h)
register struct header *h;
{
register int i;
register long sz;
register Bmap *bp;
if (h->h_fcs.f_rtyp != 0) {
sz = plong(h->h_fcs.f_efbk) - 1;
sz *= BLKSIZ;
sz += h->h_fcs.f_ffby;
return (sz);
}
for (sz = 0, i = 0; bp = getmap(&h->h_map, i); i++)
sz += bp->count;
return (sz * BLKSIZ);
}
/*
* search a directory
* return the file id
*/
int
f11walk(df, name)
Rfile *df;
char *name;
{
struct filnam fn;
register struct directory *dp;
register struct filnam *fp;
register unsigned short bestfid, bestver;
char buf[BLKSIZ];
long bno;
if (utohname(name, &fn) == 0) {
fserrno = RFEINVAL;
return (0);
}
bestfid = 0;
bestver = 0;
fp = &fn;
for (bno = 0; f11rblk(df, bno, buf) > 0; bno++) {
dp = (struct directory *)buf;
for (; dp < (struct directory *)&buf[BLKSIZ]; dp++) {
if (dp->d_fid.f_num == 0)
continue;
if (dp->d_fname.f_nam[0] != fp->f_nam[0]
|| dp->d_fname.f_nam[1] != fp->f_nam[1]
|| dp->d_fname.f_nam[2] != fp->f_nam[2]
|| dp->d_fname.f_typ != fp->f_typ)
continue;
if (dp->d_fname.f_ver == fp->f_ver)
return (dp->d_fid.f_num); /* exact match */
if (fp->f_ver)
continue; /* exact wanted */
if (dp->d_fname.f_ver > bestver) {
bestver = dp->d_fname.f_ver;
bestfid = dp->d_fid.f_num;
}
}
}
if (bestfid == 0)
fserrno = RFENOENT;
return (bestfid);
}
/*
* convert an ascii filename into a files-11 one
* unspecified parts are left 0
* returns 0 for bad filename, 1 for ok
*/
int
utohname(name, f)
char *name;
register struct filnam *f;
{
char *n;
register char *e;
register int i;
register int x;
f->f_nam[0] = f->f_nam[1] = f->f_nam[2] = 0;
f->f_typ = 0;
f->f_ver = 0;
n = name;
for (e = n; *e && *e != '.'; e++)
;
if (e - n > 9)
return (0);
if (*e)
*e++ = 0;
for (i = 0; i < 3; i++) {
if ((x = ator50(&n)) < 0)
return (0);
f->f_nam[i] = x;
}
n = e;
for (; *e && *e != '.'; e++)
;
if (e - n > 3)
return (0);
if (*e)
*e++ = 0;
if ((x = ator50(&n)) < 0)
return (0);
f->f_typ = x;
if (*e) {
x = atoi(e);
if (x < 0 || x > 65535)
return (0);
f->f_ver = x;
}
return (1);
}
/*
* read a block from a file
*/
int
f11rblk(f, bno, buf)
Rfile *f;
long bno;
char *buf;
{
register Bmap *bp;
if ((bp = getblk(fsp(f), bno)) == NULL)
return (0);
lseek(diskfd, (long)bp->bno * BLKSIZ, 0);
if (read(diskfd, buf, BLKSIZ) != BLKSIZ)
return (-1);
return (1);
}
/*
* get the header for a file
*/
int
gethdr(fid, hp)
unsigned short fid;
struct header *hp;
{
long bno;
register Bmap *bp;
bno = IBITMAP + home.H_ibsz + fidtob(fid);
if ((bp = getblk(&indexf, bno)) == NULL)
return (0);
lseek(diskfd, (long)bp->bno * BLKSIZ, 0);
if (read(diskfd, (char *)hp, sizeof(*hp)) != sizeof(*hp))
return (0);
if (hp->h_fnum != fid)
fprint(2, "gethdr: wanted fid %d, got %d\n", fid, hp->h_fnum);
return (1);
}
/*
* get the map for a chunk of a file,
* starting at block bno
*/
Bmap *
getblk(fsf, bno)
register Fsfile *fsf;
long bno;
{
static Bmap b;
long offset;
int mi;
long mbno;
register Bmap *bp;
offset = bno - fsf->lbase;
if (offset > 0 && offset < fsf->lmap.count) { /* within cached map */
b.count = fsf->lmap.count - offset;
b.bno = fsf->lmap.bno + offset;
return (&b);
}
if (offset > 0) {
mi = fsf->lmi + 1;
mbno = fsf->lbase + fsf->lmap.count;
} else {
mi = 0;
mbno = 0;
}
while ((bp = getmap(&fsf->h.h_map, mi)) != NULL) {
if (mbno + bp->count < bno) {
mbno += bp->count;
mi++;
continue;
}
fsf->lbase = mbno;
fsf->lmi = mi;
fsf->lmap = *bp;
offset = bno - mbno;
b.count = bp->count - offset;
b.bno = bp->bno + offset;
return (&b);
}
return (NULL);
}
/*
* fetch the n'th retrieval pointer from a map
* no hope for extended headers yet
*/
#define RS(c, l) ((c << 8)|l)
Bmap *
getmap(m, n)
register struct map *m;
int n;
{
static Bmap b;
register unsigned char *p;
register int off;
off = m->m_ctsz + m->m_lbsz;
off *= n;
if (off >= m->m_use * sizeof(short))
return (NULL);
p = m->m_rtrvp + off;
switch (RS(m->m_ctsz, m->m_lbsz)) {
case RS(1, 3):
b.count = p[1];
b.bno = (p[0]<<24) | p[2] | (p[3]<<8);
break;
case RS(2, 2):
b.count = p[0] | (p[1]<<8);
b.bno = p[2] | (p[3]<<8);
break;
case RS(2, 4):
b.count = p[0] | (p[1]<<8);
b.bno = (p[3]<<16) | (p[4]<<24) | p[4] | (p[5]<<8);
break;
default:
return (NULL);
}
b.count++;
return (&b);
}