/* * $Author: djh $ $Date: 1996/06/18 10:49:40 $ * $Header: /mac/src/cap60/applications/aufs/RCS/afposenum.c,v 2.15 1996/06/18 10:49:40 djh Rel djh $ * $Revision: 2.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 #include #ifndef _TYPES /* assume included by param.h */ # include #endif /* _TYPES */ #include #include #include #include #ifdef USESTRINGDOTH #include #else USESTRINGDOTH #include #endif USESTRINGDOTH #ifdef SHORT_NAMES #include #endif SHORT_NAMES #ifdef NOCASEMATCH #include #include #endif NOCASEMATCH #ifdef USEDIRENT # include #else /* USEDIRENT */ # ifdef xenix5 # include # else xenix5 # include # endif xenix5 #endif /* USEDIRENT */ #ifdef SOLARIS # include #endif /* SOLARIS */ #ifdef linux # include #endif /* linux */ #ifdef DISTRIB_PASSWDS #include #endif /* DISTRIB_PASSWDS */ #include "afps.h" #include "afpdt.h" #include "afpgc.h" #ifdef SHORT_NAMES typedef struct { char s_name[MAXSFLEN+1]; }s_entry; 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 */ #ifdef USEDIRENT struct dirent **ece_nlst; /* direct info */ #else USEDIRENT struct direct **ece_nlst; /* direct info */ #endif USEDIRENT s_entry * s_namearray; 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; #else SHORT_NAMES 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 */ #ifdef USEDIRENT struct dirent **ece_nlst; /* direct info */ #else USEDIRENT struct direct **ece_nlst; /* direct info */ #endif USEDIRENT 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; #endif SHORT_NAMES #define NILECE ((EnumCE *) 0) private EnumCE *EnumCache[NECSIZE]; private int EC_Clock; /* lru clock */ #ifdef USEDIRENT #define NILNLST ((struct dirent **) 0) #else USEDIRENT #define NILNLST ((struct direct **) 0) #endif USEDIRENT private EnumCE *EC_Min(),*EC_Find(),*EC_Fetch(),*EC_Load(); private boolean EC_Valid(); private void EC_Free(); private iselect(); #ifdef SHORT_NAMES private name_toupper(), convert(),add_ast(); private int mysort(); #endif SHORT_NAMES #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) #ifdef USEDIRENT struct dirent *d; #else USEDIRENT struct direct *d; #endif USEDIRENT { if (d == NULL) return(FALSE); if (d->d_name == NULL) return(FALSE); 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_name[1] == '\0') /* check for dot */ return(FALSE); if (d->d_name[1] == '.' && /* check for dot dot */ d->d_name[2] == '\0') 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); #ifdef DISTRIB_PASSWDS if (strcmp(d->d_name,AFP_DISTPW_USER) == 0) /* local password file */ return(FALSE); #endif /* DISTRIB_PASSWDS */ 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 */ logit(0,"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 */ #ifndef STAT_CACHE if (stat(pathstr(dirid),&stb) != 0) { /* else do a stat for checks */ #else STAT_CACHE if(OSstat(pathstr(dirid),&stb)!= 0) { /* else do a stat for checks */ #endif STAT_CACHE 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 */ } #ifdef SHORT_NAMES /* * table to map Mac character set represented with :aa into something * "approximately similar" for MSDOS, any bad characters map to '#' * (valid character list from "MSDOS User's Guide"). * * this is horrible!, but the results look a little nicer on the PC * * Modified 91/12/14 by Paul Buddington to improve translation based * on MSDOS 5.0 User's Guide * */ char mapMacChar[] = { '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '-', '!', '#', '#', '$', '%', '&', '\'','(', ')', '#', '#', '#', '-', '#', '#', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '#', '#', '#', '#', '#', '#', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '#', '#', '#', '^', '_', '`', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '{', '#', '}', '~', '#', 'A', 'A', 'C', 'E', 'N', 'O', 'U', 'A', 'A', 'A', 'A', 'A', 'A', 'C', 'E', 'E', 'E', 'E', 'I', 'I', 'I', 'I', 'N', 'O', 'O', 'O', 'O', 'O', 'U', 'U', 'U', 'U', '#', '#', 'C', '#', '#', '#', '#', 'B', 'R', 'C', 'T', '#', '#', '#', 'A', 'O', '#', '#', '#', '#', '#', 'U', '#', '#', '#', '#', '#', 'A', '#', '#', 'A', 'O', '#', '#', '#', '#', 'F', '#', '#', '#', '#', '#', '#', 'A', 'A', 'O', 'O', 'O', '#', '#', '#', '#', '#', '#', '#', '#', 'Y', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#' }; /* * Map a long name into a short, uppercase DOS compatible name. * Nothing specifies exactly how to do this, so try and make it * resemble the behaviour of a Mac AppleShare server. */ private name_toupper(nlen,name,s_name) int nlen; char *name, *s_name; { int c; int period = 0; int altered = 0; int i=0,j=0,k=0; private byte hex2nibble(); char sname[MAXSFLEN+4]; /* slop */ if (DBENU) printf("nlen %d, MAXSFLEN %d name %s \n",nlen,MAXSFLEN,name); while (name[i] != '\0' && i < nlen && j < MAXSFLEN && period < 5) { /* if the name starts with a . ignore for now, mark altered */ if ((i == 0) && (name[i] == '.')) { altered++; i++; /* when you hit the first period, save it and count it */ } else if ((period == 0) && (name[i] == '.')) { sname[j++] = '.'; period++; i++; /* any weird characters, just say no !!!! */ /* if we hit another period, skip over it */ } else if ((name[i] == '*') || (name[i] == '+') || (name[i] == '|') || (name[i] == '?') || (name[i] == '<') || (name[i] == '>') || (name[i] == '[') || (name[i] == ']') || (name[i] == '"') || (name[i] == '=') || (name[i] == '`') || (name[i] == '.') || (name[i] == '/') || (name[i] == '\\')|| (name[i] == ';') || (name[i] == ',')) { altered++; i++; /* if we see a space, ignore it, but don't mark as altered */ } else if (name[i] == ' ') { i++; /* check for aufs :aa special chars, map down into sim. ascii char */ } else if (name[i] == ':' && i < (nlen-2)) { c = hex2nibble(name[++i]); c = c << 4; c |= hex2nibble(name[++i]); if ((sname[j] = mapMacChar[c & 0xff]) != '#') j++; altered++; i++; /* otherwise, just convert to upper */ } else { if (isalpha(name[i]) && !(isupper(name[i]))) sname[j++] = toupper(name[i]); else sname[j++] = name[i]; i++; } if (period) period++; /* keep counting to get 3 more chars for DOS suffix */ } sname[j] = '\0'; /* more characters to go ? */ if (name[i] != '\0') altered++; j = k = 0; /* copy to s_name, mark start of name with ! if altered */ while(sname[j] != '\0' && j < MAXSFLEN && k < MAXSFLEN) { if (altered && k == 0) s_name[k++] = '!'; if (!period && k == 8) s_name[k++] = '.'; s_name[k++] = sname[j++]; } s_name[k] = '\0'; } private byte hex2nibble(a) char a; { if (a >= '0' && a <= '9') return(a - '0'); if (a >= 'a' && a <= 'f') return(a - 'a' + 10); if (a >= 'A' && a <= 'F') return(a - 'A' + 10); return(0); } private add_ast (ec,pos) EnumCE *ec; int pos; { int i = 1; char c,c1; c = ec->s_namearray[pos].s_name[0]; ec->s_namearray[pos].s_name[0] = '*'; while ((c != '\0') && (is_namearray[pos].s_name[i] = '.'; c1 = ec->s_namearray[pos].s_name[i+1]; ec->s_namearray[pos].s_name[i+1] = c; i+=2; } else { c1 = ec->s_namearray[pos].s_name[i]; ec->s_namearray[pos].s_name[i] = c; i++; } c = c1; } ec->s_namearray[pos].s_name[i] = '\0'; } private convert(ec) EnumCE *ec; { int ast,i; ec->s_namearray = (s_entry*)malloc (ec->ece_cnt*sizeof(s_entry)); ast = FALSE; for (i = 0; iece_cnt; i++) { #ifdef USEDIRENT name_toupper(strlen(ec->ece_nlst[i]->d_name),ec->ece_nlst[i]->d_name, #else /* USEDIRENT */ name_toupper(ec->ece_nlst[i]->d_namlen, ec->ece_nlst[i]->d_name, #endif /* USEDIRENT */ ec->s_namearray[i].s_name); if (i>0) { if ((strcmp(ec->s_namearray[i].s_name, ec->s_namearray[i-1].s_name)) == 0){ add_ast(ec,i-1); ast = TRUE; } else if (ast) { add_ast(ec,i-1); ast = FALSE; } } } if (ast) add_ast(ec,(ec->ece_cnt)-1); } private int mysort(x,y) #ifdef USEDIRENT struct dirent **x,**y; #else USEDIRENT struct direct **x,**y; #endif USEDIRENT { char tempx[MAXNAMLEN],tempy[MAXNAMLEN]; int i = 0; #ifdef USEDIRENT while (i < strlen((*x)->d_name)) { #else /* USEDIRENT */ while (i < (*x)->d_namlen) { #endif /* USEDIRENT */ tempx[i] = toupper((*x)->d_name[i]); i++; } tempx[i] = '\0'; i = 0; #ifdef USEDIRENT while (i < strlen((*y)->d_name)) { #else /* USEDIRENT */ while (i < (*y)->d_namlen) { #endif /* USEDIRENT */ tempy[i] = toupper((*y)->d_name[i]); i++; } tempy[i] = '\0'; return(strcmp(tempx,tempy)); } #endif SHORT_NAMES /* * 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); #ifdef STAT_CACHE extern char *cwd_path(); #endif STAT_CACHE int i; if (DBENU) printf("EC_Load: adding %s\n",path); #ifdef STAT_CACHE path = cwd_path(path); #endif STAT_CACHE #ifdef SHORT_NAMES ec->ece_cnt = scandir(path,&ec->ece_nlst,iselect,mysort); #else SHORT_NAMES ec->ece_cnt = scandir(path,&ec->ece_nlst,iselect,0); #endif SHORT_NAMES if (ec->ece_cnt < 0) { if (DBENU) printf("EC_Load: scandir failed for %s\n",path); return(NILECE); } #ifdef SHORT_NAMES convert(ec); #endif SHORT_NAMES 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 */ logit(0,"OSEnumGet: bad enum!\n"); return(""); } if (idx > ec->ece_cnt) { /* check for bad idx */ logit(0,"OSEnumGet: Bad idx!\n"); return(""); } if (!ec->ece_lock) /* check for bad lock */ logit(0,"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)); #ifdef STAT_CACHE OScd(pathstr(idir)); #endif STAT_CACHE 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) logit(0,"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 */ logit(0,"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 /* * 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; #ifdef USEDIRENT register struct dirent *d; #else USEDIRENT register struct direct *d; #endif USEDIRENT 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)) { #ifdef USEDIRENT if (strlen(d->d_name) != len) #else /* USEDIRENT */ if (d->d_namlen != len) #endif /* USEDIRENT */ 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 #ifdef SHORT_NAMES private int searchn (name,ec,type) char *name; EnumCE *ec; { int i = 0; if (ec == NILECE) /* hmmmm ... */ return(-1); if (type != 1) while ((iece_cnt) && (strcmp (name, ec->ece_nlst[i]->d_name) != 0)) { i++; } else while ((iece_cnt) && (strcmp (name, ec->s_namearray[i].s_name) != 0)) { i++; } if (i == ec->ece_cnt) return(-1); else return(i); } char* Get_name(dirid,name,type,outname) IDirP dirid; char *name,*outname; int type; { EnumCE *ec; int i, idx; ec = EC_Fetch(dirid); if (ec == NILECE) idx = -1; else idx = searchn(name,ec,type); if (idx == -1) { if (strcmp (name, dirid->name) == 0) /*then it is a directory*/ printf("wasn't found and it is a directory\n"); if (DBENU) printf("name wasn't found!!!!!Index == -1\n"); sprintf(outname,"%s",name); } else if (type != 1) /*return longname*/ sprintf(outname,"%s",ec->s_namearray[idx].s_name); else /* return short name */ sprintf(outname,"%s",ec->ece_nlst[idx]->d_name); } #endif SHORT_NAMES