typetab.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 1998 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <ctype.h>
/*#include <sys/types.h> included by dirent.h abs */
#include <dirent.h> /* changed from sys/dir.h abs */
#include <sys/stat.h>
#include <sys/times.h>
#include <errno.h>
#include "mio.h"
#include "wish.h"
#include "sizes.h"
#include "typetab.h"
#include "partabdefs.h"
#include "var_arrays.h"
#include "moremacros.h"
/* This file contains a package of functions which manipulate object
* type tables (ott's). The ott's are files (one per Telesystem
* directory) which contain information about all objects in that
* directory.
*
* See the liboh.a reference card for a description of the functions
* in here.
*/
#define HSIZE 512 /* hash table size, must be power of 2! */
#define ODISIZ (2*PATHSIZ)
#define NULLSTR ""
/* some statics global to these internal routines */
struct ott_tab Otts[MAX_OTT];
struct ott_tab *Cur_ott; /* pointer to current tab in Ott */
struct ott_entry *Cur_entry; /* pointer to current entry in Cur_ott */
static int Creation_size = OTT_ENTRIES; /* number of entrys to create */
static char Ott_version[] = "OTT V1.1\n"; /* file sys independent abs. */
static char Ott_name[] = "/.ott";
static int Ott_len = 5; /* strlen of above string */
clock_t times(); /* EFT abs k16 */
extern long a64l(); /* abs k16 */
char *estrtok();
static char *Scanenv;
int
scanbuf(buf, hold, max_len)
char *buf, *hold;
int max_len;
{
register char *p = estrtok(&Scanenv, buf, "|\n");
hold[0] = '\0';
if (!p)
return(O_FAIL);
strncpy(hold, p, max_len-1);
hold[max_len-1] = '\0';
return(0);
}
int
scanhex(buf, var)
char *buf;
long *var;
{
register char *p = estrtok(&Scanenv, buf, "|");
long strtol();
if (!p)
return(O_FAIL);
*var = strtol(p, NULL, 16);
return(0);
}
static int
ott_read(path, readall)
char *path;
bool readall; /* read the .ott as well as cross indexing directory */
{
register int i, j, alldead;
int size;
bool convert = FALSE;
FILE *ottfp;
DIR *dirfp; /* abs */
int recnum, result;
char ottname[PATHSIZ], buf[BUFSIZ];
char fname[FILE_NAME_SIZ]; /* abs */
static char *found;
short int qhtab[HSIZE]; /*quick hash table really kludgy but real easy*/
struct ott_entry *name_to_ott();
char *def_display();
char name[FILE_NAME_SIZ], dname[DNAMESIZ], display[DISPSIZ],
obtype[OTYPESIZ], odinfo[ODISIZ];
long mask;
time_t mtime; /* EFT abs k16 */
int hindex, val;
struct ott_entry *entry;
struct stat sbuf, dirsbuf;
struct dirent *dir_entry; /* for reading in the directory structure */
struct tms timebuf; /* for keeping timing statistics */
time_t stime, utime; /* EFT abs k16 */
static char *stray; /* stray files, i.e. not in ott */
times(&timebuf);
stime = timebuf.tms_stime;
utime = timebuf.tms_utime;
#ifdef _DEBUG
_debug(stderr, "READING: %s\n", path);
#endif
if ((dirfp = opendir(path)) == NULL || /* use fs independent funcs. abs */
stat(path, &dirsbuf) == -1)
{
#ifdef _DEBUG
_debug(stderr, "DIR open failed %s errno=%d\n", path,errno);
#endif
/* (void) fclose(dirfp); */
return(O_FAIL);
}
memset(qhtab,0xff,HSIZE*sizeof(short int)); /* initialize hash table */
if (found) /* the found array will be used to cross index the ott*/
array_trunc(found);
else {
found = (char *) array_create(sizeof(char), Creation_size);
array_ctl(found, OTT_ENTRIES);
}
if (readall) { /* is the following calculation valid?? <<<<<<<<<<<<< */
Creation_size = dirsbuf.st_size/sizeof(struct dirent); /* <<<<<<<<<<<<< */
ott_init(); /* get a new current ott */
Cur_ott->dir_mtime = dirsbuf.st_mtime;
if ((int)strlen(path) + Ott_len + 1 > PATHSIZ) { /* EFT abs k16 */
#ifdef _DEBUG
_debug(stderr, ".ott path too long for %s\n", path);
#endif
return(O_FAIL);
}
strcat(strcpy(ottname, path), Ott_name);
Cur_ott->path = strsave(path);
Cur_ott->modes = OTT_ACTIVE;
Cur_ott->prefs = 0;
Cur_ott->fmask = 0;
ottfp = (FILE *)NULL;
recnum = 0;
if ((ottfp = fopen(ottname, "r")) != NULL &&
(fstat(fileno(ottfp), &sbuf) != -1) ) {
#ifdef _DEBUG
_debug(stderr, "Opened ott fd=%d\n", (int)fileno(ottfp));
#endif
Cur_ott->ott_mtime = sbuf.st_mtime;
if (fgets(buf, BUFSIZ, ottfp) && strcmp(buf, Ott_version) != 0) {
Cur_ott->modes |= OTT_DIRTY;
rewind(ottfp);
}
while (fgets(buf, BUFSIZ, ottfp) != NULL) {
odinfo[0] = '\0';
#ifdef _DEBUG
_debug(stderr, ".");
#endif
if (scanbuf(buf, name, FILE_NAME_SIZ) ||
scanbuf(NULL, dname, DNAMESIZ) ||
scanbuf(NULL, display, DISPSIZ) ||
scanbuf(NULL, obtype, OTYPESIZ) ||
scanhex(NULL, &mask) ||
scanhex(NULL, &mtime)) {
Cur_ott->modes |= OTT_DIRTY; /* force rewrite */
continue;
}
scanbuf(NULL, odinfo, ODISIZ); /* odi allowed to be null */
Cur_entry = (struct ott_entry *) array_append(Cur_entry, NULL);
Cur_ott->ott = Cur_entry;
entry = Cur_entry + recnum;
hindex = qhash(name);
val = qhtab[hindex];
if (val == -1)
qhtab[hindex] = recnum;
else
qhtab[hindex] = recnum>val?val:recnum;
/* the found array will be used later during the cross-index*/
found = (char *) array_append(found, NULL);
found[recnum] = 'n';
strncpy(entry->name, name, FILE_NAME_SIZ);
entry->name[FILE_NAME_SIZ - 1] = '\0';
entry->dirpath = Cur_ott->path;
if (obtype[0] == ' ')
entry->objtype = NULL;
else
entry->objtype = strsave(obtype);
entry->mtime = mtime;
entry->next_part = OTTNIL;
if (strcmp(dname, " ") == 0) {
entry->dname = NULL;
if (recnum > 0) {
entry[-1].next_part = recnum;
} else {
#ifdef _DEBUG
_debug(stderr, "Orphan\n");
#endif
continue;
}
} else {
if (strcmp(dname, ".") == 0)
entry->dname = strsave(entry->name);
else {
dname[DNAMESIZ - 1] = '\0';
entry->dname = strsave(dname);
}
}
if (strcmp(display, " ") == 0)
entry->display = NULL;
else if (strcmp(display, ".") == 0)
entry->display = def_display(obtype);
else
entry->display = strsave(display);
entry->objmask = mask;
if (*odinfo)
entry->odi = strsave(odinfo);
else
entry->odi = NULL;
recnum++;
}
} else {
Cur_ott->modes |= OTT_DIRTY;
#ifdef _DEBUG
_debug(stderr, "creating ott\n");
#endif
}
Cur_ott->priority = recnum/15; /* favor bigger .ott's */
if (ottfp)
(void) fclose(ottfp);
} else { /* ott already in core, just construct the cross-index array*/
recnum = array_len(Cur_entry);
#ifdef _DEBUG
_debug(stderr, "Only doing cross-index\n");
#endif
Cur_ott->dir_mtime = dirsbuf.st_mtime;
Cur_ott->fmask = 0;
Cur_ott->prefs = 0;
Cur_ott->modes = OTT_ACTIVE;
for (i = 0; i < recnum; i++) {
Cur_entry[i].objmask &= ~M_DL; /* undelete it: refigure */
hindex = qhash(Cur_entry[i].name);
val = qhtab[hindex];
if (val == -1)
qhtab[hindex] = i;
else
qhtab[hindex] = i>val?val:i;
/* entry not found yet*/
found = (char *)array_append(found, NULL);
found[i] = 'n';
}
}
if (Cur_ott->dir_mtime >= Cur_ott->ott_mtime) {
/* Cross index the ott with the unix directory structure,
* putting anything that is not found in the stray array.
* The stray array will be passed to the heuristics program
* to determine the type of object.
*/
if (stray)
array_trunc(stray); /* just reset. */
else /* 1st time */
{
stray = (char *)array_create(FILE_NAME_SIZ, Creation_size/2 + 1);
array_ctl(stray, OTT_ENTRIES/2);
}
/* skip . & ..
** (void) fseek(dirfp,(long)(2*sizeof(struct direct)),0);
** while (fread(&dir, sizeof(dir), 1, dirfp) > 0) {
*/
dir_entry = readdir(dirfp); /* skip "." abs */
dir_entry = readdir(dirfp); /* skip ".." abs */
while ((dir_entry = readdir(dirfp)) != NULL) /* abs */
{
if (dir_entry->d_ino == 0) /* file was deleted, skip it*/
continue;
strncpy(fname, dir_entry->d_name, FILE_NAME_SIZ);
fname[FILE_NAME_SIZ -1] = '\0';
i = qhtab[qhash(fname)];
entry = NULL;
if (i != -1) {
for (; i < recnum; i++)
if (strcmp(fname, Cur_entry[i].name) == 0) {
entry = Cur_entry + i;
break;
}
}
if (entry != NULL) {
found[entry - Cur_entry] = 'y';
} else if (fname[0] != '.' ||
strcmp(fname, ".ott") == 0 ||
strcmp(fname, ".pref") == 0 ||
strncmp(fname, ".V", 2) == 0 ||
strncmp(fname, ".L", 2) == 0) {
#ifdef _DEBUG
_debug(stderr, "s");
#endif
stray = (char *) array_append(stray, fname);
}
}
closedir(dirfp); /* abs */
/* delete any entries in the ott which have no counterpart in the
* directory.
*/
size = array_len(found);
for (i = 0; i < size; i++) {
if (found[i] == 'n') { /* doesn't exist in unix dir, delete */
/* skip parts that are in a subdirectory */
if (strchr(Cur_entry[i].name, '/') && !Cur_entry[i].dname)
continue;
Cur_ott->modes |= OTT_DIRTY;
if (Cur_entry[i].dname) { /* parent, kill only if all kids dead*/
alldead = 1;
j = i+1;
while (j < recnum && ! Cur_entry[j].dname) {
if (found[j] == 'y') {
alldead = 0;
break;
}
j++;
}
if (alldead) {
do {
Cur_entry[i].name[0] = '\0';
Cur_entry[i++].objmask |= M_DL;
} while (i < recnum && Cur_entry[i].dname == NULL);
i--;
}
} else {
Cur_entry[i].name[0] = '\0';
Cur_entry[i].objmask |= M_DL;
Cur_entry[i-1].next_part = Cur_entry[i].next_part;
}
}
}
/* run heuristics on the stray entries */
if (array_len(stray) != 0) {
#ifdef _DEBUG
_debug(stderr, "\nHeur: %d files\n\n", array_len(stray));
#endif
heuristics(path, stray);
Cur_ott->modes |= OTT_DIRTY;
}
} else {
#ifdef _DEBUG
_debug(stderr, "ott older than dir - no cross index\n");
#endif
closedir(dirfp); /* abs */
}
times(&timebuf);
#ifdef _DEBUG
_debug(stderr, "\nREAD TIME: %du + %ds = %d/100 secs ",
(timebuf.tms_utime-utime), (timebuf.tms_stime-stime),
(i = timebuf.tms_utime + timebuf.tms_stime - utime - stime));
if ((readall && (j = array_len(Cur_entry))) || (j = array_len(stray)))
_debug(stderr, "(%d/1000 per file)\n\n",(10*i)/j);
else
_debug(stderr, "\n");
#endif
if (name_to_ott(".pref") != NULL) {
char buf[BUFSIZ];
/* add 1 - here if adding /.ott short enough & /.pref is 1 more */
char pref[PATHSIZ + 1];
FILE *fp;
long strtol();
#ifdef _DEBUG
_debug(stderr, "Reading .pref\n");
#endif
sprintf(pref, "%s/.pref", path);
if ((fp = fopen(pref, "r")) == NULL) {
#ifdef _DEBUG
_debug(stderr, "no .pref\n");
#endif
return(O_OK);
}
while (fgets(buf, BUFSIZ, fp) != NULL) {
if (strncmp(buf, "DISPMODE=", 9) == 0) {
Cur_ott->prefs |= PREF_DIS;
Cur_ott->modes |= strtol(buf+9, (char **)NULL, 16);
#ifdef _DEBUG
_debug(stderr, "DISP=%s (%x)\n", buf+9, strtol(buf+9,NULL,16));
#endif
} else if (strncmp(buf, "SORTMODE=", 9) == 0) {
Cur_ott->prefs |= PREF_SORT;
Cur_ott->modes |= strtol(buf+9, (char **)NULL, 16);
#ifdef _DEBUG
_debug(stderr, "SORT=%s (%x)\n", buf+9, strtol(buf+9,NULL,16));
#endif
} else if (strncmp(buf, "FMASK=", 6) == 0) {
Cur_ott->fmask = strtol(buf+6, (char **)NULL, 10);
} else if (strncmp(buf, "MAX_AGE=", 8) == 0) {
ott_del_old(strtol(buf + 8, (char **) NULL, 10));
} else if (strncmp(buf, "PRIORITY=", 9) == 0) {
Cur_ott->priority = strtol(buf+9, (char **)NULL, 10);
}
}
fclose(fp);
}
#ifdef _DEBUG
else
_debug(stderr, "No .pref\n");
#endif
if (Cur_ott->modes & OTT_DIRTY) {
#ifdef _DEBUG
_debug(stderr, "Writing ott\n");
#endif
ott_write();
}
return(O_OK);
}
ott_del_old(age)
long age;
{
int i;
struct ott_entry *ent, *ott_next_part();
time_t thetime; /* EFT abs k16 */
int lcv;
if (age < 1 || age > 365)
return;
thetime = time(NULL) - 24 * 60 * 60 * age;
#ifdef _DEBUG
_debug(stderr, "ctime(&thetime) = %s\n", ctime(&thetime));
#endif
lcv = array_len(Cur_ott->ott);
for (i = 0; i < lcv; i++) {
ent = Cur_ott->ott + i;
/*
* If we are doing a MAIL_OUT object, then we automatically age it
*/
if (strcmp(ent->objtype, "MAIL_OUT") == 0)
if (ent->mtime < thetime) {
do {
ent->objmask |= M_WB;
Cur_ott->modes |= OTT_DIRTY;
ent = ott_next_part(ent);
} while (ent);
}
}
}
/* simple multiplicative hash function. This hashing algorithm is
* really great as long as there are less than about 100 files in a
* directory. It begins to degrade after that, and is about as
* efficient as a linear search if the number of files goes beyond about
* 300. It never gets worse than linear search. It is great because there
* are no "buckets" a simple collision mechanism and quick search time.
*/
static int
qhash(str)
char *str;
{
register int result = 511; /* why 511? why not. */
while (*str) {
result *= *str++;
}
return( (result>>8) & (HSIZE-1) ); /* take the middle bits */
}
struct ott_entry *
ott_make_entry(name,dname,objtype,objmask,odi,mtime)
char *name, *dname, *objtype;
long objmask;
char *odi;
time_t mtime; /* EFT abs k16 */
{
struct ott_entry *entry;
struct stat sbuf;
char *def_display(), *def_objtype();
Cur_entry = (struct ott_entry *)array_append(Cur_entry, NULL);
Cur_ott->ott = Cur_entry;
entry = Cur_entry + array_len(Cur_entry) - 1;
strncpy(entry->name, name, FILE_NAME_SIZ);
if (objtype && objtype[0]) {
entry->objtype = def_objtype(objtype);
entry->display = def_display(objtype);
} else {
entry->objtype = NULL;
entry->display = NULL;
}
if ((int)strlen(dname) >= DNAMESIZ) /* EFT abs k16 */
dname[DNAMESIZ-1] = '\0';
if (dname && dname[0]) {
entry->dname = strsave(dname);
} else {
entry->dname = NULL;
entry[-1].next_part = entry - Cur_entry;
}
if (odi && odi[0])
entry->odi = strsave(odi);
else
entry->odi = NULL;
entry->next_part = OTTNIL;
entry->objmask = objmask;
if (mtime)
entry->mtime = mtime;
else {
if (stat(name, &sbuf) != -1)
entry->mtime = sbuf.st_mtime;
else
entry->mtime = time((time_t *) 0);
}
entry->dirpath = Cur_ott->path;
Cur_ott->modes |= OTT_DIRTY; /* needs writing */
return(entry);
}
struct ott_entry *
ott_add_entry(ottpath, name, dname, objtype, mask, odi, mtime)
char *ottpath, *name, *dname, *objtype;
long mask;
char *odi;
time_t mtime; /* EFT abs k16 */
{
struct ott_entry *entry;
struct ott_entry *name_to_ott();
if (ottpath) {
if (make_current(ottpath) == O_FAIL)
return(NULL);
}
if (dname)
ott_lock_dsk(Cur_ott->path);
if (entry = name_to_ott(name)) {
#ifdef _DEBUG
_debug(stderr, "ott_add_entry: deleting previous entry for %s\n", entry->name);
#endif
entry->objmask |= M_DL; /* remove if already in */
}
return(ott_make_entry(name, dname, objtype, mask, odi, mtime));
}
static int
ott_alphasort(el1, el2)
int *el1, *el2;
{
int reverse = (Cur_ott->modes & OTT_SREV)?-1:1;
return(reverse * strcmp(Cur_entry[*el1].dname, Cur_entry[*el2].dname));
}
static int
ott_obj_alphasort(el1, el2)
int *el1, *el2;
{
int comp1;
int reverse = (Cur_ott->modes & OTT_SREV)?-1:1;
if ((comp1 = strcmp(Cur_entry[*el1].display, Cur_entry[*el2].display)) == 0)
return(ott_alphasort(el1, el2));
else
return(reverse * comp1);
}
static int
ott_timesort(el1, el2)
int *el1, *el2;
{
time_t time1, time2; /* EFT abs k16 */
char *key, *odi_getkey();
int reverse = (Cur_ott->modes & OTT_SREV)?-1:1;
if (key = odi_getkey(Cur_entry + *el1, "DATE"))
time1 = a64l(key);
else
time1 = Cur_entry[*el1].mtime;
if (key = odi_getkey(Cur_entry + *el2, "DATE"))
time2 = a64l(key);
else
time2 = Cur_entry[*el2].mtime;
return(reverse * (time2 - time1));
}
ott_dirty()
{
Cur_ott->modes |= OTT_DIRTY;
}
/*
* Synchronize the current internal ott with the disk version. The ott
* should always be locked during internal changes, so there should be
* no problems with contention. This routine will sort the current ott,
* then write it out to disk, then unlock it.
*/
struct ott_tab *
ott_synch(nosort)
bool nosort; /* don't sort if not dirty */
{
register int size = array_len(Cur_entry);
int i;
long objmask, amask, nmask, smask;
if (nosort && !(Cur_ott->modes & OTT_DIRTY))
return(Cur_ott);
if (Cur_ott->modes & OTT_DIRTY) {
ott_lock_dsk(Cur_ott->path);
#ifdef _DEBUG
_debug(stderr, "ott_synch: writing dirty ott %s\n", Cur_ott->path);
#endif
ott_write();
ott_unlock_dsk(Cur_ott->path);
}
/* scan the ott, keeping a list of parents */
array_trunc(Cur_ott->parents);
smask = Cur_ott->amask & Cur_ott->nmask;
amask = Cur_ott->amask & ~smask;
nmask = Cur_ott->nmask & ~smask;
for (i = 0; i < size; i++) {
objmask = Cur_entry[i].objmask;
if ( Cur_entry[i].dname && Cur_entry[i].dname[0] &&
Cur_entry[i].name[0] &&
!(objmask & M_DL) &&
((amask & objmask)==amask) &&
!(nmask & objmask) &&
((!smask) || (smask & objmask)) &&
(Cur_entry[i].dname[0] != '.' || Cur_ott->modes & OTT_DALL))
Cur_ott->parents = (int *)array_append(Cur_ott->parents, &i);
}
/* sort the array of parents */
#ifdef _DEBUG
if (Cur_ott->modes & OTT_SREV)
_debug(stderr, "reverse ");
#endif
if (Cur_ott->modes & OTT_SALPHA) {
#ifdef _DEBUG
_debug(stderr, "alpha sort\n");
#endif
qsort((char *)Cur_ott->parents, array_len(Cur_ott->parents),
sizeof(int), ott_alphasort);
} else if (Cur_ott->modes & OTT_SMTIME) {
#ifdef _DEBUG
_debug(stderr, "modtime sort\n");
#endif
qsort((char *)Cur_ott->parents, array_len(Cur_ott->parents),
sizeof(int), ott_timesort);
} else if (Cur_ott->modes & OTT_SOBJ) {
#ifdef _DEBUG
_debug(stderr, "objtype sort\n");
#endif
qsort((char *)Cur_ott->parents, array_len(Cur_ott->parents),
sizeof(int), ott_obj_alphasort);
}
#ifdef _DEBUG
else
_debug(stderr, "no sort\n");
#endif
if (Cur_ott->modes & OTT_DMAIL)
Cur_ott->numpages = ((int)array_len(Cur_ott->parents)+5) / 6;
else
Cur_ott->numpages = ((int)array_len(Cur_ott->parents)+6) / 7;
return(Cur_ott);
}
struct ott_tab *
ott_get_current()
{
return(Cur_ott);
}
struct ott_tab *
ott_reget()
{
return(ott_get(Cur_ott->path, Cur_ott->modes & SORTMODES, Cur_ott->modes & DISMODES, Cur_ott->amask, Cur_ott->nmask));
}
struct ott_tab *
ott_get(path, sortmode, dismode, amask, nmask)
char *path;
int sortmode, dismode;
long amask, nmask;
{
bool needsort = FALSE;
if (make_current(path) == O_FAIL)
return(NULL);
/* if being opened with different modes than current modes, then
* set and resort
*/
if (Cur_ott->nmask != nmask || Cur_ott->amask != amask) {
Cur_ott->nmask = nmask;
Cur_ott->amask = amask;
needsort = TRUE;
}
if (!(Cur_ott->prefs & PREF_SORT) &&
((Cur_ott->modes & SORTMODES) != sortmode)) {
needsort = TRUE;
Cur_ott->modes = (Cur_ott->modes & ~SORTMODES) | sortmode;
}
if (!(Cur_ott->prefs & PREF_DIS) &&
((Cur_ott->modes & DISMODES) != dismode)) {
needsort = TRUE;
Cur_ott->modes = (Cur_ott->modes & ~DISMODES) | dismode;
}
if (Cur_ott->prefs != 0)
needsort = TRUE;
if (needsort)
ott_synch(FALSE);
Cur_ott->curpage = 0;
Cur_ott->last_used = ott_use() + Cur_ott->priority;
#ifdef _DEBUG
_debug(stderr, "Usetime: %d\n", Cur_ott->last_used);
#endif
return(Cur_ott);
}
int
ott_in_core(path)
char *path;
{
register int i;
for (i = 0; i < MAX_OTT; i++)
if ( Otts[i].path && (Otts[i].modes&OTT_ACTIVE) &&
(strcmp(Otts[i].path, path) == 0) ) {
#ifdef _DEBUG
_debug(stderr, "Found %s incore\n", path);
#endif
return(i);
}
return(O_FAIL);
}
int
make_current(path)
char *path;
{
register int i;
struct stat sbuf, dirsbuf;
struct ott_entry *prefent, *name_to_ott();
char ottname[PATHSIZ];
int retcode;
bool readall = TRUE;
static int hits, trys;
trys++;
for (i = 0; i < MAX_OTT; i++) {
if (!(Otts[i].path))
continue;
if ((Otts[i].modes & OTT_ACTIVE) && (strcmp(Otts[i].path, path) == 0)) {
#ifdef _DEBUG
_debug(stderr, "Found %s incore\n", path);
#endif
Cur_ott = Otts + i;
Cur_entry = Cur_ott->ott;
hits++;
if (stat(path, &dirsbuf) == -1)
return(O_FAIL);
if ((int)strlen(Cur_ott->path) + Ott_len + 1 > PATHSIZ) /*EFT k16*/
{
#ifdef _DEBUG
_debug(stderr, ".ott path too long for %s\n", Cur_ott->path);
#endif
return(O_FAIL);
}
strcat(strcpy(ottname, Cur_ott->path), Ott_name);
if (stat(ottname, &sbuf) != -1 &&
Cur_ott->ott_mtime < sbuf.st_mtime) {
#ifdef _DEBUG
_debug(stderr, "Incore old (.ott)\n");
#endif
Cur_ott->modes &= ~OTT_ACTIVE; /* deallocate */
break; /* go down and read */
} else if (Cur_ott->dir_mtime < dirsbuf.st_mtime) {
#ifdef _DEBUG
_debug(stderr, "Incore old (dir)\n");
#endif
readall = FALSE;
break;
} else {
#ifdef _DEBUG
_debug(stderr, "hit ratio: %d/%d (%d%%)\n",hits,trys,(100*hits)/trys);
#endif
return(O_OK);
}
}
}
/* not resident, so read it in */
ott_lock_dsk(path);
retcode = ott_read(path, readall);
ott_unlock_dsk(path);
#ifdef _DEBUG
_debug(stderr, "hit ratio: %d/%d (%d%)\n",hits,trys,(100*hits)/trys);
#endif
return(retcode);
}
int
ott_lock_inc(optr)
struct ott_tab *optr;
{
#ifdef _DEBUG
_debug(stderr, "%s: locked\n", Cur_ott->path);
#endif
if (optr == NULL)
Cur_ott->modes |= OTT_LOCKED;
else
optr->modes |= OTT_LOCKED;
}
int
ott_unlock_inc(optr)
struct ott_tab *optr;
{
#ifdef _DEBUG
_debug(stderr, "%s: unlocked\n", Cur_ott->path);
#endif
if (optr == NULL)
Cur_ott->modes &= ~OTT_LOCKED;
else
optr->modes &= ~OTT_LOCKED;
}
int
ott_lock_dsk(path)
char *path;
{
return(O_OK);
}
int
ott_unlock_dsk(path)
char *path;
{
return(O_OK);
}
struct ott_entry *
name_to_ott(name)
char *name;
{
register int i, j;
register int size = array_len(Cur_entry);
register int psize= array_len(Cur_ott->parents);
for (i = 0; i < size; i++)
if (!(Cur_entry[i].objmask & M_DL) &&
strcmp(Cur_entry[i].name, name) == 0) {
for (j = 0; j < psize; j++) {
if (Cur_ott->parents[j] == i) {
if (Cur_ott->modes & OTT_DMAIL)
Cur_ott->curpage = j/6;
else
Cur_ott->curpage = j/7;
break;
}
}
if (Cur_ott->curpage > Cur_ott->numpages)
Cur_ott->curpage = Cur_ott->numpages;
return(Cur_entry + i);
}
Cur_ott->curpage = 0;
return(NULL);
}
struct ott_entry *
dname_to_ott(name)
char *name;
{
register int i;
register int size = array_len(Cur_entry);
for (i = 0; i < size; i++) {
if (Cur_entry[i].dname == NULL)
Cur_entry[i].dname = NULLSTR;
if (!(Cur_entry[i].objmask & M_DL) &&
strcmp(Cur_entry[i].dname, name) == 0)
return(Cur_entry + i);
}
return(NULL);
}
static int
ott_write()
{
register int i;
char *dname, *display;
FILE *ottfp;
int ottfd;
struct stat sbuf;
char ottname[PATHSIZ];
int size = array_len(Cur_entry);
char *def_display();
if ((int)strlen(Cur_ott->path) + Ott_len + 1 > PATHSIZ) /* EFT k16 */
{
#ifdef _DEBUG
_debug(stderr, ".ott path too long for %s\n", Cur_ott->path);
#endif
return(O_FAIL);
}
strcat(strcpy(ottname, Cur_ott->path), Ott_name);
if ((ottfd = open(ottname, O_CREAT|O_WRONLY|O_TRUNC,0666)) == -1 ||
(ottfp = fdopen(ottfd, "w")) == NULL) {
#ifdef _DEBUG
_debug(stderr, "Can't write ott (errno=%d)\n", errno);
#endif
(void) close(ottfd);
Cur_ott->ott_mtime = time(0); /* last time we tried to update is now*/
return(O_FAIL);
}
fprintf(ottfp, Ott_version);
for (i = 0; i < size; i++ ) {
if (Cur_entry[i].name[0] == '.' &&
strcmp(Cur_entry[i].name, ".pref") != 0 &&
strcmp(Cur_entry[i].name, ".ott") != 0 &&
strncmp(Cur_entry[i].name, ".V", 2) != 0 &&
strncmp(Cur_entry[i].name, ".L", 2) != 0)
continue;
if (!(Cur_entry[i].objmask & M_DL)) {
if (Cur_entry[i].dname && Cur_entry[i].dname[0]) {
if (strcmp(Cur_entry[i].dname, Cur_entry[i].name) == 0)
dname = ".";
else
dname = Cur_entry[i].dname;
} else
dname = " ";
if (Cur_entry[i].display && Cur_entry[i].display[0] &&
Cur_entry[i].objtype) {
if (strcmp(Cur_entry[i].display,
def_display(Cur_entry[i].objtype)) == 0)
display = ".";
else
display = Cur_entry[i].display;
} else
display = " ";
fprintf(ottfp,"%s|%.*s|%s|%s|%lx|%lx|%.*s\n",
Cur_entry[i].name,
DNAMESIZ,
dname,
display,
Cur_entry[i].objtype?Cur_entry[i].objtype:" ",
Cur_entry[i].objmask,
Cur_entry[i].mtime,
ODISIZ,
Cur_entry[i].odi?Cur_entry[i].odi:"");
}
}
if (fstat(ottfd, &sbuf) != -1)
Cur_ott->ott_mtime = sbuf.st_mtime;
if (stat(Cur_ott->path, &sbuf) != -1)
Cur_ott->dir_mtime = sbuf.st_mtime;
chown(ottname, sbuf.st_uid, sbuf.st_gid); /* ott owned and group of dir*/
(void) fclose(ottfp);
(void) close(ottfd);
Cur_ott->modes &= ~OTT_DIRTY;
return(O_OK);
}
static struct ott_tab *
ott_lru()
{
register int i;
int oldest = 0; /* abs k16 */
long oldusetime;
/* first, look for one that is unused */
for (i = 0; i < MAX_OTT; i++)
if (!(Otts[i].modes & OTT_ACTIVE)) {
Otts[i].modes |= OTT_ACTIVE;
return(Otts+i);
}
#ifdef _DEBUG
_debug(stderr, "No Free Ott, dealloc\n");
#endif
/* ok, so there is none free. Now what? Good question.
* So, we'll find the one that's been ott_get()'ed least recently.
*/
oldest = 0;
oldusetime = Otts[oldest].last_used;
for (i = 1; i < MAX_OTT; i++) {
if (!(Otts[i].modes & OTT_LOCKED) && Otts[i].last_used < oldusetime) {
oldest = i;
oldusetime = Otts[i].last_used;
}
}
#ifdef _DEBUG
_debug(stderr,"Selected %s for dealloc %d\n",Otts[oldest].path,oldusetime);
#endif
Otts[oldest].modes |= OTT_ACTIVE;
return(Otts + oldest);
}
int
ott_init()
{
register int i, size;
Cur_ott = ott_lru();
if (Cur_ott->ott == NULL) { /* first time using this ott */
Cur_ott->ott = (struct ott_entry *)
array_create(sizeof(struct ott_entry), Creation_size);
Cur_entry = Cur_ott->ott;
array_ctl(Cur_entry, OTT_ENTRIES);
Cur_ott->parents = (int *) array_create(sizeof(int), Creation_size);
} else {
size = array_len(Cur_ott->ott);
for (i = 0; i < size; i++)
ott_int_free(Cur_ott->ott + i);
if (Cur_ott->path)
free(Cur_ott->path);
array_trunc(Cur_ott->ott);
array_trunc(Cur_ott->parents);
Cur_entry = Cur_ott->ott;
}
Cur_ott->curpage = Cur_ott->numpages = 0;
Cur_ott->ott_mtime = (time_t)0; /* EFT abs k16 */
Cur_ott->modes = 0L;
}
static int
ott_use()
{
static int use;
return(++use);
}
struct ott_entry *
ott_next_part(entry)
struct ott_entry *entry;
{
if (entry->next_part != OTTNIL)
return(Cur_ott->ott + entry->next_part);
else
return(NULL);
}