mirror of https://github.com/mabam/CAP.git
908 lines
23 KiB
C
908 lines
23 KiB
C
/*
|
|
* $Author: djh $ $Date: 1995/06/12 06:58:18 $
|
|
* $Header: /mac/src/cap60/applications/aufs/RCS/afposfi.c,v 2.7 1995/06/12 06:58:18 djh Rel djh $
|
|
* $Revision: 2.7 $
|
|
*/
|
|
|
|
/*
|
|
* 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
|
|
* December 1990 djh tidy up for AFP 2.0
|
|
*
|
|
*/
|
|
|
|
/* PATCH: PC.aufs/afposfi.c.diffs, djh@munnari.OZ.AU, 15/11/90 */
|
|
/* PATCH: Dan@lth.se/stat.cache.patches, djh@munnari.OZ.AU, 16/11/90 */
|
|
/* PATCH: Moy@Berkeley/afposfi.c.diff, djh@munnari.OZ.AU, 17/11/90 */
|
|
|
|
|
|
#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 */
|
|
long fe_hash; /* hash value of fe_fnam */
|
|
/* 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->fe_hash = 0; /* clear hash */
|
|
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);
|
|
if (fe->fe_hash != key->fe_hash)
|
|
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);
|
|
fe->fe_hash = key->fe_hash;
|
|
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[];
|
|
extern int sessvers;
|
|
word newattr;
|
|
#ifdef USR_FILE_TYPES
|
|
extern struct uft uft[];
|
|
#endif USR_FILE_TYPES
|
|
|
|
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);
|
|
|
|
#ifndef STAT_CACHE
|
|
fd = open(path,O_RDONLY);
|
|
#else STAT_CACHE
|
|
fd = cwd_open(path,O_RDONLY);
|
|
#endif STAT_CACHE
|
|
#ifdef NOCASEMATCH
|
|
if (fd < 0) {
|
|
noCaseFind(path);
|
|
#ifndef STAT_CACHE
|
|
fd = open(path,O_RDONLY);
|
|
#else STAT_CACHE
|
|
fd = cwd_open(path,O_RDONLY);
|
|
#endif STAT_CACHE
|
|
}
|
|
#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;
|
|
newattr = (sessvers >= AFPVersion2DOT0) ? (FPA_RNI|FPA_DEI) : 0;
|
|
if (ofi->fi_attr & FI_ATTR_SETCLEAR)
|
|
fi->fi_attr = ofi->fi_attr &
|
|
(FI_ATTR_READONLY|FI_ATTR_MUSER|FI_ATTR_INVISIBLE|newattr);
|
|
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;
|
|
#ifdef SHORT_NAMES
|
|
ItoEName(fe->fe_fnam, fi->fi_macfilename);
|
|
ItoEName_Short(fe->fe_pdir,fe->fe_fnam,fi->fi_shortfilename);
|
|
#else SHORT_NAMES
|
|
ItoEName(fe->fe_fnam, fi->fi_macfilename);
|
|
#endif SHORT_NAMES
|
|
/* 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
|
|
#ifndef STAT_CACHE
|
|
if (stat(path,&stb) != 0) { /* check if it exists */
|
|
#else STAT_CACHE
|
|
if (OSstat(path,&stb) != 0) { /* check if it exists */
|
|
#endif STAT_CACHE
|
|
noCaseFind(path);
|
|
#endif NOCASEMATCH
|
|
#ifndef STAT_CACHE
|
|
if (stat(path,&stb) != 0) /* check if it exists */
|
|
#else STAT_CACHE
|
|
if (OSstat(path,&stb) != 0) /* check if it exists */
|
|
#endif STAT_CACHE
|
|
return(aeObjectNotFound); /* no... */
|
|
#ifdef NOCASEMATCH
|
|
}
|
|
#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 */
|
|
#ifdef USR_FILE_TYPES
|
|
if (ft >= FNDR_UFT) {
|
|
ft -= FNDR_UFT; /* ft is now the index into the UFT table */
|
|
bcopy(uft[ft].uft_ftype, fndr->file.fdType, sizeof(uft[ft].uft_ftype));
|
|
bcopy(uft[ft].uft_creat, fndr->file.fdCreator, sizeof(uft[ft].uft_creat));
|
|
bcopy(uft[ft].uft_comment, fi->fi_comnt, uft[ft].uft_commentlen);
|
|
fi->fi_comln = uft[ft].uft_commentlen;
|
|
} else {
|
|
#endif USR_FILE_TYPES
|
|
bcopy(uf[ft].ufd_ftype, fndr->file.fdType, sizeof(fndr->file.fdType));
|
|
bcopy(uf[ft].ufd_creat,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;
|
|
#ifdef USR_FILE_TYPES
|
|
}
|
|
#endif USR_FILE_TYPES
|
|
}
|
|
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;
|
|
#ifdef SHORT_NAMES
|
|
ItoEName(fe->fe_fnam, fi->fi_macfilename);
|
|
ItoEName_Short(fe->fe_pdir,fe->fe_fnam, fi->fi_shortfilename);
|
|
#else SHORT_NAMES
|
|
ItoEName(fe->fe_fnam, fi->fi_macfilename);
|
|
#endif SHORT_NAMES
|
|
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 opening %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");
|
|
fi->fi_attr = htons(fi->fi_attr); /* then swab back!!!@ */
|
|
/* 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;
|
|
register long hash;
|
|
register char *p;
|
|
|
|
key.fe_pdir = pdir;
|
|
p = key.fe_fnam = fn;
|
|
|
|
hash = 0;
|
|
while (*p) {
|
|
hash <<= 2;
|
|
hash += *p++;
|
|
}
|
|
key.fe_hash = hash;
|
|
|
|
/* 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;
|
|
register long hash;
|
|
register char *p;
|
|
int idx;
|
|
|
|
key.fe_pdir = pdir;
|
|
p = key.fe_fnam = fn;
|
|
|
|
hash = 0;
|
|
while (*p) {
|
|
hash <<= 2;
|
|
hash += *p++;
|
|
}
|
|
key.fe_hash = hash;
|
|
|
|
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.
|
|
*
|
|
* Update to handle AFP 2.0 as defined by "Inside AppleTalk", 2nd Ed, p13-21
|
|
* djh@munnari.OZ.AU, 06/12/90
|
|
*
|
|
*/
|
|
OSSetFA(pdir,fn,bm,fdp)
|
|
IDirP pdir;
|
|
char *fn;
|
|
word bm;
|
|
FileDirParm *fdp;
|
|
{
|
|
FileInfo *fi;
|
|
word attr,newattr;
|
|
extern int sessvers;
|
|
|
|
fi = os_getfi(pdir,fn);
|
|
if (bm & FP_ATTR) {
|
|
attr = fdp->fdp_attr;
|
|
/* limit: allowed alter some bits only & protocol vers. dependant */
|
|
newattr = (sessvers >= AFPVersion2DOT0) ? (FPA_RNI|FPA_DEI) : 0;
|
|
attr &= (FI_ATTR_READONLY|FI_ATTR_MUSER|FI_ATTR_INVISIBLE|newattr);
|
|
if (sessvers == AFPVersion1DOT1 && (attr & FI_ATTR_READONLY))
|
|
attr |= (FPA_RNI|FPA_DEI);
|
|
if (fdp->fdp_attr & FI_ATTR_SETCLEAR)
|
|
fi->fi_attr |= attr;
|
|
else
|
|
fi->fi_attr &= ~attr;
|
|
}
|
|
|
|
#ifdef USE_MAC_DATES
|
|
if (bm & FP_CDATE) {
|
|
fi->fi_datemagic = FI_MAGIC;
|
|
fi->fi_datevalid |= FI_CDATE;
|
|
bcopy(&fdp->fdp_cdate,fi->fi_ctime,sizeof(fi->fi_ctime));
|
|
}
|
|
if (bm & FP_MDATE) {
|
|
time_t when;
|
|
time(&when);
|
|
fi->fi_datemagic = FI_MAGIC;
|
|
fi->fi_datevalid |= FI_MDATE;
|
|
bcopy(&when,fi->fi_utime,sizeof(fi->fi_utime));
|
|
bcopy(&fdp->fdp_mdate,fi->fi_mtime,sizeof(fi->fi_mtime));
|
|
}
|
|
#endif USE_MAC_DATES
|
|
|
|
if (bm & FP_FINFO) {
|
|
bcopy(fdp->fdp_finfo,fi->fi_fndr,FINFOLEN);
|
|
if (!(bm & FP_PDOS)) /* setting finder info BUT NOT PRODOS */
|
|
mapFNDR2PDOS(fdp); /* derive suitable File and Aux types */
|
|
}
|
|
|
|
if (bm & FP_PDOS)
|
|
if (!(bm & FP_FINFO)) /* setting PRODOS info BUT NOT finder */
|
|
mapPDOS2FNDR(fdp,fi); /* derive suitable fdCreator & fdType */
|
|
|
|
#ifdef USE_MAC_DATES
|
|
if (bm & (FP_ATTR|FP_FINFO|FP_PDOS|FP_CDATE|FP_MDATE))
|
|
#else USE_MAC_DATES
|
|
if (bm & (FP_ATTR|FP_FINFO|FP_PDOS))
|
|
#endif USE_MAC_DATES
|
|
WriteFA(pdir,fn,fi);
|
|
return(noErr);
|
|
}
|
|
|
|
OSGetAttr(pdir,fn,attr)
|
|
IDirP pdir;
|
|
char *fn;
|
|
word *attr;
|
|
{
|
|
FileInfo *fi;
|
|
extern int sessvers;
|
|
|
|
fi = os_getfi(pdir,fn);
|
|
*attr = fi->fi_attr;
|
|
if (sessvers == AFPVersion1DOT1) {
|
|
if (*attr & (FPA_RNI|FPA_DEI))
|
|
*attr |= FI_ATTR_READONLY;
|
|
*attr &= FPA_MASK1; /* give only AFP 1.1 Attributes */
|
|
}
|
|
return(noErr);
|
|
}
|
|
|
|
OSSetAttr(pdir, fn, attr)
|
|
IDirP pdir;
|
|
char *fn;
|
|
word attr;
|
|
{
|
|
FileInfo *fi;
|
|
|
|
fi = os_getfi(pdir, fn);
|
|
fi->fi_attr = attr;
|
|
WriteFA(pdir, fn, fi);
|
|
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);
|
|
}
|
|
|
|
#ifdef USE_MAC_DATES
|
|
OSGetCDate(pdir,fn,cdate)
|
|
IDirP pdir;
|
|
char *fn;
|
|
time_t *cdate;
|
|
{
|
|
FileInfo *fi;
|
|
|
|
fi = os_getfi(pdir,fn);
|
|
if (fi->fi_datemagic != FI_MAGIC || (!(fi->fi_datevalid & FI_CDATE)))
|
|
return(-1);
|
|
bcopy(fi->fi_ctime,cdate,sizeof(fi->fi_ctime));
|
|
return(noErr);
|
|
}
|
|
|
|
OSGetMDate(pdir,fn,mdate,udate)
|
|
IDirP pdir;
|
|
char *fn;
|
|
time_t *mdate;
|
|
time_t *udate;
|
|
{
|
|
FileInfo *fi;
|
|
|
|
fi = os_getfi(pdir,fn);
|
|
if (fi->fi_datemagic != FI_MAGIC || (!(fi->fi_datevalid & FI_MDATE)))
|
|
return(-1);
|
|
bcopy(fi->fi_mtime,mdate,sizeof(fi->fi_mtime));
|
|
bcopy(fi->fi_utime,udate,sizeof(fi->fi_utime));
|
|
return(noErr);
|
|
}
|
|
#endif USE_MAC_DATES
|
|
|
|
/*
|
|
* Establish the mac file name after a os_move
|
|
*
|
|
*/
|
|
OSSetMacFileName(pdir, fn)
|
|
IDirP pdir;
|
|
char *fn;
|
|
{
|
|
FileInfo *fi;
|
|
|
|
fi = os_getfi(pdir,fn);
|
|
#ifdef SHORT_NAMES
|
|
ItoEName(fn, fi->fi_macfilename);
|
|
ItoEName_Short(pdir,fn, fi->fi_shortfilename);
|
|
#else SHORT_NAMES
|
|
ItoEName(fn, fi->fi_macfilename);
|
|
#endif SHORT_NAMES
|
|
WriteFA(pdir, fn, fi);
|
|
return(noErr);
|
|
}
|
|
|
|
/*
|
|
* mapPDOS2FNDR
|
|
*
|
|
* convert ProDOS File Type and Aux Type to Finder Info
|
|
* (even to have to contemplate doing this is disgusting)
|
|
*
|
|
*/
|
|
|
|
#define CTLEN 4
|
|
|
|
mapPDOS2FNDR(fdp,fi)
|
|
FileDirParm *fdp;
|
|
FileInfo *fi;
|
|
{
|
|
FinderInfo *fndr;
|
|
byte prodos_at[4];
|
|
byte prodos_ft[2];
|
|
|
|
if (fdp->fdp_flg == FDP_DIRFLG) /* directory, do nothing! */
|
|
return;
|
|
|
|
bcopy(&fdp->fdp_prodos_aux, prodos_at, sizeof(prodos_at));
|
|
bcopy(&fdp->fdp_prodos_ft, prodos_ft, sizeof(prodos_ft));
|
|
fndr = (FinderInfo *) fi->fi_fndr;
|
|
|
|
switch (prodos_ft[0]) {
|
|
case 0x00:
|
|
bcopy("BINA", fndr->file.fdType, CTLEN);
|
|
break;
|
|
case 0xb3:
|
|
bcopy("PS16", fndr->file.fdType, CTLEN);
|
|
break;
|
|
case 0xff:
|
|
bcopy("PSYS", fndr->file.fdType, CTLEN);
|
|
break;
|
|
case 0x04:
|
|
if (prodos_at[0] == 0x00 && prodos_at[1] == 0x00) {
|
|
bcopy("TEXT", fndr->file.fdType, CTLEN);
|
|
break;
|
|
} /* else fall thro' */
|
|
default:
|
|
/* some fdTypes will be unprintable */
|
|
fndr->file.fdType[0] = 'p';
|
|
fndr->file.fdType[1] = prodos_ft[0]; /* file type */
|
|
fndr->file.fdType[2] = prodos_at[1]; /* high byte */
|
|
fndr->file.fdType[3] = prodos_at[0]; /* low byte */
|
|
break;
|
|
}
|
|
bcopy("pdos", fndr->file.fdCreator, CTLEN);
|
|
}
|
|
|
|
/*
|
|
* mapFNDR2PDOS
|
|
*
|
|
* convert Finder Info to ProDOS File Type and Aux Type
|
|
* (even to have to contemplate doing this is disgusting)
|
|
*
|
|
*/
|
|
|
|
mapFNDR2PDOS(fdp)
|
|
FileDirParm *fdp;
|
|
{
|
|
FinderInfo *fndr;
|
|
byte prodos_at[4];
|
|
byte prodos_ft[2];
|
|
byte hex2num();
|
|
|
|
fndr = (FinderInfo *) fdp->fdp_finfo;
|
|
|
|
if (fdp->fdp_flg == FDP_DIRFLG) {
|
|
/* set specific ProDOS directory information */
|
|
prodos_ft[0] = 0x0f;
|
|
prodos_ft[1] = 0x00;
|
|
prodos_at[0] = 0x00;
|
|
prodos_at[1] = 0x02;
|
|
prodos_at[2] = 0x00;
|
|
prodos_at[3] = 0x00;
|
|
bcopy(prodos_ft, &fdp->fdp_prodos_ft, sizeof(prodos_ft));
|
|
bcopy(prodos_at, &fdp->fdp_prodos_aux, sizeof(prodos_at));
|
|
return;
|
|
}
|
|
if (bcmp("TEXT", fndr->file.fdType, CTLEN) == 0) {
|
|
prodos_ft[0] = 0x04;
|
|
prodos_ft[1] = 0x00;
|
|
bzero(&fdp->fdp_prodos_aux, sizeof(prodos_at));
|
|
bcopy(prodos_ft, &fdp->fdp_prodos_ft, sizeof(prodos_ft));
|
|
return;
|
|
}
|
|
if (bcmp("pdos", fndr->file.fdCreator, CTLEN) == 0) {
|
|
if (bcmp("PSYS", fndr->file.fdType, CTLEN) == 0) {
|
|
prodos_ft[0] = 0xff;
|
|
prodos_ft[1] = 0x00;
|
|
bcopy(prodos_ft, &fdp->fdp_prodos_ft, sizeof(prodos_ft));
|
|
return;
|
|
}
|
|
if (bcmp("PS16", fndr->file.fdType, CTLEN) == 0) {
|
|
prodos_ft[0] = 0xb3;
|
|
prodos_ft[1] = 0x00;
|
|
bcopy(prodos_ft, &fdp->fdp_prodos_ft, sizeof(prodos_ft));
|
|
return;
|
|
}
|
|
if (bcmp("BINA", fndr->file.fdType, CTLEN) == 0) {
|
|
prodos_ft[0] = 0x00;
|
|
prodos_ft[1] = 0x00;
|
|
bcopy(prodos_ft, &fdp->fdp_prodos_ft, sizeof(prodos_ft));
|
|
return;
|
|
}
|
|
if (fndr->file.fdType[0] == 'p') { /* bizarre */
|
|
prodos_ft[0] = fndr->file.fdType[1];
|
|
prodos_ft[1] = 0x00;
|
|
prodos_at[0] = fndr->file.fdType[3]; /* low byte */
|
|
prodos_at[1] = fndr->file.fdType[2]; /* high byte */
|
|
prodos_at[2] = 0x00;
|
|
prodos_at[3] = 0x00;
|
|
bcopy(prodos_ft, &fdp->fdp_prodos_ft, sizeof(prodos_ft));
|
|
bcopy(prodos_at, &fdp->fdp_prodos_aux, sizeof(prodos_at));
|
|
return;
|
|
}
|
|
if (fndr->file.fdType[2] == ' ' && fndr->file.fdType[3] == ' ') {
|
|
short num; /* much more bizarre */
|
|
num = hex2num(fndr->file.fdType[0]) << 4;
|
|
num |= hex2num(fndr->file.fdType[1]) & 0xf;
|
|
prodos_ft[0] = (byte) num & 0xff;
|
|
prodos_ft[1] = 0x00;
|
|
bcopy(prodos_ft, &fdp->fdp_prodos_ft, sizeof(prodos_ft));
|
|
return;
|
|
}
|
|
}
|
|
/* otherwise */
|
|
prodos_ft[0] = 0x00;
|
|
prodos_ft[1] = 0x00;
|
|
bzero(&fdp->fdp_prodos_aux, sizeof(prodos_at));
|
|
bcopy(prodos_ft, &fdp->fdp_prodos_ft, sizeof(prodos_ft));
|
|
}
|
|
|
|
byte
|
|
hex2num(ch)
|
|
char ch;
|
|
{
|
|
if (ch >= '0' && ch <= '9')
|
|
return(ch - '0');
|
|
if (ch >= 'a' && ch <= 'f')
|
|
return(ch - 'a' + 10);
|
|
if (ch >= 'A' && ch <= 'F')
|
|
return(ch - 'A' + 10);
|
|
return(0);
|
|
}
|