ftp.nice.ch/pub/next/unix/network/system/cap.5.0.s.tar.gz#/cap_5.0/applications/aufs/afposenum.c

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.