1782 lines
42 KiB
C
1782 lines
42 KiB
C
/* Copyright 1986-1996 by Abacus Research and
|
|
* Development, Inc. All rights reserved.
|
|
*/
|
|
|
|
#if !defined (OMIT_RCSID_STRINGS)
|
|
char ROMlib_rcsid_fileAccess[] =
|
|
"$Id: fileAccess.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 "DeviceMgr.h"
|
|
#include "MemoryMgr.h"
|
|
|
|
#include "rsys/hfs.h"
|
|
|
|
#include "rsys/file.h"
|
|
#include "rsys/glue.h"
|
|
#include "rsys/filedouble.h"
|
|
#include "rsys/segment.h"
|
|
#include "rsys/string.h"
|
|
#include "rsys/file.h"
|
|
#include "rsys/suffix_maps.h"
|
|
#include "rsys/lockunlock.h"
|
|
|
|
#include <ctype.h>
|
|
|
|
#if defined (CYGWIN32)
|
|
#include "winfs.h"
|
|
#endif
|
|
|
|
int ROMlib_nosync = 0; /* if non-zero, we don't call sync () or fsync () */
|
|
|
|
#if !defined(NDEBUG)
|
|
PUBLIC void fs_err_hook (OSErr err)
|
|
{
|
|
}
|
|
#endif
|
|
|
|
PUBLIC int ROMlib_lasterrnomapped;
|
|
|
|
#define MAX_ERRNO 50
|
|
|
|
#define install_errno(uerr, merr) \
|
|
do \
|
|
{ \
|
|
gui_assert(uerr < NELEM(xtable)); \
|
|
xtable[uerr] = merr; \
|
|
} \
|
|
while (FALSE);
|
|
|
|
A0(PUBLIC, OSErr, ROMlib_maperrno) /* INTERNAL */
|
|
{
|
|
OSErr retval;
|
|
static OSErr xtable[MAX_ERRNO + 1];
|
|
static char been_here = FALSE;
|
|
int errno_save;
|
|
|
|
if (!been_here)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < (int) NELEM(xtable); ++i)
|
|
xtable[i] = fsDSIntErr;
|
|
|
|
install_errno(0, noErr);
|
|
install_errno(EPERM, permErr);
|
|
install_errno(ENOENT, fnfErr);
|
|
install_errno(EIO, ioErr);
|
|
install_errno(ENXIO, paramErr);
|
|
install_errno(EBADF, fnOpnErr);
|
|
install_errno(EAGAIN, fLckdErr);
|
|
install_errno(ENOMEM, memFullErr);
|
|
install_errno(EACCES, permErr);
|
|
install_errno(EFAULT, paramErr);
|
|
install_errno(EBUSY, fBsyErr);
|
|
install_errno(EEXIST, dupFNErr);
|
|
install_errno(EXDEV, fsRnErr);
|
|
install_errno(ENODEV, nsvErr);
|
|
install_errno(ENOTDIR, dirNFErr);
|
|
install_errno(EINVAL, paramErr);
|
|
install_errno(ENFILE, tmfoErr);
|
|
install_errno(EMFILE, tmfoErr);
|
|
install_errno(EFBIG, dskFulErr);
|
|
install_errno(ENOSPC, dskFulErr);
|
|
install_errno(ESPIPE, posErr);
|
|
install_errno(EROFS, wPrErr);
|
|
install_errno(EMLINK, dirFulErr);
|
|
#if !defined(MSDOS) && !defined(CYGWIN32)
|
|
install_errno(ETXTBSY, fBsyErr);
|
|
install_errno(EWOULDBLOCK,permErr);
|
|
#endif
|
|
|
|
been_here = TRUE;
|
|
}
|
|
|
|
errno_save = errno;
|
|
ROMlib_lasterrnomapped = errno_save;
|
|
|
|
if (errno_save < 0 || errno_save >= (int) NELEM(xtable))
|
|
retval = fsDSIntErr;
|
|
else
|
|
retval = xtable[errno_save];
|
|
|
|
if (retval == fsDSIntErr)
|
|
warning_unexpected ("fsDSIntErr errno = %d", errno_save);
|
|
|
|
if (retval == dirNFErr)
|
|
warning_trace_info ("dirNFErr errno = %d", errno_save);
|
|
|
|
fs_err_hook (retval);
|
|
return retval;
|
|
}
|
|
|
|
A3(PUBLIC, OSErr, FSOpen, StringPtr, filen, INTEGER, vrn, /* IMIV-109 */
|
|
INTEGER *, rn)
|
|
{
|
|
ParamBlockRec pbr;
|
|
OSErr temp;
|
|
|
|
pbr.ioParam.ioNamePtr = RM(filen);
|
|
pbr.ioParam.ioVRefNum = CW(vrn);
|
|
pbr.ioParam.ioVersNum = 0;
|
|
pbr.ioParam.ioPermssn = fsCurPerm;
|
|
pbr.ioParam.ioMisc = 0;
|
|
temp = PBOpen(&pbr, 0);
|
|
*rn = CW(pbr.ioParam.ioRefNum);
|
|
fs_err_hook (temp);
|
|
return(temp);
|
|
}
|
|
|
|
A3(PUBLIC, OSErr, OpenRF, StringPtr, filen, INTEGER, vrn, /* IMIV-109 */
|
|
INTEGER *, rn)
|
|
{
|
|
ParamBlockRec pbr;
|
|
OSErr temp;
|
|
|
|
pbr.ioParam.ioNamePtr = RM(filen);
|
|
pbr.ioParam.ioVRefNum = CW(vrn);
|
|
pbr.ioParam.ioVersNum = 0;
|
|
pbr.ioParam.ioPermssn = fsCurPerm;
|
|
pbr.ioParam.ioMisc = 0;
|
|
temp = PBOpenRF(&pbr, 0);
|
|
*rn = CW(pbr.ioParam.ioRefNum);
|
|
fs_err_hook (temp);
|
|
return(temp);
|
|
}
|
|
|
|
A3(PUBLIC, OSErr, FSRead, INTEGER, rn, LONGINT *, count, /* IMIV-109 */
|
|
Ptr, buffp)
|
|
{
|
|
ParamBlockRec pbr;
|
|
OSErr temp;
|
|
|
|
pbr.ioParam.ioRefNum = CW(rn);
|
|
pbr.ioParam.ioBuffer = RM(buffp);
|
|
pbr.ioParam.ioReqCount = CL(*count);
|
|
pbr.ioParam.ioPosMode = CWC(fsAtMark);
|
|
temp = PBRead(&pbr, 0);
|
|
*count = CL(pbr.ioParam.ioActCount);
|
|
fs_err_hook (temp);
|
|
return(temp);
|
|
}
|
|
|
|
PUBLIC OSErr
|
|
FSReadAll (INTEGER rn, LONGINT *countp, Ptr buffp)
|
|
{
|
|
LONGINT orig_count;
|
|
OSErr retval;
|
|
|
|
orig_count = *countp;
|
|
retval = FSRead (rn, countp, buffp);
|
|
if (retval == noErr && *countp != orig_count)
|
|
retval = eofErr;
|
|
return retval;
|
|
}
|
|
|
|
A3(PUBLIC, OSErr, FSWrite, INTEGER, rn, LONGINT *, count, /* IMIV-110 */
|
|
Ptr, buffp)
|
|
{
|
|
ParamBlockRec pbr;
|
|
OSErr temp;
|
|
|
|
pbr.ioParam.ioRefNum = CW(rn);
|
|
pbr.ioParam.ioBuffer = RM(buffp);
|
|
pbr.ioParam.ioReqCount = CL(*count);
|
|
pbr.ioParam.ioPosMode = CWC(fsAtMark);
|
|
temp = PBWrite(&pbr, 0);
|
|
*count = CL(pbr.ioParam.ioActCount);
|
|
fs_err_hook (temp);
|
|
return(temp);
|
|
}
|
|
|
|
PUBLIC OSErr
|
|
FSWriteAll (INTEGER rn, LONGINT *countp, Ptr buffp)
|
|
{
|
|
LONGINT orig_count;
|
|
OSErr retval;
|
|
|
|
orig_count = *countp;
|
|
retval = FSWrite (rn, countp, buffp);
|
|
if (retval == noErr && *countp != orig_count)
|
|
retval = ioErr;
|
|
return retval;
|
|
}
|
|
|
|
A2(PUBLIC, OSErr, GetFPos, INTEGER, rn, LONGINT *, filep) /* IMIV-110 */
|
|
{
|
|
ParamBlockRec pbr;
|
|
OSErr temp;
|
|
|
|
pbr.ioParam.ioRefNum = CW(rn);
|
|
temp = PBGetFPos(&pbr, 0);
|
|
*filep = CL(pbr.ioParam.ioPosOffset);
|
|
fs_err_hook (temp);
|
|
return(temp);
|
|
}
|
|
|
|
A3(PUBLIC, OSErr, SetFPos, INTEGER, rn, INTEGER, posmode, /* IMIV-110 */
|
|
LONGINT, possoff)
|
|
{
|
|
ParamBlockRec pbr;
|
|
OSErr err;
|
|
|
|
pbr.ioParam.ioRefNum = CW(rn);
|
|
pbr.ioParam.ioPosMode = CW(posmode);
|
|
pbr.ioParam.ioPosOffset = Cx(possoff);
|
|
err = PBSetFPos(&pbr, 0);
|
|
fs_err_hook (err);
|
|
return err;
|
|
}
|
|
|
|
A2(PUBLIC, OSErr, GetEOF, INTEGER, rn, LONGINT *, eof) /* IMIV-111 */
|
|
{
|
|
ParamBlockRec pbr;
|
|
OSErr temp;
|
|
|
|
pbr.ioParam.ioRefNum = Cx(rn);
|
|
temp = PBGetEOF(&pbr, 0);
|
|
*eof = CL(pbr.ioParam.ioMisc);
|
|
fs_err_hook (temp);
|
|
return(temp);
|
|
}
|
|
|
|
A2(PUBLIC, OSErr, SetEOF, INTEGER, rn, LONGINT, eof) /* IMIV-111 */
|
|
{
|
|
ParamBlockRec pbr;
|
|
OSErr err;
|
|
|
|
pbr.ioParam.ioRefNum = Cx(rn);
|
|
pbr.ioParam.ioMisc = Cx(eof);
|
|
err = PBSetEOF(&pbr, 0);
|
|
fs_err_hook (err);
|
|
return (err);
|
|
}
|
|
|
|
A2(PUBLIC, OSErr, Allocate, INTEGER, rn, LONGINT *, count) /* IMIV-112 */
|
|
{
|
|
ParamBlockRec pbr;
|
|
OSErr temp;
|
|
|
|
pbr.ioParam.ioRefNum = Cx(rn);
|
|
pbr.ioParam.ioReqCount = *count;
|
|
temp = PBAllocate(&pbr, 0);
|
|
*count = CL(pbr.ioParam.ioActCount);
|
|
fs_err_hook (temp);
|
|
return(temp);
|
|
}
|
|
|
|
A2(PUBLIC, OSErr, AllocContig, INTEGER, rn, LONGINT *, count)
|
|
{
|
|
ParamBlockRec pbr;
|
|
OSErr temp;
|
|
|
|
pbr.ioParam.ioRefNum = Cx(rn);
|
|
pbr.ioParam.ioReqCount = *count;
|
|
temp = PBAllocContig(&pbr, 0);
|
|
*count = CL(pbr.ioParam.ioActCount);
|
|
fs_err_hook (temp);
|
|
return(temp);
|
|
}
|
|
|
|
A1(PUBLIC, OSErr, FSClose, INTEGER, rn) /* IMIV-112 */
|
|
{
|
|
ParamBlockRec pbr;
|
|
OSErr err;
|
|
|
|
pbr.ioParam.ioRefNum = Cx(rn);
|
|
err = PBClose(&pbr, 0);
|
|
fs_err_hook (err);
|
|
return err;
|
|
}
|
|
|
|
A2(PUBLIC, VCB *, vlookupbyname, const char *, namep, const char *, endp)
|
|
{
|
|
VCB *retval;
|
|
int n;
|
|
|
|
n = endp - namep;
|
|
for (retval = (VCB *)MR(VCBQHdr.qHead); retval;
|
|
retval = (VCB *) MR(retval->qLink))
|
|
if (n == retval->vcbVN[0] &&
|
|
strncmp(namep, (char *) retval->vcbVN+1, n) == 0)
|
|
return retval;
|
|
|
|
#if defined (MSDOS) || defined (CYGWIN32)
|
|
for (retval = (VCB *)MR(VCBQHdr.qHead); retval;
|
|
retval = (VCB *) MR(retval->qLink))
|
|
if (n == retval->vcbVN[0] &&
|
|
strncasecmp(namep, (char *) retval->vcbVN+1, n) == 0)
|
|
return retval;
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
A1(PRIVATE, VCB *, vlookupbydrive, INTEGER, drive)
|
|
{
|
|
VCB *retval;
|
|
|
|
for (retval = (VCB *)MR(VCBQHdr.qHead); retval;
|
|
retval = (VCB *) MR(retval->qLink))
|
|
if (drive == Cx(retval->vcbDrvNum))
|
|
return retval;
|
|
return 0;
|
|
}
|
|
|
|
PRIVATE LONGINT cacheindex = 0x7fffffff;
|
|
|
|
A0(PUBLIC, void, ROMlib_rewinddir)
|
|
{
|
|
cacheindex = 0x7fffffff;
|
|
}
|
|
|
|
/*
|
|
* Blech! I've finally caved in and am going to look for the magic
|
|
* number in the obnoxious case of a file that starts with %XX where XX
|
|
* are two upper case hex digits.
|
|
*/
|
|
|
|
PUBLIC BOOLEAN ROMlib_isresourcefork(const char *fullname)
|
|
{
|
|
LONGINT fd;
|
|
LONGINT magic;
|
|
BOOLEAN retval;
|
|
const char *filename;
|
|
|
|
/* netatalk_conventions_p means we never see resource forks, because
|
|
they're stored in a subdirectory */
|
|
|
|
if (netatalk_conventions_p)
|
|
retval = FALSE;
|
|
else
|
|
{
|
|
filename = strrchr(fullname, '/');
|
|
if (!filename)
|
|
filename = fullname;
|
|
else
|
|
++filename;
|
|
if (filename[0] != '%')
|
|
retval = FALSE;
|
|
else if (!isxdigit(filename[1]) || !isxdigit(filename[2]))
|
|
retval = TRUE;
|
|
else {
|
|
fd = -1;
|
|
retval = (fd = Uopen(fullname, O_BINARY|O_RDONLY, 0)) >= 0 &&
|
|
read(fd, (void *) &magic, sizeof(magic)) == sizeof(magic) &&
|
|
(magic == CLC(DOUBLEMAGIC)
|
|
|| magic == DOUBLEMAGIC);
|
|
if (fd >= 0)
|
|
Uclose(fd);
|
|
}
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
int ROMlib_no_dot_files = FALSE;
|
|
|
|
static boolean_t
|
|
dislike_name (char *namep)
|
|
{
|
|
boolean_t retval;
|
|
|
|
if (strcmp (namep, ".") == 0
|
|
|| strcmp (namep, "..") == 0
|
|
|| strcmp (namep, ".AppleDouble") == 0
|
|
|| strcmp (namep, ".AppleDesktop") == 0
|
|
|| (ROMlib_no_dot_files && namep[0] == '.'))
|
|
retval = TRUE;
|
|
else
|
|
{
|
|
char *buf;
|
|
int namelen;
|
|
|
|
namelen = strlen (namep);
|
|
buf = alloca (namelen);
|
|
memcpy (buf, namep, namelen);
|
|
namelen -= ROMlib_UNIX7_to_Mac (buf, namelen);
|
|
retval = namelen > 31;
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
A4(PRIVATE, char *, dirindex, char *, dir, LONGINT, index, BOOLEAN, nodirectories,
|
|
struct stat *, sbufp)
|
|
{
|
|
THz saveZone;
|
|
static char *cachedir = 0, *cachedirend;
|
|
static DIR *dirp = 0;
|
|
#if defined (USE_STRUCT_DIRECT)
|
|
struct direct *dp;
|
|
#else
|
|
struct dirent *dp;
|
|
#endif
|
|
int dirnamelen;
|
|
struct stat sbuf;
|
|
|
|
#if defined(MSDOS) || defined (CYGWIN32)
|
|
while (dir[0] == '/' && dir[1] == '/')
|
|
++dir;
|
|
#endif
|
|
|
|
if (!sbufp)
|
|
sbufp = &sbuf;
|
|
if (index <= cacheindex || !cachedir || strcmp(dir, cachedir) != 0) {
|
|
if (cachedir)
|
|
free (cachedir);
|
|
if (dirp)
|
|
closedir(dirp);
|
|
dirp = Uopendir(dir);
|
|
if (!dirp) {
|
|
dp = 0;
|
|
goto DONE;
|
|
}
|
|
cacheindex = 0;
|
|
dirnamelen = strlen(dir);
|
|
|
|
#if !defined(MAXNAMLEN)
|
|
#define MAXNAMLEN 1024
|
|
#endif /* !defined(MAXNAMLEN) */
|
|
|
|
saveZone = TheZone;
|
|
TheZone = SysZone;
|
|
cachedir = malloc (dirnamelen+1+MAXNAMLEN+1);
|
|
TheZone = saveZone;
|
|
if (!cachedir)
|
|
/*-->*/ return 0;
|
|
strcpy(cachedir, dir);
|
|
cachedirend = cachedir + dirnamelen;
|
|
}
|
|
*cachedirend = '/';
|
|
do {
|
|
if ((dp = readdir(dirp))) {
|
|
strcpy(cachedirend+1, dp->d_name);
|
|
if (!dislike_name (dp->d_name)
|
|
&& !ROMlib_isresourcefork(cachedir)
|
|
&& Ustat(cachedir, sbufp) == 0) {
|
|
if (!nodirectories || !S_ISDIR (sbufp->st_mode))
|
|
++cacheindex;
|
|
}
|
|
}
|
|
} while (dp && cacheindex != index);
|
|
*cachedirend = 0;
|
|
DONE:
|
|
return dp ? dp->d_name : 0;
|
|
}
|
|
|
|
/*
|
|
* NOTE: we must use capital letters in tohex below. Code depends on it.
|
|
*/
|
|
|
|
A1(PRIVATE, unsigned char, tohex, unsigned char, c)
|
|
{
|
|
unsigned char retval;
|
|
|
|
retval = (unsigned char) (netatalk_conventions_p ?
|
|
"0123456789abcdef"
|
|
:
|
|
"0123456789ABCDEF")[c & 0xF];
|
|
return retval;
|
|
}
|
|
|
|
A3(PRIVATE, INTEGER, Mac_to_UNIX7, unsigned char *, name, INTEGER, length,
|
|
unsigned char *, out)
|
|
{
|
|
unsigned char c;
|
|
INTEGER retval;
|
|
boolean_t last_character_was_colon;
|
|
|
|
retval = length;
|
|
last_character_was_colon = TRUE;
|
|
while (--length >= 0) {
|
|
c = *name++;
|
|
if (NEEDTOMAP(c)) {
|
|
*out++ = apple_double_quote_char;
|
|
*out++ = tohex(c >> 4);
|
|
*out++ = tohex(c);
|
|
retval += 2;
|
|
} else if (c == ':') {
|
|
if (last_character_was_colon)
|
|
{
|
|
*out++ = '.';
|
|
*out++ = '.';
|
|
retval += 2;
|
|
}
|
|
*out++ = '/';
|
|
} else
|
|
*out++ = c;
|
|
last_character_was_colon = c == ':';
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
A2(PUBLIC, char *, ROMlib_newunixfrommac, char *, ip, INTEGER, n)
|
|
{
|
|
char *retval;
|
|
|
|
if ((retval = malloc (3*n+1))) /* worst case numbers */
|
|
retval[Mac_to_UNIX7((unsigned char *) ip, n,
|
|
(unsigned char *) retval)] = 0;
|
|
return retval;
|
|
}
|
|
|
|
/*
|
|
* ROMlib_breakoutioname's role is to examine ioNamePtr and vRefNum
|
|
* to determine the vcbp, but since it has to look at ioNamePtr
|
|
* anyway it makes sense to make a unix partial pathname for the
|
|
* rest. While we're at it, if we get passed in a working-director
|
|
* instead of a TRUE vrn we might as well note the directory id
|
|
* that is associated with it.
|
|
*/
|
|
|
|
/*
|
|
* BUG Fix TODO: newunixfrommac needs to be more complex; specifically
|
|
* it needs to handle :: properly (which is to go up
|
|
* a directory, UNLESS it's already at the top).
|
|
*/
|
|
|
|
A5(PUBLIC, VCB *, ROMlib_breakoutioname, ParmBlkPtr, pb, /* INTERNAL */
|
|
LONGINT *, diridp, char **, therestp, BOOLEAN *, fullpathp,
|
|
BOOLEAN, usedefault)
|
|
{
|
|
VCB *retval;
|
|
char *colon;
|
|
unsigned char *p;
|
|
INTEGER v;
|
|
wdentry *wdp;
|
|
|
|
retval = 0;
|
|
*diridp = 0;
|
|
*therestp = 0;
|
|
if (fullpathp)
|
|
*fullpathp = FALSE;
|
|
if ((p = (unsigned char *) MR(pb->ioParam.ioNamePtr))) {
|
|
if (p[0] > 1 && p[1] != ':') {
|
|
if ((colon = pstr_index_after(p, ':', SLASH_CHAR_OFFSET))) {
|
|
retval = vlookupbyname((char *) p+1, colon);
|
|
if (colon - ((char *)p+1) < p[0])
|
|
*therestp =
|
|
ROMlib_newunixfrommac(colon+1,
|
|
p[0] + (char *) p - colon);
|
|
if (fullpathp)
|
|
*fullpathp = TRUE;
|
|
} else
|
|
*therestp = ROMlib_newunixfrommac((char *) p+1, p[0]);
|
|
} else if (p[0] > 0) {
|
|
if (p[1] == ':' || (p[0] == 1 && p[1] == '/'))
|
|
*therestp = ROMlib_newunixfrommac((char *)p+2, p[0]-1);
|
|
else
|
|
*therestp = ROMlib_newunixfrommac((char *)p+1, p[0]);
|
|
}
|
|
}
|
|
if (!retval) {
|
|
if ((v = Cx(pb->ioParam.ioVRefNum)) > 0) /* drive number */
|
|
retval = vlookupbydrive(v);
|
|
else if (v < 0) {
|
|
if (ISWDNUM(v)) {
|
|
wdp = WDNUMTOWDP(v);
|
|
*diridp = CL(wdp->dirid);
|
|
retval = MR(wdp->vcbp);
|
|
} else
|
|
retval = ROMlib_vcbbyvrn(v);
|
|
}
|
|
if (!retval && (usedefault ||
|
|
(!pb->ioParam.ioNamePtr && !pb->ioParam.ioVRefNum))) {
|
|
retval = MR(DefVCBPtr);
|
|
*diridp = CL(DefDirID);
|
|
}
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
/*
|
|
* myscandir looks through a directory for a filename match with case not
|
|
* significant. It returns TRUE if a match was found; FALSE
|
|
* otherwise. Note, the filename specified in "rest" starts
|
|
* out smashed and needs the character stored in "save" to
|
|
* be filled in before it can be used, but this has to be
|
|
* done after "dirname" has been used.
|
|
*/
|
|
|
|
A4(PRIVATE, BOOLEAN, myscandir, char *, dirname, char, save, char *, rest,
|
|
INTEGER, restlen)
|
|
{
|
|
DIR *dirp;
|
|
#if defined (USE_STRUCT_DIRECT)
|
|
struct direct *directp;
|
|
#else
|
|
struct dirent *directp;
|
|
#endif
|
|
int retval;
|
|
LONGINT d0;
|
|
|
|
#if defined(MSDOS) || defined (CYGWIN32)
|
|
while (dirname[0] == '/' && dirname[1] == '/')
|
|
++dirname;
|
|
#endif
|
|
|
|
retval = FALSE;
|
|
if ((dirp = Uopendir(dirname))) {
|
|
*rest = save;
|
|
d0 = ((LONGINT) restlen << 16) | (unsigned short) restlen;
|
|
while ((directp = readdir(dirp)))
|
|
if (restlen == (INTEGER) strlen (directp->d_name) &&
|
|
ROMlib_RelString((unsigned char *) rest,
|
|
(unsigned char *) directp->d_name, FALSE, TRUE, d0) == 0) {
|
|
retval = TRUE;
|
|
memcpy(rest, directp->d_name, restlen);
|
|
/*-->*/ break;
|
|
}
|
|
closedir(dirp);
|
|
} else
|
|
*rest = save;
|
|
return retval;
|
|
}
|
|
|
|
A2(PRIVATE, LONGINT, weasel, char *, fullpathname, struct stat *, sbufp)
|
|
{
|
|
char *start, *nextslash, save;
|
|
INTEGER length;
|
|
LONGINT retval;
|
|
|
|
#if 1
|
|
gui_assert(fullpathname[SLASH_CHAR_OFFSET] == '/');
|
|
#else
|
|
if (fullpathname[SLASH_CHAR_OFFSET] != '/')
|
|
{
|
|
DEBUG_OUT("weasel surprise %s", fullpathname);
|
|
*(long *) -1 = -1;
|
|
}
|
|
#endif
|
|
|
|
if (Ustat(fullpathname, sbufp) < 0) {
|
|
switch(errno) {
|
|
#if !defined (CYGWIN32)
|
|
case ENOENT:
|
|
#if 0
|
|
/* this will only work on systems that distinguish
|
|
between ENOENT and ENOTDIR ... maybe it won't work
|
|
at all. It doesn't work under Linux, so omit it
|
|
for now */
|
|
start = strrchr(fullpathname, '/') + 1;
|
|
break;
|
|
#endif
|
|
case ENOTDIR:
|
|
start = fullpathname + SLASH_CHAR_OFFSET + 1;
|
|
break;
|
|
#endif
|
|
default:
|
|
return errno;
|
|
break;
|
|
}
|
|
} else
|
|
return 0;
|
|
do {
|
|
nextslash = strchr(start, '/');
|
|
if (nextslash)
|
|
length = nextslash - start;
|
|
else
|
|
length = strlen(start);
|
|
save = *start;
|
|
*start = 0;
|
|
if (!myscandir(fullpathname, save, start, length)) {
|
|
return nextslash ? ENOTDIR : ENOENT;
|
|
}
|
|
start = nextslash + 1;
|
|
} while (nextslash);
|
|
if (Ustat(fullpathname, sbufp) < 0)
|
|
{
|
|
retval = errno;
|
|
return retval;
|
|
}
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* NOTE: As of today, ROMlib_nami always either returns an error, or leaves
|
|
* a valid result in *sbufp (if sbufp is non-zero). That means that
|
|
* you can call ROMlib_nami and not have to do a stat afterward.
|
|
*/
|
|
|
|
A9(PUBLIC, OSErr, ROMlib_nami, ParmBlkPtr, pb, LONGINT, dir, /* INTERNAL */
|
|
IndexType, indextype, char **, pathname, char **, filename,
|
|
char **, endname, BOOLEAN, nodirs, VCBExtra **, vcbpp, struct stat *, sbufp)
|
|
{
|
|
char *temp1, *temp2, *temp3;
|
|
INTEGER index;
|
|
StringPtr fnamep;
|
|
Str255 fname;
|
|
LONGINT dirid;
|
|
char *therest;
|
|
char *fn;
|
|
VCBExtra *vcbp;
|
|
datum content;
|
|
char *vcbanddir;
|
|
int vcbstrlen, therestlen;
|
|
StringPtr savenamep;
|
|
BOOLEAN fullp;
|
|
struct stat sbuf;
|
|
INTEGER badness;
|
|
OSErr err;
|
|
ALLOCABEGIN
|
|
|
|
if (!pathname)
|
|
pathname = &temp1;
|
|
if (!filename)
|
|
filename = &temp2;
|
|
if (!endname)
|
|
endname = &temp3;
|
|
fnamep = 0;
|
|
if (indextype != NoIndex) {
|
|
savenamep = MR(pb->ioParam.ioNamePtr);
|
|
pb->ioParam.ioNamePtr = 0;
|
|
}
|
|
#if !defined (LETGCCWAIL)
|
|
else
|
|
savenamep = (StringPtr) -1;
|
|
#endif /* LETGCCWAIL */
|
|
vcbp = (VCBExtra *) ROMlib_breakoutioname(pb, &dirid, &therest, &fullp,
|
|
TRUE);
|
|
if (vcbpp)
|
|
*vcbpp = vcbp;
|
|
if (fullp)
|
|
dir = 0;
|
|
else {
|
|
if (dir <= 0)
|
|
dir = dirid;
|
|
}
|
|
content.dsize = 0;
|
|
/*
|
|
* Retry strategy:
|
|
* first time things don't work we try closing and reopening
|
|
* the database (badness == 1); second time we try closing,
|
|
* rebuilding and reopening the database (badness == 2).
|
|
*/
|
|
badness = 0;
|
|
/* do { */
|
|
loop:
|
|
if (dir > 2) {
|
|
content = ROMlib_dbm_fetch(vcbp, dir);
|
|
if (!content.dptr)
|
|
{
|
|
content.dsize = 0;
|
|
}
|
|
}
|
|
vcbstrlen = strlen(vcbp->unixname);
|
|
vcbanddir = ALLOCA(vcbstrlen + content.dsize + 2);
|
|
BlockMove((Ptr) vcbp->unixname, (Ptr) vcbanddir, (Size) vcbstrlen+1);
|
|
if (content.dsize) {
|
|
if (vcbanddir[vcbstrlen-1] != '/')
|
|
{
|
|
vcbanddir[vcbstrlen] = '/';
|
|
++vcbstrlen;
|
|
}
|
|
BlockMove((Ptr) content.dptr, (Ptr) vcbanddir+vcbstrlen,
|
|
(Size) content.dsize);
|
|
vcbanddir[vcbstrlen+content.dsize] = 0;
|
|
if (Ustat(vcbanddir, &sbuf) < 0)
|
|
{
|
|
warning_unexpected ("vcbanddir = '%s', dir = 0x%x",
|
|
vcbanddir, dir);
|
|
ROMlib_dbm_delete_inode(vcbp, dir);
|
|
/*-->*/ goto loop;
|
|
}
|
|
else if (ST_INO(sbuf) != dir)
|
|
{
|
|
#if 1
|
|
warning_unexpected ("ST_INO(sbuf) = 0x%lx, dir = 0x%x",
|
|
(unsigned long) ST_INO(sbuf), dir);
|
|
ROMlib_dbm_delete_inode(vcbp, dir);
|
|
{
|
|
LONGINT templong;
|
|
|
|
templong = ST_INO(sbuf);
|
|
ROMlib_dbm_store(vcbp, vcbanddir, &templong, TRUE);
|
|
}
|
|
/*-->*/ goto loop;
|
|
#else
|
|
fprintf(stderr, "ino mismatch %s %ld %d\n", vcbanddir,
|
|
(long)ST_INO(sbuf), dir);
|
|
++badness;
|
|
#endif
|
|
}
|
|
else
|
|
badness = 0;
|
|
} else if (dir > 2)
|
|
++badness;
|
|
if (badness == 1 && dirid)
|
|
{
|
|
dir = dirid;
|
|
badness = 2;
|
|
goto loop;
|
|
}
|
|
if (badness && badness <= 1)
|
|
goto loop;
|
|
/* } while (badness && badness <= 1); */
|
|
if (badness)
|
|
{
|
|
err = dirNFErr;
|
|
warning_trace_info ("badness = %d, dirid = %d, dir = %d, "
|
|
"vcbp->unixname = '%s', therest = '%s', "
|
|
"fullp = %d, vcbanddir = '%s'",
|
|
badness, dirid, dir,
|
|
vcbp->unixname, therest, fullp, vcbanddir);
|
|
fs_err_hook (err);
|
|
free (therest);
|
|
/*-->*/ return err;
|
|
}
|
|
if (indextype != NoIndex)
|
|
pb->ioParam.ioNamePtr = RM(savenamep);
|
|
if (indextype == FDirIndex && (index = Cx(pb->fileParam.ioFDirIndex)) > 0) {
|
|
free (therest);
|
|
therest = 0;
|
|
if (!(fn = dirindex(vcbanddir, index, nodirs, sbufp))) {
|
|
ALLOCAEND
|
|
err = fnfErr;
|
|
fs_err_hook (err);
|
|
/*-->*/ return err;
|
|
}
|
|
if (pb->ioParam.ioNamePtr)
|
|
fnamep = MR(pb->ioParam.ioNamePtr);
|
|
else
|
|
fnamep = fname;
|
|
fnamep[0] = strlen(fn);
|
|
strcpy((char *) fnamep+1, fn);
|
|
#if 0
|
|
therest = ROMlib_newunixfrommac((char *) fnamep+1, fnamep[0]);
|
|
#else
|
|
therest = malloc ((Size) fnamep[0] + 1);
|
|
BlockMove((Ptr) fnamep+1, (Ptr) therest, (Size) fnamep[0]);
|
|
therest[fnamep[0]] = 0;
|
|
#endif
|
|
}
|
|
therestlen = therest ? strlen(therest) : 0;
|
|
*pathname = malloc (therestlen + strlen(vcbanddir)+2);
|
|
*filename = *pathname + strlen(vcbanddir) +1;
|
|
*endname = *filename + therestlen + 1;
|
|
BlockMove((Ptr) vcbanddir, (Ptr) *pathname, (Size) strlen(vcbanddir));
|
|
if (therest) {
|
|
if (vcbanddir[1 + SLASH_CHAR_OFFSET]) /* i.e. test for "/" */
|
|
(*filename)[-1] = '/';
|
|
else {
|
|
--*filename;
|
|
--*endname;
|
|
}
|
|
BlockMove((Ptr) therest, (Ptr) *filename, (Size) therestlen);
|
|
(*endname)[-1] = 0;
|
|
} else {
|
|
*endname = *filename;
|
|
(*endname)[-1] = 0;
|
|
}
|
|
if (strcmp(*pathname + SLASH_CHAR_OFFSET, "/") != 0) {
|
|
while ((*endname)[-2] == '/') { /* remove trailing slashes */
|
|
(*endname)[-2] = 0;
|
|
--*endname;
|
|
}
|
|
if ((*filename = strrchr(*pathname, '/')))
|
|
++*filename;
|
|
else
|
|
*filename = *pathname;
|
|
} else
|
|
*filename = *pathname;
|
|
if (therest)
|
|
free (therest);
|
|
ALLOCAEND
|
|
if (indextype == NoIndex && sbufp) {
|
|
errno = weasel(*pathname, sbufp);
|
|
err = ROMlib_maperrno();
|
|
} else if (indextype == IGNORENAME && sbufp)
|
|
{
|
|
if (Ustat(*pathname, sbufp) < 0)
|
|
{
|
|
err = ROMlib_maperrno();
|
|
}
|
|
else
|
|
err = noErr;
|
|
}
|
|
else
|
|
err = noErr;
|
|
fs_err_hook (err);
|
|
if (err == noErr && fullp)
|
|
ROMlib_automount (*pathname);
|
|
return err;
|
|
}
|
|
|
|
/*
|
|
* Old algorithm:
|
|
*
|
|
* The new code is a little bit tricky; it would be just prepend a %, except
|
|
* if someone has a name that begins with two hex digits ("feed me") you would
|
|
* get something that could be a data fork, so we make sure that if the first
|
|
* char is a % and the next two are hex and the hex would make something that
|
|
* we would have wanted to map then we map the second character even though
|
|
* we normally wouldn't map it.
|
|
*
|
|
* New algorithm:
|
|
*
|
|
* We just prepend the bloody "%" -- We get into trouble with other providers
|
|
* of Apple Double if we do it differently. What a crock.
|
|
*/
|
|
|
|
#define ROOTS_PERCENT_FILE "%%2F"
|
|
|
|
A3(PUBLIC, char *, ROMlib_resname, char *, pathname, /* INTERNAL */
|
|
char *, filename, char *, endname)
|
|
{
|
|
int pathnamesize, filenamesize, newsize;
|
|
char *newname;
|
|
|
|
pathnamesize = filename - pathname;
|
|
filenamesize = endname - filename;
|
|
if (pathnamesize)
|
|
{
|
|
newsize = pathnamesize + filenamesize
|
|
+ apple_double_fork_prefix_length;
|
|
newname = malloc (newsize);
|
|
memcpy (newname, pathname, pathnamesize);
|
|
strcpy (&newname[pathnamesize], apple_double_fork_prefix);
|
|
memcpy (newname + pathnamesize + apple_double_fork_prefix_length,
|
|
filename, filenamesize);
|
|
}
|
|
else
|
|
{
|
|
/* "E:/" --> "E:/%%2F" */
|
|
newsize = filenamesize + sizeof (ROOTS_PERCENT_FILE);
|
|
newname = malloc (newsize);
|
|
sprintf (newname, "%s%s", filename, ROOTS_PERCENT_FILE);
|
|
}
|
|
return newname;
|
|
}
|
|
|
|
/*
|
|
* macopen opens the file using mac permissions, returning an OSErr
|
|
* the file descriptor of the opened file is filled in where fdp points
|
|
*/
|
|
|
|
A5(PRIVATE, OSErr, macopen, char *, file, short, perm, LONGINT *, fdp,
|
|
BOOLEAN, isres, Byte *,flagp)
|
|
{
|
|
int newperm;
|
|
int flockret;
|
|
boolean_t open_should_fail_p;
|
|
OSErr err;
|
|
|
|
switch (perm) {
|
|
default:
|
|
warning_unexpected ("perm = %d", perm);
|
|
/* FALL THROUGH */
|
|
case fsCurPerm:
|
|
newperm = O_RDWR; /* start out here, downgrade if necessary */
|
|
*flagp |= fcwriteperm;
|
|
break;
|
|
case fsRdPerm:
|
|
newperm = O_RDONLY;
|
|
break;
|
|
case fsWrPerm:
|
|
*flagp |= fcwriteperm;
|
|
newperm = isres ? O_RDWR : O_WRONLY;
|
|
break;
|
|
case fsRdWrPerm:
|
|
*flagp |= fcwriteperm;
|
|
newperm = O_RDWR;
|
|
break;
|
|
case fsRdWrShPerm:
|
|
*flagp |= fcwriteperm;
|
|
newperm = O_RDWR;
|
|
break;
|
|
}
|
|
|
|
#if defined(MSDOS)
|
|
#define BROKEN_OPEN
|
|
#endif
|
|
|
|
#if defined(BROKEN_OPEN)
|
|
{
|
|
struct stat sbuf;
|
|
|
|
open_should_fail_p = ((newperm == O_WRONLY || newperm == O_RDWR)
|
|
&& Ustat(file, &sbuf) == 0
|
|
&& (!(sbuf.st_mode & S_IWUSR)));
|
|
}
|
|
#else
|
|
open_should_fail_p = FALSE;
|
|
#endif
|
|
if (open_should_fail_p)
|
|
*fdp = -1;
|
|
else
|
|
*fdp = Uopen(file, O_BINARY|newperm, 0);
|
|
if (*fdp == -1 && perm == fsCurPerm) {
|
|
*fdp = Uopen(file, O_BINARY|O_RDONLY, 0);
|
|
*flagp &= ~fcwriteperm;
|
|
}
|
|
flockret = 0;
|
|
#if !defined(AVIION) && !defined(MACBLITZ) && 0
|
|
if (*fdp != -1) {
|
|
if (perm == fsCurPerm || perm == fsRdWrPerm)
|
|
flockret = flock(*fdp, LOCK_EX|LOCK_NB);
|
|
if (perm == fsRdWrShPerm || (perm == fsCurPerm && flockret == -1))
|
|
flockret = flock(*fdp, LOCK_SH|LOCK_NB);
|
|
if (flockret == -1 && perm != fsCurPerm) {
|
|
Uclose(*fdp);
|
|
*fdp = flockret;
|
|
}
|
|
}
|
|
#endif /* !defined(AVIION) */
|
|
err = *fdp == -1 ? ROMlib_maperrno(): noErr;
|
|
fs_err_hook (err);
|
|
return err;
|
|
}
|
|
|
|
A1(PRIVATE, void, freeprn, fcbrec *, fp)
|
|
{
|
|
fp->fdfnum = 0;
|
|
}
|
|
|
|
A1(PRIVATE, OSErr, getprn, INTEGER *, pprn)
|
|
{
|
|
INTEGER length;
|
|
fcbrec *fcbp, *efcbp;
|
|
OSErr err;
|
|
|
|
/* #define NASTYTEMPHAXK */
|
|
#if defined(NASTYTEMPHAXK) && defined(MSDOS)
|
|
static int n = 0;
|
|
*pprn = 2 + 94 * n++;
|
|
return noErr;
|
|
#endif
|
|
length =CW( *(short *)MR(FCBSPtr));
|
|
fcbp = (fcbrec *) ((short *)MR(FCBSPtr)+1);
|
|
efcbp = (fcbrec *) ((char *)MR(FCBSPtr) + length);
|
|
for (;fcbp < efcbp && fcbp->fdfnum;
|
|
fcbp = (fcbrec *) ((char *)fcbp + Cx(FSFCBLen)))
|
|
;
|
|
if (fcbp < efcbp) {
|
|
*pprn = (char *) fcbp - (char *) MR(FCBSPtr);
|
|
err = noErr;
|
|
} else
|
|
err = tmfoErr;
|
|
fs_err_hook (err);
|
|
return err;
|
|
}
|
|
|
|
A4(PRIVATE, OSErr, PBOpenForkD, ParmBlkPtr, pb, BOOLEAN, a,
|
|
ForkType, fork, LONGINT, dir)
|
|
{
|
|
OSErr err;
|
|
int temp;
|
|
INTEGER prn;
|
|
char *pathname, *filename, *endname, *newname;
|
|
struct stat sbuf;
|
|
VCBExtra *vcbp;
|
|
int namelen;
|
|
fcbrec *fp;
|
|
THz savezone;
|
|
int save_index;
|
|
char save_char;
|
|
char *need_to_free;
|
|
|
|
need_to_free = 0;
|
|
pb->ioParam.ioRefNum = CWC(0); /* in case some goofy program,
|
|
like StuffIt Lite decides to
|
|
ignore error codes */
|
|
savezone = TheZone;
|
|
TheZone = SysZone;
|
|
pathname = 0;
|
|
/*
|
|
* We have to pass in sbuf below or we won't be weaseled like we should be.
|
|
*/
|
|
if ((err = ROMlib_nami(pb, dir, NoIndex, &pathname, &filename, &endname,
|
|
TRUE, &vcbp, (struct stat *) &sbuf)) == noErr) {
|
|
err = getprn(&prn);
|
|
if (err == noErr) {
|
|
fp = (fcbrec *) (MR(FCBSPtr) + prn);
|
|
fp->fdfnum = CL((LONGINT) ST_INO(sbuf));
|
|
fp->fcfd = -1;
|
|
fp->fcflags = 0;
|
|
fp->fcbTypByt = 0;
|
|
fp->fcbCrPs = 0;
|
|
if ((filename == pathname + 1) ||
|
|
(filename == pathname + SLASH_CHAR_OFFSET + 1))
|
|
save_index = 0; /* root ... don't scorch leading "/" */
|
|
else
|
|
save_index = -1;
|
|
save_char = filename[save_index];
|
|
filename[save_index] = 0;
|
|
if (Ustat(pathname, &sbuf) < 0) /* NOTE: this is a stat of */
|
|
err = ROMlib_maperrno(); /* the parent's directory, */
|
|
else { /* so ROMlib_nami won't do */
|
|
if (ST_INO(sbuf) == vcbp->u.ufs.ino) /* the stat for us */
|
|
fp->fcparid = CLC (2);
|
|
else
|
|
fp->fcparid = CL((LONGINT) ST_INO(sbuf));
|
|
filename[save_index] = save_char;
|
|
if (fork == ResourceFork) {
|
|
newname = ROMlib_resname(pathname, filename, endname);
|
|
temp = Ustat(newname, &sbuf);
|
|
if (temp < 0 && errno != ENOENT)
|
|
err = ioErr;
|
|
need_to_free = pathname; /* can't free it now, because
|
|
filename is drawn from
|
|
here */
|
|
pathname = newname;
|
|
}
|
|
}
|
|
if (err == noErr) {
|
|
err = macopen(pathname, pb->ioParam.ioPermssn,
|
|
&fp->fcfd, fork == ResourceFork, &fp->fcflags);
|
|
if (err != noErr
|
|
&& (fork != ResourceFork ||
|
|
(err = ROMlib_newresfork(pathname, &fp->fcfd, TRUE))))
|
|
freeprn(fp);
|
|
else {
|
|
if (fork == ResourceFork)
|
|
{
|
|
fp->fcflags |= fcfisres;
|
|
fp->hiddenfd = fp->fcfd;
|
|
lseek(fp->fcfd, ROMlib_FORKOFFSET(fp), L_SET);
|
|
}
|
|
else
|
|
{
|
|
newname = ROMlib_resname (pathname, filename,
|
|
endname);
|
|
fp->hiddenfd = Uopen (newname, O_BINARY|O_RDWR, 0666L);
|
|
if (fp->hiddenfd < 0)
|
|
{
|
|
Byte dummy_byte = -1;
|
|
|
|
if (errno == ENOENT)
|
|
{
|
|
if ((fp->fcflags & fcwriteperm) &&
|
|
!ROMlib_creator_and_type_from_filename
|
|
(strlen (filename), filename, NULL, NULL))
|
|
err = ROMlib_newresfork(newname,
|
|
&fp->hiddenfd, TRUE);
|
|
else
|
|
{
|
|
err = noErr;
|
|
fp->hiddenfd = -1;
|
|
}
|
|
}
|
|
else
|
|
macopen(newname, pb->ioParam.ioPermssn,
|
|
&fp->hiddenfd, TRUE, &dummy_byte);
|
|
}
|
|
free (newname);
|
|
}
|
|
if (err == noErr)
|
|
err = ROMlib_geteofostype(fp);
|
|
fp->fcvptr = RM((VCB *) vcbp);
|
|
pb->ioParam.ioRefNum = CW(prn);
|
|
namelen = strlen (filename);
|
|
namelen -= ROMlib_UNIX7_to_Mac (filename, namelen);
|
|
namelen = MIN(namelen, 31);
|
|
fp->fcname[0] = namelen;
|
|
BlockMove((Ptr) filename,
|
|
(Ptr) fp->fcname+1, (Size) namelen);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (need_to_free)
|
|
free (need_to_free);
|
|
|
|
if (pathname)
|
|
free (pathname);
|
|
TheZone = savezone;
|
|
fs_err_hook (err);
|
|
return err;
|
|
}
|
|
|
|
A2(PUBLIC, OSErr, ufsPBOpen, ParmBlkPtr, pb, BOOLEAN, a) /* INTERNAL */
|
|
{
|
|
OSErr err;
|
|
|
|
err = PBOpenForkD(pb, a, DataFork, 0);
|
|
fs_err_hook (err);
|
|
return err;
|
|
}
|
|
|
|
A2(PUBLIC, OSErr, ufsPBHOpen, HParmBlkPtr, pb, /* INTERNAL */
|
|
BOOLEAN, a) /* IMIV-136 */
|
|
{
|
|
OSErr err;
|
|
|
|
err = PBOpenForkD((ParmBlkPtr) pb, a, DataFork, CL(pb->fileParam.ioDirID));
|
|
fs_err_hook (err);
|
|
return err;
|
|
}
|
|
|
|
A2(PUBLIC trap, OSErrRET, OpenDeny, HParmBlkPtr, pb, /* IMV-397 */
|
|
BOOLEAN, a)
|
|
{ /* HACK */
|
|
HParamBlockRec block;
|
|
OSErr retval;
|
|
|
|
block.ioParam.ioCompletion = pb->ioParam.ioCompletion;
|
|
block.ioParam.ioNamePtr = pb->ioParam.ioNamePtr;
|
|
block.ioParam.ioVRefNum = pb->ioParam.ioVRefNum;
|
|
block.ioParam.ioVersNum = 0;
|
|
switch (pb->ioParam.ioPermssn & 3) {
|
|
case 0:
|
|
block.ioParam.ioPermssn = fsCurPerm;
|
|
break;
|
|
case 1:
|
|
block.ioParam.ioPermssn = fsRdPerm;
|
|
break;
|
|
case 2:
|
|
block.ioParam.ioPermssn = fsWrPerm;
|
|
break;
|
|
case 3:
|
|
block.ioParam.ioPermssn = fsRdWrPerm;
|
|
break;
|
|
}
|
|
block.ioParam.ioMisc = 0;
|
|
block.fileParam.ioDirID = pb->fileParam.ioDirID;
|
|
|
|
retval = PBHOpen(&block, a);
|
|
pb->ioParam.ioResult = block.ioParam.ioResult;
|
|
pb->ioParam.ioRefNum = block.ioParam.ioRefNum;
|
|
fs_err_hook (retval);
|
|
return retval;
|
|
}
|
|
|
|
A2(PUBLIC, OSErr, ufsPBOpenRF, ParmBlkPtr, pb, /* INTERNAL */
|
|
BOOLEAN, a)
|
|
{
|
|
OSErr err;
|
|
|
|
err = PBOpenForkD(pb, a, ResourceFork, 0);
|
|
fs_err_hook (err);
|
|
return err;
|
|
}
|
|
|
|
A2(PUBLIC, OSErr, ufsPBHOpenRF, HParmBlkPtr, pb, /* INTERNAL */
|
|
BOOLEAN, a)
|
|
{
|
|
OSErr err;
|
|
|
|
err = PBOpenForkD((ParmBlkPtr) pb, a, ResourceFork,
|
|
CL(pb->fileParam.ioDirID));
|
|
fs_err_hook (err);
|
|
return err;
|
|
}
|
|
|
|
#define POSMASK 0x3 /* IMIV-121 */
|
|
|
|
PRIVATE OSErr
|
|
pbfpos (ParmBlkPtr pb, LONGINT *toseekp, boolean_t can_go_past_eof)
|
|
{
|
|
OSErr err;
|
|
LONGINT leof;
|
|
INTEGER forkoffset;
|
|
LONGINT pos;
|
|
int fd;
|
|
fcbrec *fp;
|
|
|
|
fp = PRNTOFPERR(Cx(pb->ioParam.ioRefNum), &err);
|
|
if (err == noErr) {
|
|
forkoffset = FORKOFFSET(fp);
|
|
leof = Cx(fp->fcleof);
|
|
fd = fp->fcfd;
|
|
|
|
switch (Cx(pb->ioParam.ioPosMode) & POSMASK) {
|
|
case fsAtMark:
|
|
if ((pos = lseek(fd, 0L, L_INCR)) == -1) {
|
|
switch(errno) {
|
|
case EBADF:
|
|
err = fnOpnErr;
|
|
break;
|
|
case EINVAL:
|
|
err = paramErr;
|
|
break;
|
|
default:
|
|
err = ioErr;
|
|
}
|
|
} else
|
|
*toseekp = pos - forkoffset;
|
|
break;
|
|
case fsFromStart:
|
|
*toseekp = Cx(pb->ioParam.ioPosOffset);
|
|
break;
|
|
case fsFromLEOF:
|
|
*toseekp = leof + Cx(pb->ioParam.ioPosOffset);
|
|
break;
|
|
case fsFromMark:
|
|
if ((pos = lseek(fd, 0L, L_INCR)) == -1) {
|
|
switch(errno) {
|
|
case EBADF:
|
|
err = fnOpnErr;
|
|
break;
|
|
case EINVAL:
|
|
err = paramErr;
|
|
break;
|
|
default:
|
|
err = ioErr;
|
|
}
|
|
} else
|
|
*toseekp = pos + Cx(pb->ioParam.ioPosOffset) - forkoffset;
|
|
break;
|
|
}
|
|
if (*toseekp + forkoffset < 0) {
|
|
err = posErr;
|
|
*toseekp = 0;
|
|
} else if ((*toseekp > leof) && !can_go_past_eof) {
|
|
err = eofErr;
|
|
*toseekp = leof;
|
|
}
|
|
*toseekp += forkoffset;
|
|
}
|
|
fs_err_hook (err);
|
|
return err;
|
|
}
|
|
|
|
A3(PRIVATE, OSErr, PBLockUnlockRange, ParmBlkPtr, pb, BOOLEAN, a,
|
|
lockunlock_t, op)
|
|
{
|
|
OSErr err;
|
|
LONGINT toseek;
|
|
int fd;
|
|
LONGINT curseek;
|
|
fcbrec *fp;
|
|
|
|
err = noErr;
|
|
fp = PRNTOFPERR(Cx(pb->ioParam.ioRefNum), &err);
|
|
if (err == noErr) {
|
|
if ((err = pbfpos(pb, &toseek, TRUE)) == noErr) {
|
|
OSErr (*verify ) (int fd, uint32 start, uint32 count);
|
|
OSErr (*cleanup) (int fd, uint32 start, uint32 count);
|
|
|
|
fd = fp->fcfd;
|
|
curseek = lseek(fd, 0, L_SET);
|
|
|
|
if (op == lock)
|
|
{
|
|
verify = ROMlib_fd_range_overlap;
|
|
cleanup = ROMlib_fd_add_range;
|
|
}
|
|
else
|
|
{
|
|
verify = ROMlib_find_fd_start_count;
|
|
cleanup = ROMlib_fd_remove_range;
|
|
}
|
|
|
|
err = verify (fd, toseek, CL (pb->ioParam.ioReqCount));
|
|
if (err == noErr && lseek(fd, toseek, L_SET) == -1)
|
|
err = ROMlib_maperrno();
|
|
if (err == noErr)
|
|
err = ROMlib_lockunlockrange (fd, toseek,
|
|
CL (pb->ioParam.ioReqCount), op);
|
|
if (err == noErr)
|
|
err = cleanup (fd, toseek, CL (pb->ioParam.ioReqCount));
|
|
lseek(fd, curseek, L_SET);
|
|
}
|
|
}
|
|
fs_err_hook (err);
|
|
return err;
|
|
}
|
|
|
|
A2(PUBLIC, OSErr, ufsPBLockRange, ParmBlkPtr, pb, /* INTERNAL */
|
|
BOOLEAN, a)
|
|
{
|
|
OSErr err;
|
|
|
|
err = PBLockUnlockRange(pb, a, lock);
|
|
fs_err_hook (err);
|
|
return err;
|
|
}
|
|
|
|
A2(PUBLIC, OSErr, ufsPBUnlockRange, ParmBlkPtr, pb, /* INTERNAL */
|
|
BOOLEAN, a)
|
|
{
|
|
OSErr err;
|
|
|
|
err = PBLockUnlockRange(pb, a, unlock);
|
|
fs_err_hook (err);
|
|
return err;
|
|
}
|
|
|
|
PRIVATE OSErr
|
|
pbsetfpos (ParmBlkPtr pb, boolean_t can_go_past_eof)
|
|
{
|
|
OSErr err;
|
|
INTEGER forkoffset;
|
|
LONGINT toseek;
|
|
int fd;
|
|
fcbrec *fp;
|
|
|
|
fp = PRNTOFPERR(Cx(pb->ioParam.ioRefNum), &err);
|
|
if (err == noErr) {
|
|
forkoffset = FORKOFFSET(fp);
|
|
err = pbfpos(pb, &toseek, can_go_past_eof);
|
|
fd = fp->fcfd;
|
|
pb->ioParam.ioPosOffset = CL(lseek(fd, toseek, L_SET) - forkoffset);
|
|
}
|
|
fs_err_hook (err);
|
|
return err;
|
|
}
|
|
|
|
PUBLIC int ROMlib_newlinetocr = TRUE;
|
|
|
|
/*
|
|
* NOTE: ROMlib_destroy_blocks is a wrapper routine that either destroys
|
|
* a limited range or flushes the entire cache. Apple's semantics
|
|
* say that you must flush the entire cache in certain circumstances.
|
|
* However, 99% of all programs need to destroy only a range of
|
|
* addresses.
|
|
*/
|
|
|
|
PUBLIC int ROMlib_flushoften = 0;
|
|
|
|
PUBLIC unsigned long ROMlib_destroy_blocks(syn68k_addr_t start, uint32 count,
|
|
BOOLEAN flush_only_faulty_checksums)
|
|
{
|
|
unsigned long num_blocks_destroyed;
|
|
|
|
if (ROMlib_flushoften)
|
|
{
|
|
start = 0;
|
|
count = ~0;
|
|
}
|
|
if (count)
|
|
{
|
|
if (flush_only_faulty_checksums)
|
|
num_blocks_destroyed =
|
|
destroy_blocks_with_checksum_mismatch (start, count);
|
|
else
|
|
num_blocks_destroyed = destroy_blocks (start, count);
|
|
}
|
|
else
|
|
num_blocks_destroyed = 0;
|
|
|
|
return num_blocks_destroyed;
|
|
}
|
|
|
|
A2(PUBLIC, OSErr, ufsPBRead, ParmBlkPtr, pb, BOOLEAN, a) /* INTERNAL */
|
|
{
|
|
OSErr err;
|
|
LONGINT nread;
|
|
INTEGER forkoffset;
|
|
fcbrec *fp;
|
|
|
|
#if 0
|
|
if (pb->ioParam.ioRefNum == 0x5003)
|
|
{
|
|
printf ("read IN mode = %d, offset = %5d, req = %5d\n",
|
|
CW (pb->ioParam.ioPosMode),
|
|
CL (pb->ioParam.ioPosOffset), CL (pb->ioParam.ioReqCount));
|
|
}
|
|
#endif
|
|
|
|
if (Cx(pb->ioParam.ioRefNum) < 0)
|
|
{
|
|
err = ROMlib_dispatch(pb, a, Prime, aRdCmd);
|
|
fs_err_hook (err);
|
|
return err;
|
|
}
|
|
fp = PRNTOFPERR(Cx(pb->ioParam.ioRefNum), &err);
|
|
if (err == noErr && ((err = pbsetfpos(pb, FALSE)) == noErr || err == eofErr)) {
|
|
forkoffset = FORKOFFSET(fp);
|
|
if (Cx(pb->ioParam.ioReqCount) < 0)
|
|
err = paramErr;
|
|
else {
|
|
int fd = fp->fcfd;
|
|
LONGINT rc = Cx(pb->ioParam.ioReqCount);
|
|
|
|
if (Cx(pb->ioParam.ioPosOffset) + rc > Cx(fp->fcleof))
|
|
rc = Cx(fp->fcleof) - Cx(pb->ioParam.ioPosOffset);
|
|
nread = read(fd, (char *)(MR(pb->ioParam.ioBuffer)), rc);
|
|
ROMlib_destroy_blocks((syn68k_addr_t)
|
|
(long) US_TO_SYN68K(MR(pb->ioParam.ioBuffer)),
|
|
rc, TRUE);
|
|
if (nread == -1) {
|
|
pb->ioParam.ioActCount = 0;
|
|
err = ioErr;
|
|
} else {
|
|
pb->ioParam.ioActCount = CL(nread);
|
|
pb->ioParam.ioPosOffset = CL(lseek(fd, 0L, L_INCR) -
|
|
forkoffset);
|
|
if (rc != Cx(pb->ioParam.ioReqCount))
|
|
err = eofErr;
|
|
}
|
|
}
|
|
}
|
|
fs_err_hook (err);
|
|
#if 0
|
|
if (pb->ioParam.ioRefNum == 0x5003)
|
|
{
|
|
printf ("read OUT mode = %d, offset = %5d, req = %5d, act = %d, err = %d\n",
|
|
CW (pb->ioParam.ioPosMode),
|
|
CL (pb->ioParam.ioPosOffset), CL (pb->ioParam.ioReqCount),
|
|
CL (pb->ioParam.ioActCount),
|
|
err);
|
|
}
|
|
#endif
|
|
return err;
|
|
}
|
|
|
|
A2(PUBLIC, OSErr, ufsPBWrite, ParmBlkPtr, pb, BOOLEAN, a) /* INTERNAL */
|
|
{
|
|
OSErr err;
|
|
LONGINT nwrite, rc;
|
|
INTEGER forkoffset;
|
|
fcbrec *fp;
|
|
|
|
if (Cx(pb->ioParam.ioRefNum) < 0)
|
|
{
|
|
err = ROMlib_dispatch(pb, a, Prime, aWrCmd);
|
|
fs_err_hook (err);
|
|
return err;
|
|
}
|
|
fp = PRNTOFPERR(Cx(pb->ioParam.ioRefNum), &err);
|
|
if (err == noErr && ((err = pbsetfpos(pb, TRUE)) == noErr || err == eofErr)) {
|
|
forkoffset = FORKOFFSET(fp);
|
|
if ((rc = Cx(pb->ioParam.ioReqCount)) < 0)
|
|
err = paramErr;
|
|
else {
|
|
int fd = fp->fcfd;
|
|
#if defined (WEHAVEENOUGHSWAPSPACETORUNSUNSGOOFYLITTLERPCTHINGYS)
|
|
#if defined (SUN)
|
|
if (lockf(fd, F_TLOCK, rc))
|
|
err = fLckdErr;
|
|
#endif /* SUN */
|
|
#endif /* WEHAVEENOUGHSWAPSPACETORUNSUNSGOOFYLITTLERPCTHINGYS */
|
|
if (err == noErr && Cx(pb->ioParam.ioPosOffset) + rc > Cx(fp->fcleof)) {
|
|
fp->fcleof = CL(CL(pb->ioParam.ioPosOffset) + rc);
|
|
err = ROMlib_seteof(fp);
|
|
}
|
|
if (err == noErr) {
|
|
nwrite = write(fd, (char *)(MR(pb->ioParam.ioBuffer)), rc);
|
|
if (nwrite == -1) {
|
|
pb->ioParam.ioActCount = 0;
|
|
err = ioErr;
|
|
} else {
|
|
err = noErr;
|
|
pb->ioParam.ioActCount = CL(nwrite);
|
|
pb->ioParam.ioPosOffset = CL(lseek(fd, 0L, L_INCR) -
|
|
forkoffset);
|
|
if (Cx(pb->ioParam.ioPosOffset) > Cx(fp->fcleof)) {
|
|
fp->fcleof = pb->ioParam.ioPosOffset;
|
|
err = ROMlib_seteof(fp);
|
|
}
|
|
}
|
|
}
|
|
#if defined (WEHAVEENOUGHSWAPSPACETORUNSUNSGOOFYLITTLERPCTHINGYS)
|
|
#if defined (SUN)
|
|
lockf(fd, F_ULOCK, Cx(pb->ioParam.ioReqCount));
|
|
#endif /* SUN */
|
|
#endif /* WEHAVEENOUGHSWAPSPACETORUNSUNSGOOFYLITTLERPCTHINGYS */
|
|
}
|
|
}
|
|
fs_err_hook (err);
|
|
return err;
|
|
}
|
|
|
|
A2(PUBLIC, OSErr, ufsPBGetFPos, ParmBlkPtr, pb, /* INTERNAL */
|
|
BOOLEAN, a)
|
|
{
|
|
OSErr err;
|
|
INTEGER forkoffset;
|
|
fcbrec *fp;
|
|
|
|
fp = PRNTOFPERR(Cx(pb->ioParam.ioRefNum), &err);
|
|
if (err == noErr) {
|
|
forkoffset = FORKOFFSET(fp);
|
|
pb->ioParam.ioPosOffset = CL(lseek(fp->fcfd, 0L, L_INCR) -
|
|
forkoffset);
|
|
pb->ioParam.ioReqCount = pb->ioParam.ioActCount =
|
|
pb->ioParam.ioPosMode = 0;
|
|
}
|
|
fs_err_hook (err);
|
|
return err;
|
|
}
|
|
|
|
A2(PUBLIC, OSErr, ufsPBSetFPos, ParmBlkPtr, pb, /* INTERNAL */
|
|
BOOLEAN, a)
|
|
{
|
|
OSErr err = pbsetfpos(pb, FALSE);
|
|
|
|
#if 0
|
|
if (pb->ioParam.ioRefNum == 0x5003)
|
|
{
|
|
printf ("seek IN mode = %d, offset = %5d\n",
|
|
CW (pb->ioParam.ioPosMode),
|
|
CL (pb->ioParam.ioPosOffset));
|
|
}
|
|
#endif
|
|
|
|
if (err == noErr)
|
|
pb->ioParam.ioReqCount = pb->ioParam.ioActCount = 0;
|
|
fs_err_hook (err);
|
|
#if 0
|
|
if (pb->ioParam.ioRefNum == 0x5003)
|
|
{
|
|
printf ("seek OUT mode = %d, offset = %5d, err = %d\n",
|
|
CW (pb->ioParam.ioPosMode),
|
|
CL (pb->ioParam.ioPosOffset), err);
|
|
}
|
|
#endif
|
|
return err;
|
|
}
|
|
|
|
A2(PUBLIC, OSErr, ufsPBGetEOF, ParmBlkPtr, pb, BOOLEAN, a) /* INTERNAL */
|
|
{
|
|
fcbrec *fp;
|
|
OSErr err;
|
|
|
|
fp = PRNTOFPERR(Cx(pb->ioParam.ioRefNum), &err);
|
|
if (err == noErr)
|
|
pb->ioParam.ioMisc = fp->fcleof;
|
|
fs_err_hook (err);
|
|
return err;
|
|
}
|
|
|
|
A2(PUBLIC, OSErr, ufsPBSetEOF, ParmBlkPtr, pb, BOOLEAN, a) /* INTERNAL */
|
|
{
|
|
fcbrec *fp;
|
|
OSErr err;
|
|
|
|
fp = PRNTOFPERR(Cx(pb->ioParam.ioRefNum), &err);
|
|
if (err == noErr) {
|
|
fp->fcleof = pb->ioParam.ioMisc;
|
|
err = ROMlib_seteof(fp);
|
|
}
|
|
fs_err_hook (err);
|
|
return err;
|
|
}
|
|
|
|
A2(PUBLIC, OSErr, ufsPBAllocate, ParmBlkPtr, pb, /* INTERNAL */
|
|
BOOLEAN, a)
|
|
{
|
|
fcbrec *fp;
|
|
OSErr err;
|
|
|
|
fp = PRNTOFPERR(Cx(pb->ioParam.ioRefNum), &err);
|
|
if (err == noErr) {
|
|
fp->fcleof = CL(CL(fp->fcleof) + CL(pb->ioParam.ioReqCount));
|
|
err = ROMlib_seteof(fp);
|
|
pb->ioParam.ioActCount = pb->ioParam.ioReqCount;
|
|
}
|
|
fs_err_hook (err);
|
|
return err;
|
|
}
|
|
|
|
A2(PUBLIC, OSErr, ufsPBAllocContig, ParmBlkPtr, pb, /* INTERNAL */
|
|
BOOLEAN, a)
|
|
{
|
|
OSErr err;
|
|
|
|
/* WARN that calling this might be a sign of a non-portable program */
|
|
err = PBAllocate(pb, a); /* o.k. a lie, but wtf */
|
|
fs_err_hook (err);
|
|
return err;
|
|
}
|
|
|
|
A2(PUBLIC, OSErr, ufsPBFlushFile, ParmBlkPtr, pb, /* INTERNAL */
|
|
BOOLEAN, a)
|
|
{
|
|
fcbrec *fp;
|
|
OSErr err;
|
|
|
|
fp = PRNTOFPERR(Cx(pb->ioParam.ioRefNum), &err);
|
|
if (!ROMlib_nosync)
|
|
sync ();
|
|
fs_err_hook (err);
|
|
return err;
|
|
}
|
|
|
|
A2(PUBLIC, OSErr, ufsPBClose, ParmBlkPtr, pb, BOOLEAN, a)/* INTERNAL */
|
|
{
|
|
OSErr err;
|
|
fcbrec *fp;
|
|
|
|
if (Cx(pb->ioParam.ioRefNum) < 0)
|
|
{
|
|
err = ROMlib_dispatch(pb, a, Close, 0);
|
|
fs_err_hook (err);
|
|
return err;
|
|
}
|
|
fp = PRNTOFPERR(Cx(pb->ioParam.ioRefNum), &err);
|
|
|
|
if (err == noErr) {
|
|
if (Uclose(fp->fcfd) < 0)
|
|
{
|
|
err = ioErr;
|
|
}
|
|
Uclose(fp->hiddenfd);
|
|
freeprn(fp);
|
|
}
|
|
fs_err_hook (err);
|
|
return err;
|
|
}
|
|
|
|
A2(PUBLIC trap, OSErrRET, PBHGetLogInInfo, HParmBlkPtr, pb, BOOLEAN, a)
|
|
{
|
|
OSErrRET retval;
|
|
|
|
warning_unimplemented (NULL_STRING);
|
|
retval = paramErr;
|
|
return retval;
|
|
}
|
|
|
|
A2(PUBLIC trap, OSErrRET, PBHGetDirAccess, HParmBlkPtr, pb, BOOLEAN, a)
|
|
{
|
|
OSErrRET retval;
|
|
|
|
warning_unimplemented (NULL_STRING);
|
|
retval = paramErr;
|
|
return retval;
|
|
}
|
|
|
|
A2(PUBLIC trap, OSErrRET, PBHCopyFile, HParmBlkPtr, pb, BOOLEAN, a)
|
|
{
|
|
OSErrRET retval;
|
|
|
|
warning_unimplemented (NULL_STRING);
|
|
retval = paramErr;
|
|
return retval;
|
|
}
|
|
|
|
A2(PUBLIC trap, OSErrRET, PBHMapName, HParmBlkPtr, pb, BOOLEAN, a)
|
|
{
|
|
OSErrRET retval;
|
|
|
|
warning_unimplemented (NULL_STRING);
|
|
retval = paramErr;
|
|
return retval;
|
|
}
|
|
|
|
A2(PUBLIC trap, OSErrRET, PBHMapID, HParmBlkPtr, pb, BOOLEAN, a)
|
|
{
|
|
OSErrRET retval;
|
|
|
|
warning_unimplemented (NULL_STRING);
|
|
retval = paramErr;
|
|
return retval;
|
|
}
|
|
|
|
A2(PUBLIC trap, OSErrRET, PBHSetDirAccess, HParmBlkPtr, pb, BOOLEAN, a)
|
|
{
|
|
OSErrRET retval;
|
|
|
|
warning_unimplemented (NULL_STRING);
|
|
retval = paramErr;
|
|
return retval;
|
|
}
|
|
|
|
A2(PUBLIC trap, OSErrRET, PBHMoveRename, HParmBlkPtr, pb, BOOLEAN, a)
|
|
{
|
|
OSErrRET retval;
|
|
|
|
warning_unimplemented (NULL_STRING);
|
|
retval = paramErr;
|
|
return retval;
|
|
}
|