mirror of
https://github.com/ctm/executor.git
synced 2024-05-29 06:41:34 +00:00
1112 lines
28 KiB
C
1112 lines
28 KiB
C
/* Copyright 1986-1995 by Abacus Research and
|
|
* Development, Inc. All rights reserved.
|
|
*/
|
|
|
|
#if !defined (OMIT_RCSID_STRINGS)
|
|
char ROMlib_rcsid_fileVolumes[] =
|
|
"$Id: fileVolumes.c 86 2005-05-25 00:47:12Z ctm $";
|
|
#endif
|
|
|
|
/* Forward declarations in FileMgr.h (DO NOT DELETE THIS LINE) */
|
|
|
|
#include "rsys/common.h"
|
|
#include "FileMgr.h"
|
|
#include "OSEvent.h"
|
|
#include "VRetraceMgr.h"
|
|
#include "OSUtil.h"
|
|
#include "MemoryMgr.h"
|
|
|
|
#include "rsys/hfs.h"
|
|
|
|
#include "rsys/file.h"
|
|
#include "rsys/glue.h"
|
|
#include "rsys/notmac.h"
|
|
#include "rsys/segment.h"
|
|
#include "rsys/string.h"
|
|
|
|
#if defined (CYGWIN32) || defined (MSDOS)
|
|
#include "rsys/fauxdbm.h"
|
|
#endif
|
|
|
|
#if defined (CYGWIN32)
|
|
#include "winfs.h"
|
|
#include "cygwin32.h"
|
|
#endif
|
|
|
|
#define MAKEVOLUME "/makevolume"
|
|
|
|
#define RETURN(x) { err = (x); goto DONE; }
|
|
|
|
/*
|
|
* For now we just use 101 entries in our hash table, no matter what.
|
|
* The hash function should be pretty damn uniform, so even if we have
|
|
* 10,000 entries (pretty unlikely), the linked list would only grow
|
|
* to 100 entries each, which shouldn't lead to very LONGINT searches.
|
|
*
|
|
* We still keep the number of hash entries in the data structure, because
|
|
* we want the flexibility to be able to change if anyone ever has the
|
|
* time to care.
|
|
*/
|
|
|
|
/*
|
|
* TODO: put an override option into the function that writes into
|
|
* the hash table. Use it when the host is known good.
|
|
*/
|
|
|
|
/*
|
|
* NOTE: The only two directories that are guaranteed to be in the database
|
|
* are "ExecutorVolume" and "ExecutorVolume/System Folder". If the
|
|
* program is started with any file arguments, their directory IDs
|
|
* and the directories/filesystems that are between them and /
|
|
* are also put into the database. All other entries come from
|
|
* the special hooks in Stdfile (or other places we put hooks).
|
|
*/
|
|
|
|
#define HASHSIZE 101
|
|
|
|
A2(PRIVATE, hashlink_t **, hashloc, VCBExtra *, vcbp, LONGINT, dir)
|
|
{
|
|
hashlink_t **hlpp;
|
|
INTEGER index;
|
|
|
|
gui_assert(vcbp);
|
|
index = dir % vcbp->u.ufs.nhashentries;
|
|
for (hlpp = &vcbp->u.ufs.hashtable[index]; *hlpp && (*hlpp)->dirid != dir;
|
|
hlpp = &(*hlpp)->next)
|
|
;
|
|
return hlpp;
|
|
}
|
|
|
|
typedef struct _chain_str {
|
|
hashlink_t *hashlinkp;
|
|
struct _chain_str *next;
|
|
} chain_t;
|
|
|
|
/*
|
|
* one of the following enum values is placed at the beginning of the
|
|
* directory name to indicate how confident we are that we have the
|
|
* right value. The order *is* important in the code: they are
|
|
* listed from least confident to most confident (actually checked_val
|
|
* and new_val represent the same confidence, but checked_val doesn't
|
|
* get placed into the database when we shut down).
|
|
*/
|
|
|
|
typedef enum {
|
|
old_generic_val,
|
|
old_specific_val,
|
|
checked_val,
|
|
new_val,
|
|
} newness_t;
|
|
|
|
static int
|
|
chaincount (chain_t *therest)
|
|
{
|
|
if (therest == 0)
|
|
/* the destination string already has accounted
|
|
for the nul terminator */
|
|
return 0;
|
|
else
|
|
return (strlen (therest->hashlinkp->dirname+1)
|
|
+ chaincount(therest->next)
|
|
/* for the prepended `/' */
|
|
+ 1);
|
|
}
|
|
|
|
static void
|
|
chainfill (char *p, chain_t *therest)
|
|
{
|
|
if (therest)
|
|
{
|
|
*p++ = '/';
|
|
strcpy (p, therest->hashlinkp->dirname + 1);
|
|
chainfill (p + strlen (p), therest->next);
|
|
}
|
|
}
|
|
|
|
static boolean_t
|
|
on_chain_p (hashlink_t *hlp, chain_t *therest, boolean_t dump_link)
|
|
{
|
|
if (dump_link)
|
|
warning_trace_info ("dirid = %d, parid = %d, dirname = '%s'", hlp->dirid,
|
|
hlp->parid, hlp->dirname);
|
|
if (!therest)
|
|
return FALSE;
|
|
else if (therest->hashlinkp == hlp)
|
|
return TRUE;
|
|
else
|
|
return on_chain_p (hlp, therest->next, dump_link);
|
|
}
|
|
|
|
void
|
|
recsetdp (VCBExtra * vcbp, datum *dp, hashlink_t *hlp, chain_t *therest)
|
|
{
|
|
if (hlp->parid <= 2 || hlp->parid == vcbp->u.ufs.ino)
|
|
{
|
|
int ourlen;
|
|
|
|
ourlen = strlen (hlp->dirname+1); /* don't count flag byte */
|
|
dp->dsize = ourlen + chaincount(therest) + 1;
|
|
dp->dptr = malloc(dp->dsize);
|
|
strcpy(dp->dptr, hlp->dirname+1);
|
|
chainfill(dp->dptr + ourlen, therest);
|
|
}
|
|
else
|
|
{
|
|
chain_t ourlink;
|
|
hashlink_t *newhlp;
|
|
|
|
ourlink.hashlinkp = hlp;
|
|
ourlink.next = therest;
|
|
newhlp = *hashloc(vcbp, hlp->parid);
|
|
if (newhlp)
|
|
{
|
|
if (on_chain_p (newhlp, therest, FALSE))
|
|
{
|
|
warning_unexpected ("recset loop unixname = '%s'"
|
|
" dirid = %d, parid = %d, dirname = '%s'",
|
|
vcbp->unixname, newhlp->dirid,
|
|
newhlp->parid, newhlp->dirname);
|
|
on_chain_p (newhlp, therest, TRUE);
|
|
dp->dsize = 0;
|
|
dp->dptr = 0;
|
|
}
|
|
else
|
|
recsetdp(vcbp, dp, newhlp, &ourlink);
|
|
}
|
|
else
|
|
{
|
|
warning_unexpected ("newhlp = 0, unixname = %s, parid = %d",
|
|
vcbp->unixname, hlp->parid);
|
|
dp->dsize = 0;
|
|
dp->dptr = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
A2(PUBLIC, datum, ROMlib_dbm_fetch, VCBExtra *, vcbp, LONGINT, dir) /* INTERNAL */
|
|
{
|
|
datum foo;
|
|
hashlink_t *hlp;
|
|
|
|
hlp = *hashloc(vcbp, dir);
|
|
|
|
if (hlp)
|
|
recsetdp(vcbp, &foo, hlp, (chain_t *) 0);
|
|
else {
|
|
foo.dptr = 0;
|
|
foo.dsize = 0;
|
|
}
|
|
return foo;
|
|
}
|
|
|
|
PRIVATE char *copystring(const char *orig, newness_t new)
|
|
{
|
|
int length;
|
|
char *retval;
|
|
|
|
length = strlen(orig);
|
|
retval = malloc(length + 2); /* +1 for NULL, +1 for new */
|
|
retval[0] = new;
|
|
strcpy(retval+1, orig);
|
|
return retval;
|
|
}
|
|
|
|
PRIVATE const char *
|
|
filename_from_pathname (const char *path)
|
|
{
|
|
const char *last_slash;
|
|
const char *last_back_slash;
|
|
|
|
last_slash = strrchr (path, '/');
|
|
last_back_slash = strrchr (path, '\\');
|
|
path = MAX (path, last_slash+1);
|
|
path = MAX (path, last_back_slash+1);
|
|
return path;
|
|
}
|
|
|
|
#define REMOVE_TRAILING_SLASHES(path) \
|
|
({ \
|
|
char *__retval; \
|
|
const char *__path; \
|
|
int __len; \
|
|
const char *__lastcp; \
|
|
\
|
|
__path = (path); \
|
|
__len = strlen (__path); \
|
|
__lastcp = __path + __len - 1; \
|
|
while (__len > SLASH_CHAR_OFFSET + 1 && *__lastcp == '/') \
|
|
{ \
|
|
--__len; \
|
|
--__lastcp; \
|
|
} \
|
|
\
|
|
__retval = alloca (__len + 1); \
|
|
memcpy (__retval, __path, __len); \
|
|
__retval[__len] = 0; \
|
|
\
|
|
__retval; \
|
|
})
|
|
|
|
PRIVATE boolean_t
|
|
filename_match (const char *prefix, const char *path1, const char *path2)
|
|
{
|
|
boolean_t retval;
|
|
int prefix_length;
|
|
|
|
retval = TRUE;
|
|
if (path2[0] == '/' && !path2[1]) /* top-level dir of this volume */
|
|
prefix_length = 1;
|
|
else
|
|
{
|
|
prefix_length = strlen (prefix);
|
|
if (strncasecmp (prefix, path2, prefix_length) != 0)
|
|
retval = FALSE;
|
|
}
|
|
|
|
if (retval)
|
|
{
|
|
const char *file1;
|
|
const char *file2;
|
|
|
|
path2 += prefix_length;
|
|
file1 = filename_from_pathname (path1);
|
|
file2 = REMOVE_TRAILING_SLASHES (path2);
|
|
file2 = filename_from_pathname (file2);
|
|
retval = strcasecmp (file1, file2) == 0;
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
/*
|
|
* hashinsert will do the stat for you if the dirid is 0
|
|
* hashinsert returns TRUE if the entry is already there
|
|
*/
|
|
|
|
PRIVATE BOOLEAN hashinsert(VCBExtra *vcbp, char *pathname, LONGINT *diridp,
|
|
LONGINT parid, newness_t new)
|
|
{
|
|
BOOLEAN retval;
|
|
hashlink_t **hlpp, *newlink;
|
|
struct stat sbuf;
|
|
char *savep, save;
|
|
char *newpathname;
|
|
int len;
|
|
|
|
len = strlen (pathname) + 1;
|
|
newpathname = alloca (len);
|
|
memcpy (newpathname, pathname, len);
|
|
ROMlib_undotdot (newpathname);
|
|
pathname = newpathname;
|
|
if (*diridp == 0) {
|
|
if (Ustat(pathname, &sbuf) == 0 && S_ISDIR (sbuf.st_mode))
|
|
*diridp = ST_INO (sbuf);
|
|
}
|
|
if (!diridp)
|
|
retval = FALSE;
|
|
else {
|
|
hlpp = hashloc(vcbp, *diridp);
|
|
if (*hlpp && (*hlpp)->dirname[0] >= checked_val)
|
|
{
|
|
if (!filename_match (vcbp->unixname,
|
|
(*hlpp)->dirname+1, pathname) ||
|
|
(parid && (*hlpp)->parid != parid))
|
|
{
|
|
warning_unexpected ("%s %s %d %d %d %d %s %d %d",
|
|
vcbp->unixname, pathname, *diridp, parid,
|
|
new, (*hlpp)->dirname[0],
|
|
(*hlpp)->dirname+1, (*hlpp)->dirid,
|
|
(*hlpp)->parid);
|
|
goto use_new_value_to_be_safe;
|
|
}
|
|
retval = TRUE;
|
|
}
|
|
else {
|
|
use_new_value_to_be_safe:
|
|
savep = 0;
|
|
retval = FALSE;
|
|
if (parid == 0) {
|
|
if (*diridp == 2) /* root of a filesystem */
|
|
parid = 1; /* that's the way it is on the mac */
|
|
else {
|
|
savep = strrchr(pathname, '/');
|
|
if (savep == pathname + SLASH_CHAR_OFFSET)
|
|
++savep;
|
|
save = *savep;
|
|
*savep = 0;
|
|
if (Ustat(pathname, &sbuf) == 0)
|
|
parid = ST_INO (sbuf);
|
|
*savep = save;
|
|
if (savep == pathname + 1 + SLASH_CHAR_OFFSET)
|
|
--savep; /* restore for later */
|
|
}
|
|
}
|
|
if (parid) {
|
|
if (strlen(pathname) > SLASH_CHAR_OFFSET
|
|
&& pathname[SLASH_CHAR_OFFSET] == '/') {
|
|
if (!savep)
|
|
savep = strrchr(pathname, '/');
|
|
++savep;
|
|
} else
|
|
savep = pathname;
|
|
if (*hlpp) {
|
|
if ((*hlpp)->dirid == *diridp && (*hlpp)->parid == parid &&
|
|
strcmp(savep, (*hlpp)->dirname+1) == 0) {
|
|
if (new >= checked_val &&
|
|
(*hlpp)->dirname[0] < checked_val)
|
|
(*hlpp)->dirname[0] = checked_val;
|
|
} else if (new >= (unsigned char) (*hlpp)->dirname[0]) {
|
|
free((*hlpp)->dirname);
|
|
(*hlpp)->dirname = 0;
|
|
}
|
|
} else {
|
|
newlink = (hashlink_t *) malloc(sizeof(hashlink_t));
|
|
newlink->next = 0;
|
|
newlink->dirid = *diridp;
|
|
newlink->dirname = 0;
|
|
*hlpp = newlink;
|
|
}
|
|
(*hlpp)->parid = parid;
|
|
if (!(*hlpp)->dirname)
|
|
(*hlpp)->dirname = copystring(savep, new);
|
|
}
|
|
}
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
A4(PUBLIC, BOOLEAN, ROMlib_dbm_store, VCBExtra *, vcbp, char *, pathname, /* INTERNAL */
|
|
LONGINT *, diridp, BOOLEAN, verify_p)
|
|
{
|
|
BOOLEAN retval;
|
|
|
|
retval = hashinsert(vcbp, pathname, diridp, 0, new_val);
|
|
if (retval && verify_p)
|
|
{
|
|
datum verify;
|
|
|
|
verify = ROMlib_dbm_fetch (vcbp, *diridp);
|
|
if (!verify.dptr)
|
|
{
|
|
warning_unexpected ("vcbp->unixname = '%s', pathname = '%s', "
|
|
"*diridp = %d", vcbp->unixname, pathname,
|
|
*diridp);
|
|
ROMlib_automount (pathname);
|
|
}
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
PUBLIC void ROMlib_dbm_delete_inode( VCBExtra *vcbp, LONGINT inode )
|
|
{
|
|
hashlink_t **hlpp, *todie;
|
|
|
|
hlpp = hashloc(vcbp, inode);
|
|
if ((todie = *hlpp))
|
|
{
|
|
*hlpp = todie->next;
|
|
free(todie->dirname);
|
|
free(todie);
|
|
}
|
|
}
|
|
|
|
PRIVATE BOOLEAN filesystems_match(rkey_t *keyp, VCBExtra *vcbp)
|
|
{
|
|
int namlen;
|
|
BOOLEAN retval;
|
|
|
|
namlen = strlen(vcbp->unixname);
|
|
if (namlen == CW(keyp->filesystemlen))
|
|
retval = strncmp(vcbp->unixname,
|
|
keyp->hostnameandroot + keyp->hostnamelen, namlen) == 0;
|
|
else
|
|
retval = FALSE;
|
|
return retval;
|
|
}
|
|
|
|
PRIVATE BOOLEAN no_hostname(rkey_t *keyp)
|
|
{
|
|
return !!keyp->hostnamelen;
|
|
}
|
|
|
|
#define OURMAXHOSTNAMELEN 64
|
|
|
|
#if !defined(MSDOS) && !defined (CYGWIN32)
|
|
PUBLIC char ROMlib_hostname[OURMAXHOSTNAMELEN + 1];
|
|
PUBLIC INTEGER ROMlib_hostnamelen = -1;
|
|
#else /* defined(MSDOS) */
|
|
PUBLIC char ROMlib_hostname[] = "MSDOS";
|
|
PUBLIC INTEGER ROMlib_hostnamelen = sizeof(ROMlib_hostname)-1;
|
|
#endif /* defined(MSDOS) */
|
|
|
|
PRIVATE void ourgethostname( void )
|
|
{
|
|
if (ROMlib_hostnamelen == -1) {
|
|
#if !defined(MSDOS) && !defined (CYGWIN32)
|
|
gethostname(ROMlib_hostname, OURMAXHOSTNAMELEN);
|
|
ROMlib_hostnamelen = strlen(ROMlib_hostname);
|
|
#else /* defined(MSDOS) */
|
|
gui_abort();
|
|
#endif /* defined(MSDOS) */
|
|
}
|
|
}
|
|
|
|
|
|
PRIVATE BOOLEAN hostnames_match(rkey_t *keyp, VCBExtra *vcbp)
|
|
{
|
|
BOOLEAN retval;
|
|
|
|
ourgethostname();
|
|
if (ROMlib_hostnamelen == keyp->hostnamelen) {
|
|
retval = strncmp(ROMlib_hostname, keyp->hostnameandroot,
|
|
ROMlib_hostnamelen) == 0;
|
|
} else
|
|
retval = FALSE;
|
|
return retval;
|
|
}
|
|
|
|
PRIVATE BOOLEAN isamatch(rkey_t *keyp, VCBExtra *vcbp, newness_t *newp)
|
|
{
|
|
BOOLEAN retval;
|
|
|
|
retval = FALSE;
|
|
if (filesystems_match(keyp, vcbp)) {
|
|
if (no_hostname(keyp)) {
|
|
*newp = old_generic_val;
|
|
retval = TRUE;
|
|
} else if (hostnames_match(keyp, vcbp)) {
|
|
*newp = old_specific_val;
|
|
retval = TRUE;
|
|
}
|
|
}
|
|
return retval;
|
|
|
|
return filesystems_match(keyp, vcbp) &&
|
|
(no_hostname(keyp) || hostnames_match(keyp, vcbp));
|
|
}
|
|
|
|
PRIVATE char *extractpathname(rcontent_t *contentp)
|
|
{
|
|
return contentp->path;
|
|
}
|
|
|
|
/*
|
|
* cleanvcbhash cleans up the hash table by freeing all the entries
|
|
* except the new ones, which are kept on a list so that they can be
|
|
* added to the database when things shut down.
|
|
*/
|
|
|
|
PRIVATE hashlink_t *cleanvcbhash(VCBExtra *vcbp)
|
|
{
|
|
hashlink_t *retval, *hlp, *next;
|
|
INTEGER i;
|
|
|
|
retval = 0;
|
|
for (i = 0; i < vcbp->u.ufs.nhashentries; ++i)
|
|
for (hlp = vcbp->u.ufs.hashtable[i]; hlp; hlp = next) {
|
|
next = hlp->next;
|
|
if (hlp->dirname[0] == new_val) {
|
|
hlp->next = retval;
|
|
retval = hlp;
|
|
} else
|
|
free(hlp);
|
|
}
|
|
free(vcbp->u.ufs.hashtable);
|
|
return retval;
|
|
}
|
|
|
|
PRIVATE void freedeletelist(hashlink_t *deletep)
|
|
{
|
|
hashlink_t *nextlink;
|
|
|
|
while (deletep) {
|
|
nextlink = deletep->next;
|
|
free(deletep);
|
|
deletep = nextlink;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* See the extended comment in linux.c before adjusting any of this.
|
|
* It's much more subtle than it looks.
|
|
*/
|
|
|
|
#if !defined (DBM_FETCH)
|
|
#define DBM_FETCH(datump, db, datum) (*(datump) = dbm_fetch ((db), (datum)))
|
|
#define DBM_FIRSTKEY(datump, db) (*(datump) = dbm_firstkey (db))
|
|
#define DBM_NEXTKEY(datump, db) (*(datump) = dbm_nextkey (db))
|
|
#endif
|
|
|
|
PRIVATE void readadbm(const char *dbmname, VCBExtra *vcbp)
|
|
{
|
|
DBM *db;
|
|
datum key, content;
|
|
rkey_t *keyp;
|
|
rcontent_t *contentp;
|
|
newness_t new;
|
|
LONGINT dirid;
|
|
|
|
/*
|
|
* The cast to (char *) of dbmname is necessary since dbm_open doesn't
|
|
* explicitly require a (const char *)
|
|
*/
|
|
if (!(db = dbm_open((char *) dbmname, O_RDONLY, (LONGINT) 0)))
|
|
; /* fprintf(stderr, "Problems opening dbm \"%s\"\n", dbmname); */
|
|
else {
|
|
for (DBM_FIRSTKEY(&key, db); key.dptr; DBM_NEXTKEY(&key, db)) {
|
|
keyp = (rkey_t *) key.dptr;
|
|
if (isamatch(keyp, vcbp, &new)) {
|
|
DBM_FETCH (&content, db, key);
|
|
if (content.dsize) {
|
|
contentp = (rcontent_t *) content.dptr;
|
|
dirid = CL(keyp->dirid);
|
|
hashinsert(vcbp, extractpathname(contentp), &dirid,
|
|
CL(contentp->parid), new);
|
|
}
|
|
}
|
|
}
|
|
dbm_close(db);
|
|
}
|
|
}
|
|
|
|
PRIVATE void writeadbm(const char *dbmname, VCBExtra *vcbp,
|
|
hashlink_t *deletep)
|
|
{
|
|
DBM *db;
|
|
datum key, content;
|
|
INTEGER unamelen, dirnamelen;
|
|
char buf[1024], *dst, buf2[1024];
|
|
rkey_t *keyp;
|
|
rcontent_t *contentp;
|
|
|
|
/*
|
|
* The cast to (char *) of dbmname is necessary since dbm_open doesn't
|
|
* explicitly require a (const char *)
|
|
*/
|
|
if (deletep && (db = dbm_open((char *) dbmname, O_CREAT|O_RDWR,
|
|
(LONGINT) 0666))) {
|
|
ourgethostname();
|
|
unamelen = strlen(vcbp->unixname);
|
|
keyp = (rkey_t *) buf;
|
|
key.dptr = buf;
|
|
contentp = (rcontent_t *) buf2;
|
|
content.dptr = buf2;
|
|
do {
|
|
dirnamelen = strlen(deletep->dirname+1);
|
|
key.dsize = sizeof(rkey_t) + ROMlib_hostnamelen + unamelen - 1;
|
|
content.dsize = sizeof(rcontent_t) + dirnamelen - 1;
|
|
keyp->dirid = CL(deletep->dirid);
|
|
keyp->filesystemlen = CW(unamelen);
|
|
keyp->hostnamelen = ROMlib_hostnamelen;
|
|
dst = keyp->hostnameandroot;
|
|
memcpy(dst, ROMlib_hostname, ROMlib_hostnamelen);
|
|
dst += ROMlib_hostnamelen;
|
|
memcpy(dst, vcbp->unixname, unamelen);
|
|
contentp->parid = CL(deletep->parid);
|
|
strcpy(contentp->path, deletep->dirname+1);
|
|
dbm_store(db, key, content, DBM_REPLACE);
|
|
keyp->hostnamelen = 0;
|
|
key.dsize -= ROMlib_hostnamelen;
|
|
/* NOTE: we memmove more bytes than we need, but with no ill effect */
|
|
memmove(keyp->hostnameandroot,
|
|
keyp->hostnameandroot+ROMlib_hostnamelen,
|
|
key.dsize);
|
|
dbm_store(db, key, content, DBM_REPLACE);
|
|
} while ((deletep = deletep->next));
|
|
dbm_close(db);
|
|
}
|
|
}
|
|
|
|
A1(PUBLIC, void, ROMlib_dbm_open, VCBExtra *, vcbp) /* INTERNAL */
|
|
{
|
|
LONGINT size;
|
|
LONGINT dirid;
|
|
|
|
size = (LONGINT) sizeof(hashlink_t) * HASHSIZE;
|
|
vcbp->u.ufs.hashtable = malloc(size);
|
|
vcbp->u.ufs.nhashentries = HASHSIZE;
|
|
memset(vcbp->u.ufs.hashtable, 0, size);
|
|
readadbm(ROMlib_PublicDirectoryMap, vcbp);
|
|
#if !defined (CYGWIN32) && !defined (MSDOS)
|
|
readadbm(ROMlib_PrivateDirectoryMap, vcbp);
|
|
#endif
|
|
dirid = 2;
|
|
hashinsert(vcbp, "", &dirid, 1, checked_val);
|
|
}
|
|
|
|
A1(PUBLIC, void, ROMlib_dbm_close, VCBExtra *, vcbp) /* INTERNAL */
|
|
{
|
|
hashlink_t *deletep;
|
|
LONGINT oumask;
|
|
|
|
deletep = cleanvcbhash(vcbp);
|
|
#if !defined (CYGWIN32) && !defined (MSDOS)
|
|
writeadbm(ROMlib_PrivateDirectoryMap, vcbp, deletep);
|
|
#endif
|
|
oumask = umask(000);
|
|
writeadbm(ROMlib_PublicDirectoryMap, vcbp, deletep);
|
|
umask(oumask);
|
|
freedeletelist(deletep);
|
|
}
|
|
|
|
A1(PUBLIC, OSErr, ufsPBMountVol, ParmBlkPtr, pb) /* INTERNAL */
|
|
{
|
|
VCBExtra *vp;
|
|
char *name;
|
|
int macvolumenamelen, namelen;
|
|
struct stat sbuf;
|
|
OSErr err;
|
|
THz savezone;
|
|
ALLOCABEGIN
|
|
|
|
err = noErr;
|
|
savezone = TheZone;
|
|
TheZone = SysZone;
|
|
if (Ustat(ROMlib_volumename, &sbuf) < 0)
|
|
/*-->*/ RETURN(badMDBErr)
|
|
if (ROMlib_vcbbydrive(Cx(pb->volumeParam.ioVRefNum)) ||
|
|
ROMlib_vcbbyunixname(ROMlib_volumename))
|
|
RETURN(volOnLinErr);
|
|
vp = (VCBExtra *) NewPtr((Size) sizeof(VCBExtra));
|
|
|
|
macvolumenamelen = strlen(ROMlib_volumename);
|
|
if (vp)
|
|
memset(vp, 0, (LONGINT) sizeof(VCBExtra));
|
|
if (!vp ||
|
|
!(vp->unixname = (char *) NewPtr(macvolumenamelen+1)))
|
|
/*-->*/ RETURN(memFullErr)
|
|
strcpy(vp->unixname, ROMlib_volumename);
|
|
vp->vcb.vcbDrvNum = pb->ioParam.ioVRefNum;
|
|
--ROMlib_nextvrn;
|
|
vp->vcb.vcbVRefNum = CW(ROMlib_nextvrn);
|
|
vp->u.ufs.ino = ST_INO (sbuf);
|
|
if (strcmp("/", ROMlib_volumename + SLASH_CHAR_OFFSET) == 0) {
|
|
name = ROMlib_volumename;
|
|
if (SLASH_CHAR_OFFSET == 2) /* C:/ --> C/ */
|
|
{
|
|
char *new_name;
|
|
|
|
new_name = alloca(3);
|
|
new_name[0] = name[0];
|
|
new_name[1] = '/';
|
|
new_name[2] = 0;
|
|
name = new_name;
|
|
}
|
|
} else {
|
|
if (!(name = strrchr(ROMlib_volumename, '/')))
|
|
name = ROMlib_volumename;
|
|
else
|
|
++name;
|
|
}
|
|
namelen = strlen(name);
|
|
if (namelen >= (int) sizeof(vp->vcb.vcbVN))
|
|
namelen = sizeof(vp->vcb.vcbVN) - 1;
|
|
vp->vcb.vcbVN[0] = namelen;
|
|
strncpy((char *) vp->vcb.vcbVN+1, name, namelen);
|
|
/*
|
|
* TODO: we have to set up the hash table for this entry ...
|
|
*/
|
|
ROMlib_dbm_open(vp);
|
|
vp->vcb.vcbSigWord = CWC(0x4244); /* IMIV-188 */
|
|
vp->vcb.vcbFreeBks = CWC(20480); /* arbitrary */
|
|
vp->vcb.vcbCrDate = 0; /* I'm lying here */
|
|
vp->vcb.vcbVolBkUp = 0;
|
|
vp->vcb.vcbAtrb = CWC(VNONEJECTABLEBIT);
|
|
vp->vcb.vcbNmFls = CWC(100);
|
|
vp->vcb.vcbNmAlBlks = CWC(300);
|
|
vp->vcb.vcbAlBlkSiz = CLC(512);
|
|
vp->vcb.vcbClpSiz = CLC(1);
|
|
vp->vcb.vcbAlBlSt = CWC(10);
|
|
vp->vcb.vcbNxtCNID = CLC(1000);
|
|
if (!DefVCBPtr) {
|
|
DefVCBPtr = RM((VCB *) vp);
|
|
DefVRefNum = vp->vcb.vcbVRefNum;
|
|
DefDirID = CLC(2); /* top level */
|
|
}
|
|
|
|
pb->ioParam.ioVRefNum = vp->vcb.vcbVRefNum;
|
|
Enqueue((QElemPtr) vp, &VCBQHdr);
|
|
DONE:
|
|
TheZone = savezone;
|
|
ALLOCAEND
|
|
return err;
|
|
}
|
|
#undef RETURN
|
|
|
|
A4(PUBLIC, OSErr, GetVInfo, INTEGER, drv, StringPtr, voln, /* IMIV-107 */
|
|
INTEGER *, vrn, LONGINT *, freeb)
|
|
{
|
|
ParamBlockRec pbr;
|
|
OSErr temp;
|
|
|
|
pbr.volumeParam.ioVolIndex = 0;
|
|
pbr.volumeParam.ioVRefNum = CW(drv);
|
|
pbr.volumeParam.ioNamePtr = RM(voln);
|
|
temp = PBGetVInfo(&pbr, 0);
|
|
*vrn = pbr.volumeParam.ioVRefNum;
|
|
*freeb = CL(Cx(pbr.volumeParam.ioVFrBlk) * Cx(pbr.volumeParam.ioVAlBlkSiz));
|
|
return(temp);
|
|
}
|
|
|
|
A2(PUBLIC, OSErr, GetVRefNum, INTEGER, prn, INTEGER *, vrn) /* IMIV-107 */
|
|
{
|
|
OSErr err;
|
|
fcbrec *fp;
|
|
|
|
fp = PRNTOFPERR(prn, &err);
|
|
|
|
if (err == noErr)
|
|
*vrn = MR(fp->fcvptr)->vcbVRefNum;
|
|
return(err);
|
|
}
|
|
|
|
A2(PUBLIC, OSErr, GetVol, StringPtr, voln, INTEGER *, vrn) /* IMIV-107 */
|
|
{
|
|
ParamBlockRec pbr;
|
|
OSErr temp;
|
|
|
|
pbr.volumeParam.ioNamePtr = RM(voln);
|
|
temp = PBGetVol(&pbr, 0);
|
|
*vrn = pbr.volumeParam.ioVRefNum;
|
|
return(temp);
|
|
}
|
|
|
|
A2(PUBLIC, OSErr, SetVol, StringPtr, voln, INTEGER, vrn) /* IMIV-107 */
|
|
{
|
|
ParamBlockRec pbr;
|
|
|
|
pbr.volumeParam.ioNamePtr = RM(voln);
|
|
pbr.volumeParam.ioVRefNum = CW(vrn);
|
|
return(PBSetVol(&pbr, 0));
|
|
}
|
|
|
|
A2(PUBLIC, OSErr, FlushVol, StringPtr, voln, INTEGER, vrn) /* IMIV-108 */
|
|
{
|
|
ParamBlockRec pbr;
|
|
|
|
pbr.ioParam.ioNamePtr = RM(voln);
|
|
pbr.ioParam.ioVRefNum = CW(vrn);
|
|
return(PBFlushVol(&pbr, 0));
|
|
}
|
|
|
|
A2(PUBLIC, OSErr, UnmountVol, StringPtr, voln, INTEGER, vrn) /* IMIV-108 */
|
|
{
|
|
ParamBlockRec pbr;
|
|
|
|
pbr.ioParam.ioNamePtr = RM(voln);
|
|
pbr.ioParam.ioVRefNum = CW(vrn);
|
|
return(PBUnmountVol(&pbr));
|
|
}
|
|
|
|
A2(PUBLIC, OSErr, Eject, StringPtr, voln, INTEGER, vrn) /* IMIV-108 */
|
|
{
|
|
ParamBlockRec pbr;
|
|
|
|
pbr.ioParam.ioNamePtr = RM(voln);
|
|
pbr.ioParam.ioVRefNum = CW(vrn);
|
|
return(PBEject(&pbr));
|
|
}
|
|
|
|
A4(PRIVATE, VCB *, findvcb, StringPtr, sp, INTEGER, vrn, BOOLEAN *, iswd,
|
|
INTEGER *, vrnp)
|
|
{
|
|
VCB *vcbptr;
|
|
|
|
*iswd = FALSE;
|
|
if (sp && sp[U(sp[0])] == VOLCHAR) {
|
|
for (vcbptr = (VCB *)MR(VCBQHdr.qHead);
|
|
vcbptr && !EqualString(sp, (StringPtr) vcbptr->vcbVN,
|
|
FALSE, TRUE);
|
|
vcbptr = (VCB *)MR(vcbptr->qLink))
|
|
;
|
|
*vrnp = vcbptr->vcbVRefNum;
|
|
} else {
|
|
if (vrn == 0) {
|
|
if (DefVCBPtr)
|
|
*vrnp = MR(DefVCBPtr)->vcbVRefNum;
|
|
else
|
|
*vrnp = 0;
|
|
/*-->*/ return MR(DefVCBPtr);
|
|
}
|
|
if (vrn < 0) {
|
|
*vrnp = CW(vrn);
|
|
if (ISWDNUM(vrn)) {
|
|
*iswd = TRUE;
|
|
vcbptr = WDNUMTOWDP(vrn)->vcbp;
|
|
} else
|
|
vcbptr = ROMlib_vcbbyvrn(vrn);
|
|
} else {
|
|
for (vcbptr = (VCB *)MR(VCBQHdr.qHead);
|
|
vcbptr && Cx(vcbptr->vcbDrvNum) != vrn;
|
|
vcbptr = (VCB *)MR(vcbptr->qLink))
|
|
;
|
|
if (vcbptr)
|
|
*vrnp = vcbptr->vcbVRefNum;
|
|
else
|
|
*vrnp = 0;
|
|
}
|
|
}
|
|
return vcbptr;
|
|
}
|
|
|
|
A2(PRIVATE, VCB *, grabvcb, ParmBlkPtr, pb, INTEGER *, vrefnump)
|
|
{
|
|
INTEGER i;
|
|
VCB *vcbp;
|
|
StringPtr sp;
|
|
LONGINT dir;
|
|
char *therest;
|
|
|
|
therest = 0;
|
|
dir = 1;
|
|
if ((i = Cx(pb->volumeParam.ioVolIndex)) > 0)
|
|
for (vcbp = (VCB *) MR(VCBQHdr.qHead); i > 1 && vcbp ;
|
|
vcbp = (VCB *)MR(vcbp->qLink), i--)
|
|
;
|
|
else if (Cx(pb->volumeParam.ioVolIndex) == 0) {
|
|
sp = MR(pb->volumeParam.ioNamePtr);
|
|
pb->volumeParam.ioNamePtr = 0;
|
|
vcbp = ROMlib_breakoutioname(pb, &dir, &therest, (BOOLEAN *) 0, FALSE);
|
|
pb->volumeParam.ioNamePtr = RM(sp);
|
|
} else
|
|
{
|
|
BOOLEAN use_defaults;
|
|
unsigned char *p;
|
|
|
|
p = (unsigned char *) MR (pb->volumeParam.ioNamePtr);
|
|
if (!p || p[0] == 0 || p[1] == ':')
|
|
use_defaults = TRUE;
|
|
else
|
|
use_defaults = !pstr_index_after (p, ':', 1);
|
|
vcbp = ROMlib_breakoutioname(pb, &dir, &therest, (BOOLEAN *) 0,
|
|
use_defaults);
|
|
}
|
|
free (therest);
|
|
if (vcbp) {
|
|
if (dir <= 2)
|
|
*vrefnump = vcbp->vcbVRefNum;
|
|
else { /* working dir id */
|
|
if (pb->volumeParam.ioVRefNum != 0)
|
|
*vrefnump = pb->volumeParam.ioVRefNum;
|
|
else
|
|
*vrefnump = DefVRefNum;
|
|
}
|
|
}
|
|
|
|
return vcbp;
|
|
}
|
|
|
|
PRIVATE unsigned short
|
|
find_pseudo_block_size (long n_blocks, long block_size)
|
|
{
|
|
unsigned short retval;
|
|
long long total_blockage;
|
|
|
|
if (!block_size) /* can happen when dealing with stale NFS handles */
|
|
block_size = 1024;
|
|
|
|
total_blockage = (long long) n_blocks * block_size;
|
|
|
|
if (total_blockage >= (unsigned long) 1 << 31)
|
|
total_blockage = ((unsigned long) 1 << 31) - 512;
|
|
|
|
if (n_blocks < (1 << 16))
|
|
retval = block_size;
|
|
else
|
|
{
|
|
retval = (block_size + 511) / 512 * 512;
|
|
while (total_blockage / retval >= (1 << 16))
|
|
retval += 512;
|
|
}
|
|
|
|
if (retval == 0)
|
|
{
|
|
/* shouldn't be possible to get here */
|
|
warning_unexpected ("n_blocks = %ld, block_size = %ld", n_blocks,
|
|
block_size);
|
|
retval = 1024;
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
A1(PRIVATE, VCB *, common, ParmBlkPtr, pb)
|
|
{
|
|
VCB *vcbp;
|
|
struct statfs sbuf;
|
|
|
|
vcbp = grabvcb(pb, &pb->volumeParam.ioVRefNum);
|
|
if (vcbp) {
|
|
if (Ustatfs(((VCBExtra *) vcbp)->unixname, &sbuf) == 0) {
|
|
LONGINT effective_free_blocks;
|
|
unsigned long pseudo_block_size;
|
|
long nm_al_blks;
|
|
long free_bks;
|
|
unsigned short short_nm_al_blks;
|
|
unsigned short short_free_bks;
|
|
|
|
pseudo_block_size = find_pseudo_block_size (sbuf.f_blocks,
|
|
sbuf.f_bsize);
|
|
vcbp->vcbAlBlkSiz = CL (pseudo_block_size);
|
|
nm_al_blks = ((long long) sbuf.f_blocks * sbuf.f_bsize
|
|
/ pseudo_block_size);
|
|
short_nm_al_blks = MIN (nm_al_blks, 65535);
|
|
vcbp->vcbNmAlBlks = CW (short_nm_al_blks);
|
|
effective_free_blocks = geteuid() ? sbuf.f_bavail : sbuf.f_bfree;
|
|
free_bks = ((long long) effective_free_blocks * sbuf.f_bsize
|
|
/ pseudo_block_size);
|
|
|
|
short_free_bks = MIN (free_bks, 65535);
|
|
vcbp->vcbFreeBks = CW (short_free_bks);
|
|
vcbp->vcbFilCnt = CL(sbuf.f_files);
|
|
}
|
|
if (pb->volumeParam.ioNamePtr)
|
|
str255assign(MR(pb->volumeParam.ioNamePtr), vcbp->vcbVN);
|
|
pb->volumeParam.ioVCrDate = vcbp->vcbCrDate;
|
|
pb->volumeParam.ioVLsBkUp = vcbp->vcbVolBkUp;
|
|
pb->volumeParam.ioVAtrb = vcbp->vcbAtrb;
|
|
pb->volumeParam.ioVNmFls = vcbp->vcbNmFls;
|
|
pb->volumeParam.ioVNmAlBlks = vcbp->vcbNmAlBlks;
|
|
pb->volumeParam.ioVAlBlkSiz = vcbp->vcbAlBlkSiz;
|
|
pb->volumeParam.ioVClpSiz = vcbp->vcbClpSiz;
|
|
pb->volumeParam.ioAlBlSt = vcbp->vcbAlBlSt;
|
|
pb->volumeParam.ioVNxtFNum = vcbp->vcbNxtCNID;
|
|
pb->volumeParam.ioVFrBlk = vcbp->vcbFreeBks;
|
|
}
|
|
return vcbp;
|
|
}
|
|
|
|
A2(PUBLIC, OSErr, ufsPBGetVInfo, ParmBlkPtr, pb, /* INTERNAL */
|
|
BOOLEAN, a)
|
|
{
|
|
OSErr err = noErr;
|
|
VCB *vcbp;
|
|
|
|
vcbp = common(pb);
|
|
if (!vcbp)
|
|
err = nsvErr;
|
|
return err;
|
|
}
|
|
|
|
A2(PUBLIC, OSErr, ufsPBHGetVInfo, HParmBlkPtr, pb, /* INTERNAL */
|
|
BOOLEAN, a)
|
|
{
|
|
OSErr err = noErr;
|
|
VCB *vcbp;
|
|
wdentry *wdp;
|
|
|
|
vcbp = common((ParmBlkPtr) pb);
|
|
if (!vcbp)
|
|
err = nsvErr;
|
|
else {
|
|
pb->volumeParam.ioVRefNum = vcbp->vcbVRefNum;
|
|
pb->volumeParam.ioVSigWord = vcbp->vcbSigWord;
|
|
pb->volumeParam.ioVDrvInfo = vcbp->vcbDrvNum;
|
|
pb->volumeParam.ioVDRefNum = vcbp->vcbDRefNum;
|
|
pb->volumeParam.ioVFSID = vcbp->vcbFSID;
|
|
pb->volumeParam.ioVBkUp = vcbp->vcbVolBkUp;
|
|
pb->volumeParam.ioVSeqNum = vcbp->vcbVSeqNum;
|
|
pb->volumeParam.ioVWrCnt = vcbp->vcbWrCnt;
|
|
pb->volumeParam.ioVFilCnt = vcbp->vcbFilCnt;
|
|
pb->volumeParam.ioVDirCnt = vcbp->vcbDirCnt;
|
|
BlockMove((Ptr) vcbp->vcbFndrInfo, (Ptr) pb->volumeParam.ioVFndrInfo,
|
|
(Size) sizeof(vcbp->vcbFndrInfo));
|
|
if (ISWDNUM(Cx(BootDrive))) {
|
|
wdp = WDNUMTOWDP(Cx(BootDrive));
|
|
if (MR(wdp->vcbp) == vcbp)
|
|
pb->volumeParam.ioVFndrInfo[1] = wdp->dirid;
|
|
}
|
|
}
|
|
return err;
|
|
}
|
|
|
|
A2(PUBLIC, OSErr, ufsPBSetVInfo, HParmBlkPtr, pb, /* INTERNAL */
|
|
BOOLEAN, a)
|
|
{
|
|
VCB *vcbp;
|
|
int ntocopy;
|
|
OSErr err;
|
|
BOOLEAN iswd;
|
|
INTEGER temp;
|
|
|
|
err = noErr;
|
|
|
|
if ((vcbp = findvcb(MR(pb->volumeParam.ioNamePtr), Cx(pb->volumeParam.ioVRefNum),
|
|
&iswd, &temp)) && !iswd) {
|
|
if (pb->volumeParam.ioNamePtr)
|
|
{
|
|
ntocopy = MIN(MR(pb->volumeParam.ioNamePtr)[0],
|
|
sizeof (vcbp->vcbVN)-1);
|
|
BlockMove((Ptr) MR(pb->volumeParam.ioNamePtr)+1,
|
|
(Ptr) vcbp->vcbVN+1,(Size) ntocopy);
|
|
vcbp->vcbVN[0] = ntocopy;
|
|
}
|
|
vcbp->vcbCrDate = pb->volumeParam.ioVCrDate;
|
|
vcbp->vcbLsMod = pb->volumeParam.ioVLsMod;
|
|
vcbp->vcbAtrb = pb->volumeParam.ioVAtrb;
|
|
vcbp->vcbClpSiz = pb->volumeParam.ioVClpSiz;
|
|
vcbp->vcbVolBkUp = pb->volumeParam.ioVBkUp;
|
|
vcbp->vcbVSeqNum = pb->volumeParam.ioVSeqNum;
|
|
BlockMove((Ptr) pb->volumeParam.ioVFndrInfo, (Ptr) vcbp->vcbFndrInfo,
|
|
(Size) sizeof(vcbp->vcbFndrInfo));
|
|
} else
|
|
err = nsvErr;
|
|
return err;
|
|
}
|
|
|
|
A2(PUBLIC, OSErr, ufsPBFlushVol, ParmBlkPtr, pb, /* INTERNAL */
|
|
BOOLEAN, a)
|
|
{
|
|
OSErr err = noErr;
|
|
|
|
if (!ROMlib_nosync)
|
|
sync();
|
|
return err;
|
|
}
|
|
|
|
/*
|
|
* TODO: think about what it really means to unmount a UNIX volume...
|
|
* we could probably free up some more memory if it's worth it.
|
|
*/
|
|
|
|
A1(PUBLIC, OSErr, ufsPBUnmountVol, ParmBlkPtr, pb) /* INTERNAL */
|
|
{
|
|
OSErr temp;
|
|
int i;
|
|
VCBExtra *vcbp;
|
|
|
|
temp = PBFlushVol(pb, FALSE);
|
|
for (i = 0; i < NFCB; i++)
|
|
if (ROMlib_fcblocks[i].fdfnum &&
|
|
MR(ROMlib_fcblocks[i].fcvptr)->vcbVRefNum == pb->ioParam.ioVRefNum)
|
|
FSClose(i*94+2);
|
|
if ((vcbp = (VCBExtra *) ROMlib_vcbbyvrn(Cx(pb->ioParam.ioVRefNum))))
|
|
ROMlib_dbm_close(vcbp);
|
|
if (temp != noErr)
|
|
return(temp);
|
|
else
|
|
return(nsDrvErr);
|
|
}
|
|
|
|
A1(PUBLIC, OSErr, ufsPBOffLine, ParmBlkPtr, pb) /* INTERNAL */
|
|
{
|
|
OSErr temp;
|
|
|
|
temp = PBFlushVol(pb, FALSE);
|
|
if (temp != noErr)
|
|
return(temp);
|
|
else
|
|
return(noErr);
|
|
}
|
|
|
|
A1(PUBLIC, OSErr, ufsPBEject, ParmBlkPtr, pb) /* INTERNAL */
|
|
{
|
|
OSErr temp;
|
|
|
|
temp = PBFlushFile(pb, FALSE);
|
|
if (temp != noErr)
|
|
return(temp);
|
|
temp = PBOffLine(pb);
|
|
if (temp != noErr)
|
|
return(temp);
|
|
return(nsDrvErr);
|
|
}
|