This is afposfi.c in view mode; [Download] [Up]
/* * $Author: cck $ $Date: 88/03/30 11:52:01 $ * $Header: afposfi.c,v 1.29 88/03/30 11:52:01 cck Rel $ * $Revision: 1.29 $ */ /* * afposfi.c - Appletalk Filing Protocol OS FNDR File Interface. * * 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. * Jan 1988 CCKim New finderinfo format * */ #include <stdio.h> #include <errno.h> extern int errno; #include <sys/param.h> #ifndef _TYPES # include <sys/types.h> #endif #include <sys/file.h> #include <sys/stat.h> #include <netinet/in.h> /* for htons, htonl */ #include <netat/appletalk.h> #include <netat/compat.h> #include <netat/afp.h> #include "afps.h" #include "afpgc.h" #ifdef NEEDFCNTLDOTH # include <fcntl.h> #endif #include "afpudb.h" typedef struct FCacheEnt { struct FCacheEnt *next; /* link for free queue */ IDirP fe_pdir; /* directory */ int fe_okay; /* last internal modify count */ char *fe_fnam; /* file */ /* should we use ctime instead perhaps? */ time_t fe_mtime; /* last modify time: file system */ time_t fe_vtime; /* last time validated */ FileInfo fe_fi; /* file info */ } FCacheEnt; export GCHandle *fich; /* handle on cache */ private FCacheEnt *fce, *lfce; /* recycle purge-load */ private FCacheEnt *getfe; /* last os_getfi */ private int fc_valid(); private int fc_compare(); private char *fc_load(); private void WriteFA(); private void fc_purge(); private void fc_flush(); private void fc_flush_start(); private void fc_flush_end(); private FileInfo *os_getfi(); private fc_readent(); #define FICacheSize 128 /* Each cache entry has a lifetime that it goes through before it must */ /* be revalidated before reuse: this prevents cache entries from getting */ /* "stale". */ /* The revalidation consists of seeing if the disk copy has changed */ #define FI_VALID_TIME (60*5) /* 5 minutes */ InitOSFI() { fich = GCNew(FICacheSize,fc_valid,fc_compare,fc_load,fc_purge,fc_flush); lfce = fce = (FCacheEnt *) 0; getfe = (FCacheEnt *) 0; } /* * Our flush doesn't flush modified entries since our cache is * write through, but attempts instead to check validity of items in * our cache * * can bracket with fc_flush_start and fc_flush_end to reduce # of * stats. This depends on the .finderinfo directory modify time * getting changed when a finderinfo entry is modified. WriteFA * guarantees this as best it can (can you say hack?) * * */ private time_t fcf_val_time = 0; /* validate time */ private IDirP fcf_val_dir = NILDIR; /* directory val time is for */ private void fc_flush_start(pdir) IDirP pdir; { char path[MAXPATHLEN]; struct stat stb; OSfname(path, pdir, "", F_FNDR); /* get directory */ if (stat(path, &stb) < 0) { #ifdef NOCASEMATCH noCaseFind(path); if (stat(path, &stb) < 0) { fcf_val_dir = NILDIR; fcf_val_time = 0; return; /* nothing else we can do */ } #else NOCASEMATCH fcf_val_dir = NILDIR; fcf_val_time = 0; return; /* nothing else we can do */ #endif NOCASEMATCH } fcf_val_dir = pdir; fcf_val_time = stb.st_mtime; /* remember */ } private void fc_flush_end() { fcf_val_time = 0; /* mark none */ fcf_val_dir = NILDIR; } private void fc_flush(fe, pdir) FCacheEnt *fe; IDirP pdir; { char path[MAXPATHLEN]; struct stat stb; /* if passed directory isn't nildir (flush all), then the file */ /* will only be check if the particular item has the same directory */ if (pdir != NILDIR && (fe->fe_pdir != pdir)) return; if ((fe->fe_pdir->flags & DID_FINDERINFO)) { /* always okay */ OSfname(path, fe->fe_pdir, fe->fe_fnam, F_FNDR); /* if we have a .finderinfo directory update time */ /* and it is more recent than cache entry, then check the */ /* cache entry */ /* also add a check against vtime. Makes it much more useful */ /* since it is more than likely that fcf_val_time is later */ /* than the mtime for the majority of the files */ if (fcf_val_dir == fe->fe_pdir && (fcf_val_time > fe->fe_mtime) && (fcf_val_time > fe->fe_vtime)) { #ifdef NOCASEMATCH if (stat(path, &stb) < 0) { noCaseFind(path); if (stat(path, &stb) < 0) return; /* nothing else we can do */ } #else NOCASEMATCH if (stat(path, &stb) < 0) return; /* nothing else we can do */ #endif NOCASEMATCH if (stb.st_mtime != fe->fe_mtime) /* reload entry */ fe->fe_okay = FALSE; /* make entry as bad */ } } time(&fe->fe_vtime); /* mark last validate time */ } private fc_valid(fe) FCacheEnt *fe; { char path[MAXPATHLEN]; struct stat stb; time_t mtime; if (!fe->fe_okay) /* if not okay, don't */ return(fe->fe_okay); /* bother with checks */ time(&mtime); if (fe->fe_vtime + FI_VALID_TIME < mtime) { fe->fe_vtime = mtime; /* mark as new validate time */ if ((fe->fe_pdir->flags & DID_FINDERINFO) == 0) /* always okay */ return(fe->fe_okay); OSfname(path, fe->fe_pdir, fe->fe_fnam, F_FNDR); #ifdef NOCASEMATCH if (stat(path, &stb) < 0) { noCaseFind(path); if (stat(path, &stb) < 0) return(fe->fe_okay); /* nothing else we can do */ } #else NOCASEMATCH if (stat(path, &stb) < 0) return(fe->fe_okay); /* nothing else we can do */ #endif NOCASEMATCH if (stb.st_mtime != fe->fe_mtime) /* reload entry */ return(FALSE); /* bad entry */ } return(fe->fe_okay); } private void fc_purge(fe) FCacheEnt *fe; { if (DBOSI) printf("fc_purge: %s\n",fe->fe_fnam); if (fe == getfe) /* purging last get? */ getfe = (FCacheEnt *) 0; /* yes... then zero */ free(fe->fe_fnam); /* always free the name */ fe->fe_fnam = (char *) 0; /* and zero... */ fe->next = NULL; /* trash it here since want in both */ if (fce == (FCacheEnt *) 0) /* check for recycled entry */ lfce = fce = fe; /* if none then save */ else { lfce->next = fe; /* put at end of free list */ lfce = fe; /* remember the end */ #ifdef notdef free(fe); /* and the struct itself */ #endif } } private fc_compare(fe,key) FCacheEnt *fe,*key; { if (fe->fe_pdir != key->fe_pdir) return(FALSE); return(strcmp(fe->fe_fnam,key->fe_fnam) == 0); } private char * fc_load(key) FCacheEnt *key; { FCacheEnt *fe; if (DBOSI) printf("fc_load: %s\n",key->fe_fnam); if (fce != (FCacheEnt *) 0) { /* recycled fc avail? */ fe = fce; /* yes... use that */ fce = fce->next; } else /* else allocate */ fe = (FCacheEnt *) malloc(sizeof(FCacheEnt)); fe->fe_pdir = key->fe_pdir; fe->fe_fnam = (char *) malloc(strlen(key->fe_fnam)+1); fe->fe_okay = TRUE; fe->fe_mtime = 0; time(&fe->fe_vtime); /* validate time stamp */ strcpy(fe->fe_fnam,key->fe_fnam); fc_readent(fe); return((char *) fe); } private fc_readent(fe) FCacheEnt *fe; { struct stat stb; char path[MAXPATHLEN]; int fd, ft, len, err; FileInfo *fi = &fe->fe_fi; FinderInfo *fndr; extern struct ufinderdb uf[]; bzero((char *) fi,sizeof(FileInfo)); /* make sure clear before */ if (fe->fe_pdir->flags & DID_FINDERINFO) { OSfname(path,fe->fe_pdir,fe->fe_fnam,F_FNDR); if (DBOSI) printf("fc_readent: reading %s\n",path); fd = open(path,O_RDONLY); #ifdef NOCASEMATCH if(fd < 0) { noCaseFind(path); fd = open(path,O_RDONLY); } #endif NOCASEMATCH if (fd >= 0) { OSLockFileforRead(fd); err = fstat(fd, &stb); len = read(fd,(char *) fi,sizeof(FileInfo)); OSUnlockFile(fd); if (len < FI_BASELENGTH) { close(fd); if (len == 0) /* length zero means creat'd */ goto dummy; if (DBOSI) printf("fc_readent: finderinfo too short\n"); goto nofileinfo; } if (fi->fi_magic1 != FI_MAGIC1) { OldFileInfo *ofi = (OldFileInfo *)fi; bcopy(ofi->fi_comnt, fi->fi_comnt, fi->fi_magic1); fi->fi_comln = fi->fi_magic1; if (ofi->fi_attr & FI_ATTR_SETCLEAR) fi->fi_attr = ofi->fi_attr & (FI_ATTR_READONLY|FI_ATTR_MUSER|FI_ATTR_INVISIBLE); else fi->fi_attr = 0; fi->fi_magic1 = FI_MAGIC1; fi->fi_magic = FI_MAGIC; fi->fi_version = FI_VERSION; fi->fi_bitmap = FI_BM_MACINTOSHFILENAME; ItoEName(fe->fe_fnam, fi->fi_macfilename); /* make sure we update it */ WriteFA(fe->fe_pdir, fe->fe_fnam, fi); } else { if (fi->fi_magic != FI_MAGIC || fi->fi_version != FI_VERSION) { if (DBOSI) printf("fc_readent: fileinfo check fail\n"); close(fd); goto nofileinfo; } fi->fi_attr = ntohs(fi->fi_attr); if (err == 0) /* stat okay */ fe->fe_mtime = stb.st_mtime; /* remember mtime */ } if (close(fd) != 0) printf("fc_readent: close error"); return(noErr); } /* Open failed for .finderinfo file. Use defaults finfo or zero if dir */ if (DBOSI) printf("fc_readent: Open failed for %s\n",path); } nofileinfo: /* convert name to internal name */ OSfname(path,fe->fe_pdir,fe->fe_fnam,F_DATA); /* create plain name */ #ifdef NOCASEMATCH if (stat(path,&stb) != 0) { /* check if it exists */ noCaseFind(path); if (stat(path,&stb) != 0) /* check if it exists */ return(aeObjectNotFound); /* no... */ } #else NOCASEMATCH if (stat(path,&stb) != 0) /* check if it exists */ return(aeObjectNotFound); /* no... */ #endif NOCASEMATCH if (S_ISDIR(stb.st_mode)) { fi->fi_comln = 0; } else { ft = os_getunixtype(path, &stb); fndr = (FinderInfo *)fi->fi_fndr; /* get pointer to finder info */ bcopy(uf[ft].ufd_ftype, fndr->file.fdType, sizeof(fndr->file.fdType)); bcopy(DEFFCREATOR,fndr->file.fdCreator, sizeof(fndr->file.fdCreator)); bcopy(uf[ft].ufd_comment, fi->fi_comnt, uf[ft].ufd_commentlen); fi->fi_comln = uf[ft].ufd_commentlen; } fi->fi_attr = DEFATTR; /* set default attributes */ dummy: fi->fi_magic1 = FI_MAGIC1; fi->fi_version = FI_VERSION; fi->fi_magic = 0; /* mark as "default" entry */ fi->fi_bitmap = FI_BM_MACINTOSHFILENAME; ItoEName(fe->fe_fnam, fi->fi_macfilename); return(noErr); } private void WriteFA(ipdir,fn,fi) IDirP ipdir; char *fn; FileInfo *fi; { char path[MAXPATHLEN]; int fd; int needu = 0; if ((ipdir->flags & DID_FINDERINFO) == 0) { if (DBOSI) printf("WriteFA skipped, no finderinfo directory\n"); return; } OSfname(path,ipdir,fn,F_FNDR); /* convert to internal name */ if (DBOSI) printf("WriteFA: writing %s\n",path); needu++; fd = open(path,O_WRONLY); #ifdef NOCASEMATCH if(fd < 0) { noCaseFind(path); fd = open(path,O_WRONLY); } #endif NOCASEMATCH if (fd < 0) { /* open for write */ if (errno != ENOENT) { printf("WriteFA: error openning %s errno=%d\n",path,errno); return; } if ((fd = open(path,O_WRONLY|O_CREAT,0666)) < 0) { if (DBOSI) printf("fc_flush: create failed for %s %d\n",path,errno); return; } if (DBOSI) printf("fc_flush: created %s\n",path); } else needu++; fi->fi_attr = htons(fi->fi_attr); /* swab!!!@ */ fi->fi_magic = FI_MAGIC; OSLockFileforWrite(fd); (void)write(fd,(char *) fi,sizeof(FileInfo)); /* write stuff */ OSUnlockFile(fd); if (close(fd) != 0) printf("WriteFA: close error"); /* horrible hack, but can't use utimes, because we must be owner then */ if (needu) { /* update directory modified time */ OSfname(path,ipdir,FIDIRFN,F_FNDR); /* pick bad name */ if ((fd = open(path, O_WRONLY|O_CREAT,0666)) < 0) return; close(fd); unlink(path); } /* EModified(fe->fe_pdir); /* and mark directory as modified */ } private FileInfo * os_getfi(pdir,fn) IDirP pdir; char *fn; { FCacheEnt key; key.fe_pdir = pdir; key.fe_fnam = fn; /* do the "quick" check first */ if (getfe == 0 || !fc_compare(getfe,&key)) { /* nope, either find in cache or load from disk */ getfe = (FCacheEnt *)GCLocate(fich,(char *)&key); } return(&getfe->fe_fi); /* and return the FileInfo */ } FModified(pdir, fn) IDirP pdir; char *fn; { FCacheEnt key; int idx; key.fe_pdir = pdir; key.fe_fnam = fn; EModified(pdir); /* make parent directory as modified */ if (getfe == 0 || !fc_compare(getfe,&key)) { /* no kept entry */ if (!GCScan(fich, &key, &idx)) /* not in cache, already flushed */ return; getfe = (FCacheEnt *)GCidx2ent(fich, idx); } if (DBOSI) printf("Invalidating file cache entry %s/%s\n",pathstr(pdir),fn); getfe->fe_okay = FALSE; /* invalidate entry */ } /* * OSValidateFICacheforEnum(directory) * * validate a file cache for enumerate * * make fc_flush only stat if .finderinfo directory modification time * has changed -- writefa guarantees us that * */ OSValFICacheForEnum(pdir) IDirP pdir; { fc_flush_start(pdir); GCFlush(fich, pdir); /* make sure valid */ fc_flush_end(); } /* * OSSetFA(IDirP pdir, char *fn, word bm, FileDirParm *fdp) * * Set finder and attr for a file specified by ancestor directory * (pdir) and file name (fn). The bitmap in bm specifies which * FP_FINFO (DP_FINFO) or FP_ATTR (DP_ATTR) are to be set. * */ OSSetFA(pdir,fn,bm,fdp) IDirP pdir; char *fn; word bm; FileDirParm *fdp; { FileInfo *fi; word attr; fi = os_getfi(pdir,fn); if (bm & FP_ATTR) { attr = fdp->fdp_attr; /* limit to these: allow readonly and MUSER even if directory */ attr &= (FI_ATTR_READONLY|FI_ATTR_MUSER|FI_ATTR_INVISIBLE); if (fdp->fdp_attr & FI_ATTR_SETCLEAR) fi->fi_attr |= attr; else fi->fi_attr &= ~attr; } if (bm & FP_FINFO) bcopy(fdp->fdp_finfo,fi->fi_fndr,FINFOLEN); if (bm & (FP_ATTR|FP_FINFO)) WriteFA(pdir,fn,fi); return(noErr); } OSGetAttr(pdir,fn,attr) IDirP pdir; char *fn; word *attr; { FileInfo *fi; fi = os_getfi(pdir,fn); *attr = fi->fi_attr; return(noErr); } OSGetFNDR(pdir,fn,finfo) IDirP pdir; char *fn; byte *finfo; { FileInfo *fi; fi = os_getfi(pdir,fn); bcopy(fi->fi_fndr,finfo,FINFOLEN); return(noErr); } OSSetComment(pdir,fn,cs,cl) IDirP pdir; char *fn; byte *cs; byte cl; { FileInfo *fi; fi = os_getfi(pdir,fn); bcopy(cs,fi->fi_comnt,cl); fi->fi_comln = cl; WriteFA(pdir,fn,fi); return(noErr); } OSGetComment(pdir,fn,cs,cl) IDirP pdir; char *fn; byte *cs; byte *cl; { FileInfo *fi; fi = os_getfi(pdir,fn); *cl = fi->fi_comln; if (*cl == 0) *cs = 0; bcopy(fi->fi_comnt,cs,*cl); return(noErr); } /* * Establish the mac file name after a os_move * */ OSSetMacFileName(pdir, fn) IDirP pdir; char *fn; { FileInfo *fi; fi = os_getfi(pdir,fn); ItoEName(fn, fi->fi_macfilename); WriteFA(pdir, fn, fi); return(noErr); }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.