This is afposenum.c in view mode; [Download] [Up]
/*
* $Author: cck $ $Date: 88/03/20 18:37:22 $
* $Header: afposenum.c,v 1.15 88/03/20 18:37:22 cck Rel $
* $Revision: 1.15 $
*/
/*
* afposenum.c - Appletalk Filing Protocol OS enumeration.
*
* AppleTalk package for UNIX (4.2 BSD).
*
* Copyright (c) 1986, 1987, 1988 by The Trustees of Columbia University in the
* City of New York.
*
* Edit History:
*
* March 1987 Schilit Created.
*
*/
#include <stdio.h>
#include <sys/param.h>
#ifndef _TYPES
/* assume included by param.h */
# include <sys/types.h>
#endif
#include <sys/dir.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <netat/appletalk.h>
#include <netat/afp.h>
#include <strings.h>
#include "afps.h"
#include "afpdt.h"
#include "afpgc.h"
typedef struct { /* Enumeration cache entry */
IDirP ece_dirid; /* enumerated directory id */
int ece_lru;
int ece_lock; /* do not purge lock */
int ece_cnt; /* count of entries */
struct direct **ece_nlst; /* direct info */
time_t ece_ctime; /* last directory write dt */
int ece_mmode; /* last directory mode */
int ece_mcnt; /* last internal modify count */
int ece_idx; /* our index in the cache */
} EnumCE;
#define NILECE ((EnumCE *) 0)
private EnumCE *EnumCache[NECSIZE];
private int EC_Clock; /* lru clock */
#define NILNLST ((struct direct **) 0)
private EnumCE *EC_Min(),*EC_Find(),*EC_Fetch(),*EC_Load();
private boolean EC_Valid();
private void EC_Free();
private iselect();
#ifdef NOCASEMATCH
private noCaseDir();
private searchDirectory();
#endif NOCASEMATCH
/*
* int iselect(struct direct *d)
*
* See if this directory entry should be included in our enumeration.
* Special files are skipped ("." , ".." ".finderinfo", etc) and
* a length check is made to see if the name is too long for AFP.
*
*/
private
iselect(d)
struct direct *d;
{
if (ENameLen(d->d_name) > MAXLFLEN) /* external name too long? */
return(FALSE); /* sorry this name is too long */
if (d->d_name[0] != '.') /* all special dirs begin with dot */
return(TRUE);
if (d->d_namlen == 1) /* check for dot */
return(FALSE);
if (d->d_namlen == 2 && /* check for dot dot */
d->d_name[1] == '.')
return(FALSE);
if (strcmp(d->d_name,RFDIRFN) == 0) /* resource fork directory? */
return(FALSE); /* yes... don't include */
if (strcmp(d->d_name,FIDIRFN) == 0) /* finder info directory? */
return(FALSE); /* yes... don't include */
if (strcmp(d->d_name,DESKTOP_ICON) == 0) /* check for desktop files */
return(FALSE);
if (strcmp(d->d_name,DESKTOP_APPL) == 0)
return(FALSE);
return(TRUE);
}
/*
* void ECacheInit()
*
* Initialize the cache table.
*
*/
void
ECacheInit()
{
int i;
if (DBENU)
printf("ECacheInit: Cache size is %d\n",NECSIZE);
EC_Clock = 1; /* init clock */
for (i=0; i < NECSIZE; i++) {
EnumCache[i] = (EnumCE *) malloc(sizeof(EnumCE));
EnumCache[i]->ece_dirid = NILDIR;
EnumCache[i]->ece_idx = i;
}
}
private EnumCE *
EC_Min()
{
int i,mi = -1;
int mlru = EC_Clock+1;
for (i=0; i < NECSIZE; i++) {
if (EnumCache[i]->ece_dirid == NILDIR)
return(EnumCache[i]); /* found unused slot */
if (!EnumCache[i]->ece_lock && /* if not locked and... */
EnumCache[i]->ece_lru < mlru) { /* is older than current */
mlru = EnumCache[i]->ece_lru; /* remember new clock */
mi = i; /* and new index */
}
}
if (mi == -1) /* all locked? big problem */
log("EC_Min: no entry found\n"); /* at least we will know */
return(EnumCache[mi]);
}
/*
* void EC_Free(EnumCE *ec)
*
* Free storage associate with a cache entry and set the entry to be
* unused by making ece_dirid = NILDIR.
*
*/
private void
EC_Free(ec)
EnumCE *ec;
{
int i;
if (ec->ece_dirid == NILDIR) /* unused entry? */
return; /* yes, just return */
if (DBENU)
printf("EC_Free: releasing %s\n",pathstr(ec->ece_dirid));
for (i=0; i < ec->ece_cnt; i++)
free((char *) ec->ece_nlst[i]);
free((char *) ec->ece_nlst);
(ec->ece_dirid)->eceidx = NOECIDX; /* not in cache */
ec->ece_dirid = NILDIR; /* indicate free entry */
}
/*
* boolean EC_Valid(EnumCE *ec, struct stat *stb)
*
* Check if the cache entry is valid by comparing information in
* the cache entry with information provided from the stat.
*
* If the cache entry is empty, the internal modification counters
* are different, or the directory modification time_t differs from
* the time_t the entry was created, then return FALSE.
*
*/
private boolean
EC_Valid(ec,stb)
EnumCE *ec;
struct stat *stb;
{
IDirP dirid = ec->ece_dirid;
if (ec->ece_dirid == NILDIR) /* no entry? */
return(FALSE); /* should not happen */
/* See if the directory has been modified and needs to be reread */
/* Check both the internal modified counter and the os modify times. */
/* The internal mod counts are to prevent a race condition with the */
/* file's mod times not getting set/read correctly */
if (ec->ece_dirid->modified != ec->ece_mcnt) { /* modified by us? */
if (DBENU)
printf("EC_Valid: internal modify invalidates %s\n",pathstr(dirid));
return(FALSE); /* yes... */
}
if ((stb->st_ctime != ec->ece_ctime) || (stb->st_mode != ec->ece_mmode)) {
if (DBENU)
printf("EC_Valid: external modify invalidates %s\n",pathstr(dirid));
return(FALSE);
}
return(TRUE); /* not modified */
}
/*
* EnumCE * EC_Find(IDirP dirid)
*
* Given a dirid return the cached Enum entry or NILECE.
*
*/
private EnumCE *
EC_Find(dirid)
IDirP dirid;
{
int cidx = dirid->eceidx; /* cache index */
if (cidx == NOECIDX) /* check dir for cache entry */
return(NILECE); /* no cache entry */
EnumCache[cidx]->ece_lru = EC_Clock++; /* this is a reference */
return(EnumCache[cidx]); /* return the cache */
}
/*
* EnumCE * EC_Fetch(IDirP dirid)
*
* Get the EnumCE entry for this dirid. If the entry is in the
* cache then validate it by calling EC_Valid. If not valid
* (changed) then reload the information. If the directory info
* is not in the cache then recycle the min cache entry and load
* a new entry.
*
* Returns NILECE on failure, ece on success.
*
*/
private EnumCE *
EC_Fetch(dirid)
IDirP dirid;
{
EnumCE *ec;
struct stat stb;
if (DBENU)
printf("EC_Fetch: request for %s\n",pathstr(dirid));
ec = EC_Find(dirid); /* see if entry is cached */
if (ec != NILECE && ec->ece_lock) /* found and locked? */
return(ec); /* then being enumerated, return */
if (stat(pathstr(dirid),&stb) != 0) { /* else do a stat for checks */
Idrdirid(Ipdirid(dirid),dirid); /* unlink from directory tree */
return(NILECE); /* nothing there... */
}
if (ec != NILECE) { /* find anything? */
if (EC_Valid(ec,&stb)) /* yes... do validity check */
return(ec); /* seems ok, return it */
} else
ec = EC_Min(); /* else get a current min */
EC_Free(ec); /* free entry or min */
return(EC_Load(dirid,ec,&stb)); /* load dir and return */
}
/*
* EnumCE *EC_Load(IDirP dirid, EnumCE *ec, struct stat *stb)
*
* Read the directory dirid into ec, filling in information from
* the stat structure stb.
*
* Return ec on success, or NILECE if failure.
*
*/
private EnumCE *
EC_Load(dirid,ec,stb)
IDirP dirid;
EnumCE *ec;
struct stat *stb;
{
char *path = pathstr(dirid);
if (DBENU)
printf("EC_Load: adding %s\n",path);
ec->ece_cnt = scandir(path,&ec->ece_nlst,iselect,0);
if (ec->ece_cnt < 0) {
if (DBENU)
printf("EC_Load: scandir failed for %s\n",path);
return(NILECE);
}
ec->ece_ctime = stb->st_ctime; /* copy last modify time */
ec->ece_mmode = stb->st_mode; /* copy the last mode */
ec->ece_dirid = dirid; /* copy directory id */
ec->ece_mcnt = dirid->modified; /* copy modify count */
ec->ece_lru = EC_Clock++; /* set LRU from clock */
dirid->eceidx = ec->ece_idx; /* add new entry */
return(ec); /* and return table */
}
/*
* char * OSEnumGet(dirid,idx)
*
* Fetch the idx'th file/dir name from an enumerated directory.
* Index starts at 1.
*
* You must have first called OSEnumIni() to initialize and
* discover the maximun count of entries in the directory.
*
*/
char *
OSEnumGet(dirid,idx)
IDirP dirid;
int idx; /* ranges from 1..count */
{
EnumCE *ec;
ec = EC_Find(dirid); /* find enum entry given dirid */
if (ec == NILECE) { /* was locked could not be purged */
log("OSEnumGet: bad enum!\n");
return("");
}
if (idx > ec->ece_cnt) { /* check for bad idx */
log("OSEnumGet: Bad idx!\n");
return("");
}
if (!ec->ece_lock) /* check for bad lock */
log("OSEnumGet: Handle not locked!\n");
if (DBENU)
printf("OSEnumGet: %d:%s\n",idx,ec->ece_nlst[idx-1]->d_name);
return(ec->ece_nlst[idx-1]->d_name);
}
/*
* int OSEnumInit(IDirP idir)
*
* Call OSEnumInit to initialize enumeration information. This
* procedure must be called before OSEnumGet which returns the
* nth entry for a directory.
*
* OSEnumDone must be called when finished to release enumeration
* information for a directory.
*
* Returns the count of entries in the directory or a negative error
* code.
*
*/
int
OSEnumInit(idir)
IDirP idir;
{
EnumCE *ec;
if (DBENU)
printf("OSEnumInit: %s\n",pathstr(idir));
OSValFICacheForEnum(idir); /* make sure fi cache for directory is valid */
ec = EC_Fetch(idir); /* get directory info */
if (ec == NILECE) /* access problem? */
return(aeAccessDenied); /* yes... */
if (ec->ece_lock == TRUE)
log("OSEnumInit: directory already locked!\n");
ec->ece_lock = TRUE; /* entry is locked, no purge */
return(ec->ece_cnt); /* return count */
}
/*
* void OSEnumDone(dirid)
*
* Call this routine to say that enumeration is no longer active for
* a directory.
*
* OSEnumDone unlocks the directory entry and allows it to be removed
* from the cache.
*
*/
void
OSEnumDone(dirid)
IDirP dirid;
{
EnumCE *ec;
ec = EC_Find(dirid); /* get cached entry */
if (ec == NILECE) /* should not happen */
log("OSEnumDone: no cache for dirid\n");
else
ec->ece_lock = FALSE; /* unlock */
}
/*
* int OSEnumCount(dirid)
*
* Return the count of entries in a directory.
*
*/
int OSEnumCount(dirid)
IDirP dirid;
{
EnumCE *ec;
ec = EC_Fetch(dirid); /* get directory info */
if (ec == NILECE) /* access problem? */
return(aeAccessDenied); /* yes... */
if (DBENU)
printf("OSEnumCount: %s = %d\n",pathstr(ec->ece_dirid),ec->ece_cnt);
return(ec->ece_cnt); /* return the count */
}
OSfname(r,idir,fn,typ)
IDirP idir;
register char *fn,*r;
register int typ;
{
register char *p;
for (p = pathstr(idir); *p != '\0';) /* copy the directory */
*r++ = *p++;
if (typ == F_RSRC || typ == F_FNDR) /* append directory names */
for (p = ((typ == F_RSRC) ? RFDIR : FIDIR); *p != '\0'; )
*r++ = *p++;
if (*fn != '\0') { /* add slash */
*r++ = '/'; /* if not null file */
while (*fn != '\0')
*r++ = *fn++;
}
*r = '\0';
}
toResFork(str, fn)
register char *str;
char *fn;
{
register char *fp, *tp;
if(*fn) { /* a real file */
if(fp = rindex(str, '/')) /* skip over last slash */
fp++;
else
fp = str;
str = fp;
fp = str + strlen(str);
tp = fp + DIRRFLEN;
*tp = 0;
while(fp > str) /* move filename, leaving space for .resource */
*--tp = *--fp;
fp = DIRRF;
while(*fp)
*str++ = *fp++;
} else /* a directory */
strcat(str,RFDIR); /* just append .resource */
}
toFinderInfo(str, fn)
register char *str;
char *fn;
{
register char *fp, *tp;
if(*fn) { /* a real file */
if(fp = rindex(str,'/')) /* skip over last slash */
fp++;
else
fp = str;
str = fp;
fp = str + strlen(str);
tp = fp + DIRFILEN;
*tp = 0;
while(fp > str) /* move filename, leaving space for .finderinfo */
*--tp = *--fp;
fp = DIRFI;
while(*fp)
*str++ = *fp++;
} else /* a directory */
strcat(str,FIDIR); /* just append .finderinfo */
}
#ifdef NOCASEMATCH
#include <sys/file.h>
#include <ctype.h>
/*
* searchDirectory(dir, name)
* Do a case insensitive search for name in dir, and write the true name
* of the file in name.
*/
private
searchDirectory(dir, name)
char *dir, *name;
{
register char *fp, *tp;
register DIR *dp;
register struct direct *d;
register int len;
char lname[BUFSIZ], dname[BUFSIZ];
if((dp = opendir(dir)) == NULL)
return(0);
len = 0;
for(fp = name, tp = lname ; *fp ; fp++) {
*tp++ = isupper(*fp) ? tolower(*fp) : *fp;
len++;
}
*tp = 0;
while(d = readdir(dp)) {
if(d->d_namlen != len)
continue;
for(fp = d->d_name, tp = dname ; *fp ; fp++)
*tp++ = isupper(*fp) ? tolower(*fp) : *fp;
*tp = 0;
if(strcmp(dname, lname) == 0) {
strcpy(name, d->d_name);
closedir(dp);
return(1);
}
}
closedir(dp);
return(0);
}
/*
* noCaseDir(path)
* Recursively verify the components of path.
*/
private
noCaseDir(path)
register char *path;
{
register char *last;
register int status;
if(access(path, F_OK) >= 0)
return(1);
if(last = rindex(path, '/')) {
if(last == path)
return(searchDirectory("/", last + 1));
else {
*last++ = 0;
status = 0;
if(noCaseDir(path))
status = searchDirectory(path, last);
*--last = '/';
return(status);
}
}
return(searchDirectory(".", path));
}
/*
* noCaseFind(path)
* noCaseFind() calls noCaseDir() and searchDirectory() recursively to
* take path (case insensitive) and converts it to (case sensitive) newpath
* corresponding to the true Unix filename. This is mainly to fix
* HyperCard doing funny things to stack names.
*/
void
noCaseFind(path)
register char *path;
{
register char *last;
if(last = rindex(path, '/')) {
if(last == path)
searchDirectory("/", last + 1);
else {
*last++ = 0;
if(noCaseDir(path))
searchDirectory(path, last);
*--last = '/';
}
} else
searchDirectory(".", path);
}
/*
* noCaseMatch(path)
* noCaseMatch() tests path first and will call noCaseFind() is path
* doesn't exist.
*/
void
noCaseMatch(path)
register char *path;
{
if(access(path, F_OK) >= 0)
return;
noCaseFind(path);
}
#endif NOCASEMATCH
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.