/* Copyright 1992 - 1996 by Abacus Research and * Development, Inc. All rights reserved. */ #if !defined (OMIT_RCSID_STRINGS) char ROMlib_rcsid_hfsHelper[] = "$Id: hfsHelper.c 63 2004-12-24 18:19:43Z ctm $"; #endif #include "rsys/common.h" #include "OSUtil.h" #include "FileMgr.h" #include "SegmentLdr.h" #include "ToolboxEvent.h" #include "MemoryMgr.h" #include "ThinkC.h" #include "SysErr.h" #include "DialogMgr.h" #include "ResourceMgr.h" #include "rsys/hfs.h" #include "rsys/file.h" #include "rsys/setuid.h" #include "rsys/partition.h" #if defined (MSDOS) || defined (CYGWIN32) #include "dosdisk.h" #include "aspi.h" #endif #if !defined(MAC) #define FLOPPYWORKSFS "/usr/filesystems/macintosh.fs" #define NEWFLOPPYWORKSFS "/usr/filesystems/macintosh.fs.SAVE" #define MAC30FS "/usr/filesystems/mac.fs" #define NEWMAC30FS "/usr/filesystems/mac.fs.SAVE" #define OURSOCK "/dev/HFS_XFer" #define HFSXFERDOTFS "/usr/filesystems/HFS_XFer.fs" #define HFSXFERUTIL HFSXFERDOTFS "/HFS_XFer.util" #if defined (NEXT) PRIVATE LONGINT pipefd[2]; #endif /* NEXT */ PUBLIC LONGINT ROMlib_sock; PUBLIC void ROMlib_hfsinit( void ) { #if defined (NEXT) struct stat sbuf; struct sockaddr sockname; LONGINT i; char device[DEVNAMELEN]; LONGINT nread, nwritten; LONGINT err; LONGINT savemask; LONGINT myfd; LONGINT mode; if (geteuid()) mustbesetuid(); if (Ustat(HFSXFERDOTFS, &sbuf) < 0) { savemask = umask(0); Umkdir(HFSXFERDOTFS, 0755); umask(savemask); } if (((Ustat(HFSXFERUTIL, &sbuf) < 0) || (sbuf.st_mtime < ROMlib_ourmtime)) && ROMlib_xfervmsize) { myfd = Uopen(HFSXFERUTIL, O_BINARY|O_CREAT|O_WRONLY, 000); if (myfd >= 0) { nwritten = write(myfd, ROMlib_xfervmaddr, ROMlib_xfervmsize); err = close(myfd); if (nwritten == ROMlib_xfervmsize && err == 0) Uchmod(HFSXFERUTIL, 04711); else Uunlink(HFSXFERUTIL); } } if (Ustat(FLOPPYWORKSFS, &sbuf) >= 0) Urename(FLOPPYWORKSFS, NEWFLOPPYWORKSFS); if (Ustat(MAC30FS, &sbuf) >= 0) Urename(MAC30FS, NEWMAC30FS); pipefd[1] = -1; pipe((void *) pipefd); if (fork() == 0) { setpgrp(0, 0); for (i = 1; i < NSIG; ++i) signal(i, SIG_IGN); close(pipefd[1]); do { nread = read(pipefd[0], device, sizeof(device)); if (nread > 1) { sscanf(device+strlen(device)+1, "%o", &mode); Uchmod(device, mode); } } while (nread > 0); Urename(NEWFLOPPYWORKSFS, FLOPPYWORKSFS); Urename(NEWMAC30FS, MAC30FS); Uunlink(OURSOCK); exit(0); } else close(pipefd[0]); ROMlib_sock = socket(AF_UNIX, SOCK_STREAM, 0); gui_assert(ROMlib_sock >= 0); sockname.sa_family = AF_UNIX; memmove(sockname.sa_data, OURSOCK, sizeof(OURSOCK)); Uunlink(OURSOCK); err = bind(ROMlib_sock, &sockname, sizeof(sockname)); if (err < 0) someoneelseonfloppy(); /* gui_assert(err >= 0); */ ROMlib_setuid(getuid()); err = fcntl(ROMlib_sock, F_SETFL, FNDELAY); /* gui_assert(err >= 0); */ err = listen(ROMlib_sock, 1); /* gui_assert(err >= 0); */ #endif /* NEXT */ } /* * NOTE: The weird name constructed below is inherited from HFS_XFer.util.c, * which is an ARDI written NEXTSTEP atrocity. */ #if !defined(LINUX) && !defined (MACOSX) #define EJECTABLE(buf) FALSE #else /* #warning this is not the proper way to tell if something is ejectable */ #define EJECTABLE(buf) (buf[strlen(buf)-3] == 'f' && buf[strlen(buf)-2] == 'd') #endif #define ASSIGN_NAME_MODE_STRING(buf, lenp, filename, sbuf) \ do { \ char ejectable; \ \ ejectable = EJECTABLE(filename); \ *(lenp) = strlen((filename)) + 1 + 6 + 1 + 1 + 1; \ (buf) = alloca(*(lenp)); \ sprintf((buf), "%s%c%06o%c%c", (filename), 0, (sbuf).st_mode & 07777, 0, \ ejectable);\ } while (0) #define NRETRIES 5 #if defined (NEXT) PUBLIC long ROMlib_priv_open(const char *filename, long mode) { long retval; struct stat sbuf; long savemode; char *dname; long len; int count; if (Ustat(filename, &sbuf) < 0) retval = ROMlib_maperrno(); else { savemode = sbuf.st_mode; sbuf.st_mode = 0666; ASSIGN_NAME_MODE_STRING(dname, &len, filename, sbuf); write(pipefd[1], dname, len); count = NRETRIES; do { if (count != NRETRIES) Delay(60, (LONGINT *) 0); retval = Uopen(filename, mode); } while ((retval < 0) && (errno == EACCES) && --count); if (retval < 0) retval = ROMlib_maperrno(); sbuf.st_mode = savemode; ASSIGN_NAME_MODE_STRING(dname, &len, filename, sbuf); write(pipefd[1], dname, len); } return retval; } #else PUBLIC long ROMlib_priv_open (const char *filename, long mode) { long retval; retval = Uopen(filename, mode, 0); if (retval < 0) retval = ROMlib_maperrno(); return retval; } #endif PRIVATE void eject_floppy_notify( void ) { /* * We make the test for 'ALRT' because when Executor shuts down, an ejectable * volume may be unmounted after the volume with the System file has already * been unmounted. In the past, this caused a crash. It may make sense to * deliberately unmount last the volume containing System, but that's a fix * for another day. */ if (WWExist == EXIST_YES && GetResource(TICK("ALRT"), EJECTALERTID)) Alert(EJECTALERTID, (ProcPtr) 0); } PUBLIC OSErr ROMlib_ejectfloppy( LONGINT floppyfd ) { OSErr err; err = noErr; #if defined(MSDOS) || defined (CYGWIN32) if (floppyfd == -1 || (floppyfd & (DOSFDBIT|ASPIFDBIT))) { if (floppyfd != -1) { if (floppyfd & DOSFDBIT) { floppyfd &= ~DOSFDBIT; dosdisk_close(floppyfd, TRUE); } #if defined (MSDOS) else { floppyfd &= ~ASPIFDBIT; aspi_disk_close(floppyfd, TRUE); } #endif } eject_floppy_notify(); } else { #endif #if defined(NEXTSTEP) || defined (MACOSX) if (floppyfd != -1 && ioctl(floppyfd, DKIOCEJECT, (char *) 0) < 0) { fprintf(stderr, "couldn't eject disk\n"); err = ioErr; } #endif if (floppyfd != -1) close(floppyfd); #if defined(LINUX) || defined (MACOSX) eject_floppy_notify(); #endif #if defined(MSDOS) || defined (CYGWIN32) } #endif return err; } PUBLIC void ROMlib_OurClose( void ) { HVCB *vcbp, *next; ParamBlockRec pbr; for (vcbp = (HVCB *) MR(VCBQHdr.qHead); vcbp; vcbp = next) { next = (HVCB *) MR(vcbp->qLink); pbr.ioParam.ioNamePtr = 0; if (Cx(vcbp->vcbCTRef)) { pbr.ioParam.ioVRefNum = vcbp->vcbVRefNum; PBUnmountVol(&pbr); #if defined (NEXTSTEP) || defined (MACOSX) if (!(Cx(vcbp->vcbAtrb) & VNONEJECTABLEBIT) && Cx(vcbp->vcbDrvNum)) ROMlib_ejectfloppy(((VCBExtra *) vcbp)->u.hfs.fd); #endif } else ROMlib_dbm_close((VCBExtra *) vcbp); } } #if 0 PRIVATE BOOLEAN isejectable( const charCx( *dname), LONGINT fd ) { BOOLEAN retval; #if defined(NEXTSTEP) || defined (MACOSX) struct scsi_req sr; char inqbuf[sizeof(struct inquiry_reply) + 3]; struct inquiry_replyCx( *inqp); const charCx( *p); #endif /* look for rfd[0-9] */ retval = FALSE; #if defined(NEXTSTEP) || defined (MACOSX) for (p = dname; p = index(p, 'r'); ++p) { if (p[1] == 'f' && p[2] == 'd' && isdigit(p[3])) { retval = TRUE; /*-->*/ break; } } if (!retval) { inqp = (struct inquiry_reply *) (((LONGINT) inqbuf + 3) / 4Cx( * 4)); bzero (&sr, sizeof(sr)); sr.sr_cdb.cdb_c6.c6_opcode = C6OP_INQUIRY; sr.sr_cdb.cdb_c6.c6_len = sizeofCx((*inqp)); sr.sr_dma_dir = SR_DMA_RD; sr.sr_addr = (caddr_t) inqp; sr.sr_dma_max = sr.sr_cdb.cdb_c6.c6_len; sr.sr_ioto = 1; if (ioctl(fd, SGIOCREQ, &sr) == 0 && sr.sr_io_status == 0 && Cx(inqp->ir_removable)) retval = TRUE; } #endif return retval; } #endif /* * NOTE: messp below points to the longint that will be filled in with * the status of the first disk insert event that we create, but * because we can have multiple drives mounted on one physical * drive, we wind put using PostEvent for all but the first. * * The above method sounds pretty hacky to me, and should probably * be replaced once we find a cheaper way to be notified that * a disk can be read (probably use a signal on the pipe). */ PRIVATE LONGINT try_to_open_disk( const char *dname, LONGINT *bsizep, LONGINT *maxbytesp, drive_flags_t *flagsp, uint32 *offsetp) { LONGINT floppyfd; int len; #if defined(NEXTSTEP) struct drive_info drvinfo; #endif *flagsp = 0; len = strlen(dname)+1; /* first component: name */ len += strlen(dname+len)+1; /* second component: permission */ if (!dname[len]) *flagsp |= DRIVE_FLAGS_FIXED; /* third component: ejectable */ #if defined (NEXT) if (pipefd[1] != -1) write(pipefd[1], dname, len); #endif /* NEXT */ #if !defined (CYGWIN32) #define EXTRA_BITS O_EXCL #else #define EXTRA_BITS 0 #endif if ((floppyfd = Uopen(dname, O_BINARY|O_RDWR|EXTRA_BITS, 0000)) < 0 && (*flagsp |= DRIVE_FLAGS_LOCKED, (floppyfd = Uopen(dname, O_BINARY|O_RDONLY|EXTRA_BITS, 0000)) < 0)) /* fprintf(stderr, "can't open %s\n", dname) */; else { #if defined(NEXTSTEP) if (ioctl(floppyfd, DKIOCINFO, &drvinfo) == 0) { *bsizep = drvinfo.di_devblklen; *maxbytesp = drvinfo.di_maxbcount / *bsizep * *bsizep; } else { *bsizep = PHYSBSIZE; *maxbytesp = 1024L * 1024; } #else *bsizep = PHYSBSIZE; *maxbytesp = 1024L * 1024; #endif } if (floppyfd >= 0) { struct stat sbuf; if (fstat (floppyfd, &sbuf) >= 0 && (S_IFREG & sbuf.st_mode)) *offsetp = sbuf.st_size % PHYSBSIZE; else *offsetp = 0; } return floppyfd; } PRIVATE LONGINT read_driver_block_size (LONGINT fd, LONGINT bsize, LONGINT maxbytes, char aligned_buf[]) { LONGINT retval; retval = PHYSBSIZE; if (ROMlib_readwrite (fd, aligned_buf, PHYSBSIZE, 0, reading, bsize, maxbytes) == noErr) { if (aligned_buf[0] == 0x45 && aligned_buf[1] == 0x52) { retval = (unsigned short) CW (*(unsigned short *) &aligned_buf[2]); warning_fs_log ("fd = 0x%x, block size = %d", fd, retval); } } return retval; } PUBLIC void try_to_mount_disk (const char *dname, LONGINT floppyfd, LONGINT *messp, LONGINT bsize, LONGINT maxbytes, drive_flags_t flags, uint32 offset_in) { INTEGER partition; ParamBlockRec pb; char *tbuf, *buf; INTEGER drivenum; LONGINT offset; BOOLEAN foundmap, first; oldblock1_t *oldmapp; partmapentry_t *partp; int i; LONGINT mess; OSErr err; DrvQExtra *dqp; hfs_access_t hfs; LONGINT driver_block_size; *messp = 0; tbuf = alloca (bsize + 3); buf = (char *) (((long)tbuf +3)&~3); partition = 0; if (floppyfd >= 0) driver_block_size = read_driver_block_size (floppyfd, bsize, maxbytes, buf); else driver_block_size = PHYSBSIZE; hfs.fd = (flags & DRIVE_FLAGS_FLOPPY) ? floppyfd : -1; hfs.offset = offset_in; hfs.bsize = bsize; hfs.maxbytes = maxbytes; dqp = ROMlib_addtodq (2048L * 2, dname, partition, OURHFSDREF, flags, &hfs); if (floppyfd < 0) /*-->*/return; drivenum = CW(dqp->dq.dQDrive); pb.ioParam.ioVRefNum = CW(drivenum); foundmap = FALSE; first = TRUE; offset = hfs.offset + PARTOFFSET * driver_block_size; if (ROMlib_readwrite(floppyfd, buf, PHYSBSIZE, offset, reading, bsize, maxbytes) == noErr) { if (buf[0] == PARMAPSIG0 && buf[1] == PARMAPSIG1) { warning_fs_log ("found partition sig at %d, floppyfd = 0x%x", offset, floppyfd); partp = (partmapentry_t *) buf; do { if (strncmp((char *) partp->pmPartType, HFSPARTTYPE, 32) == 0) { foundmap = TRUE; if (!first) { ++partition; dqp = ROMlib_addtodq (2048L * 2, dname, partition, OURHFSDREF, flags, &hfs); drivenum = CW(dqp->dq.dQDrive); pb.ioParam.ioVRefNum = CW(drivenum); } dqp->hfs.offset = hfs.offset + (CL (partp->pmPyPartStart) * driver_block_size); err = hfsPBMountVol(&pb, floppyfd, dqp->hfs.offset, bsize, maxbytes, flags, dqp); mess = ((LONGINT) err << 16) | drivenum; if (first) { *messp = CL(mess); first = FALSE; } else PPostEvent(diskEvt, mess, (HIDDEN_EvQElPtr *) 0); } offset += driver_block_size; } while (ROMlib_readwrite(floppyfd, buf, PHYSBSIZE, offset, reading, bsize, maxbytes) == noErr && buf[0] == PARMAPSIG0 && buf[1] == PARMAPSIG1); } else if (buf[0] == OLDMAPSIG0 && buf[1] == OLDMAPSIG1) { oldmapp = (oldblock1_t *) buf; for (i = 0; i < NOLDENTRIES && (Cx(oldmapp->oldmapentry[i].pdStart) != 0 || Cx(oldmapp->oldmapentry[i].pdSize) != 0 || Cx(oldmapp->oldmapentry[i].pdFSID) != 0) ; ++i) { /* * NOTE: We initially tried looking for 'TFS1' in pdFSID, but our Cirrus 80 * didn't use that id. */ if (!first) { ++partition; dqp = ROMlib_addtodq (2048L * 2, dname, partition, OURHFSDREF, flags, &hfs); drivenum = CW(dqp->dq.dQDrive); pb.ioParam.ioVRefNum = CW(drivenum); } dqp->hfs.offset = hfs.offset + (CL (oldmapp->oldmapentry[i].pdStart) * driver_block_size); err = hfsPBMountVol(&pb, floppyfd, dqp->hfs.offset, bsize, maxbytes, flags, dqp); mess = ((LONGINT) err << 16) | drivenum; if (first) { *messp = CL(mess); first = FALSE; } else PPostEvent(diskEvt, mess, (HIDDEN_EvQElPtr *) 0); } foundmap = TRUE; } } if (!foundmap) { for (offset = hfs.offset + VOLUMEINFOBLOCKNO * PHYSBSIZE, i = 4; --i >= 0 ; offset += PHYSBSIZE) { if (i == 0) { if (ROMlib_magic_offset == -1) /*-->*/ continue; else offset = ROMlib_magic_offset; } err = ROMlib_readwrite(floppyfd, buf, PHYSBSIZE, offset, reading, bsize, maxbytes); if (err != noErr) { warning_unexpected ("fd = 0x%x err = %d, offset = %d, " "bsize = %d, maxbytes = %d", floppyfd, err, offset, bsize, maxbytes); /*-->*/ break; } if (buf[0] == 'B' && buf[1] == 'D') { warning_fs_log ("Found HFS volume on 0x%x %d", floppyfd, offset); offset -= VOLUMEINFOBLOCKNO * PHYSBSIZE; foundmap = TRUE; /*-->*/ break; } else if (buf[0] == 'H' && buf[1] == '+') { warning_fs_log ("Found HFS+ volume on 0x%x %d", floppyfd, offset); } else { warning_fs_log ("fd = 0x%x, offset = %d, sig = 0x%02x%02x", floppyfd, offset, buf[0], buf[1]); } } if (foundmap) { dqp->hfs.offset = offset; err = hfsPBMountVol(&pb, floppyfd, offset, bsize, maxbytes, flags, dqp); *messp = CL(((LONGINT) err << 16) | drivenum); } } } PUBLIC void ROMlib_openfloppy( const char *dname, LONGINT *messp) { LONGINT floppyfd; LONGINT bsize, maxbytes; drive_flags_t flags; uint32 offset; *messp = 0; floppyfd = try_to_open_disk (dname, &bsize, &maxbytes, &flags, &offset); if (floppyfd >= 0) try_to_mount_disk (dname, floppyfd, messp, bsize, maxbytes, flags, offset); } PUBLIC void ROMlib_openharddisk( const char *dname, LONGINT *messp ) { char *newbuf; long len; struct stat sbuf; *messp = 0; if (Ustat(dname, &sbuf) == 0) { ASSIGN_NAME_MODE_STRING(newbuf, &len, dname, sbuf); ROMlib_openfloppy(newbuf, messp); } } #endif #define JUMPTODONEIF(x) if ((x)) { err = ioErr; goto DONE; } PUBLIC OSErr ROMlib_readwrite(LONGINT fd, char *buffer, LONGINT count, LONGINT offset, accesstype rw, LONGINT blocksize, LONGINT maxtransfer) { char *newbuffer; LONGINT remainder, totransfer; BOOLEAN needlseek; OSErr err; int (* readfp)(int fd, void *buf, int nbytes); int (*writefp)(int fd, const void *buf, int nbytes); off_t (*seekfp)(int fd, off_t where, int how); if (blocksize > 18 * 1024) { warning_unexpected ("fd = 0x%x, block size = %d", fd, blocksize); return fsDSIntErr; } if (blocksize == 0) { blocksize = 2048; warning_unexpected ("fd = 0x%x, zero block size", fd); } #if defined(MSDOS) || defined (CYGWIN32) if (fd & DOSFDBIT) { fd &= ~DOSFDBIT; seekfp = dosdisk_seek; readfp = dosdisk_read; writefp = dosdisk_write; } #if defined (MSDOS) else if (fd & ASPIFDBIT) { fd &= ~ASPIFDBIT; seekfp = aspi_disk_seek; readfp = aspi_disk_read; writefp = aspi_disk_write; } #endif else { #endif seekfp = (off_t (*)(int, off_t, int)) lseek; readfp = (int (*)(int, void *, int)) read; writefp = (int (*)(int, const void *, int)) write; #if defined(MSDOS) || defined (CYGWIN32) } #endif err = noErr; newbuffer = 0; needlseek = TRUE; if ((remainder = offset % blocksize)) { /* |xxxDATA| */ remainder = blocksize - remainder; totransfer = MIN(count, remainder); newbuffer = (char *) (((long) alloca(blocksize + 3)+3) & ~3); offset = offset / blocksize * blocksize; JUMPTODONEIF(seekfp(fd, offset, L_SET) < 0) needlseek = FALSE; JUMPTODONEIF(readfp(fd, newbuffer, blocksize) != blocksize) if (rw == reading) { memmove(buffer, newbuffer+blocksize-remainder, totransfer); } else { memmove(newbuffer+blocksize-remainder, buffer, totransfer); JUMPTODONEIF(seekfp(fd, offset, L_SET) < 0) JUMPTODONEIF(writefp(fd, newbuffer, blocksize) != blocksize) } buffer += totransfer; count -= totransfer; offset += blocksize; } if (count >= blocksize) { /* |DATADATADATA...| */ remainder = count % blocksize; count -= remainder; if (needlseek) { JUMPTODONEIF(seekfp(fd, offset, L_SET) < 0) needlseek = FALSE; } while (count) { totransfer = MIN(maxtransfer, count); if (rw == reading) { JUMPTODONEIF(readfp(fd, buffer, totransfer) != totransfer) } else { JUMPTODONEIF(writefp(fd, buffer, totransfer) != totransfer) } buffer += totransfer; count -= totransfer; offset += totransfer; } count = remainder; } if (count) { /* |DATAxxx| */ if (!newbuffer) newbuffer = (char *) (((long) alloca(blocksize+3)+3) & ~3); if (needlseek) JUMPTODONEIF(seekfp(fd, offset, L_SET) < 0) JUMPTODONEIF(readfp(fd, newbuffer, blocksize) != blocksize) if (rw == reading) { memmove(buffer, newbuffer, count); } else { memmove(newbuffer, buffer, count); JUMPTODONEIF(seekfp(fd, offset, L_SET) < 0) JUMPTODONEIF(writefp(fd, newbuffer, blocksize) != blocksize) } } DONE: return err; } PUBLIC OSErr ROMlib_transphysblk (hfs_access_t *hfsp, LONGINT physblock, short nphysblocks, Ptr bufp, accesstype rw, LONGINT *actp) { LONGINT fd; OSErr err; Ptr newbufp; #if defined(MAC) ioParam pb; pb.ioVRefNum = vcbp->vcbDrvNum; pb.ioRefNum = vcbp->vcbDRefNum; pb.ioBuffer = CL(bufp); pb.ioReqCount = CL(PHYSBSIZE * (LONGINT nphysblocks)); pb.ioPosMode = CW(fsFromStart); pb.ioPosOffset = CL(physblock); err = rw == reading ? PBRead ((ParmBlkPtr) &pb, FALSE) : PBWrite((ParmBlkPtr) &pb, FALSE); if (actp) *actp = pb.ioActCount; #else #if defined(NEXTSTEP) || defined (MACOSX) if ((LONGINT) bufp & 3) { newbufp = alloca( (LONGINT) nphysblocks * PHYSBSIZE + 4); newbufp = (Ptr) (((LONGINT) newbufp + 3) & ~3); if (rw == writing) memmove(newbufp, bufp, (LONGINT) nphysblocks * PHYSBSIZE); } else #endif newbufp = bufp; fd = hfsp->fd; err = ROMlib_readwrite(fd, (char *) newbufp, (LONGINT) nphysblocks * PHYSBSIZE, physblock + hfsp->offset, rw, hfsp->bsize, hfsp->maxbytes); #if defined(NEXTSTEP) || defined (MACOSX) if (rw == reading && bufp != newbufp && err == noErr) memmove(bufp, newbufp, (LONGINT) nphysblocks * PHYSBSIZE); #endif if (actp) *actp = err != noErr ? 0 : CL((LONGINT) nphysblocks * PHYSBSIZE); #endif if (err != noErr) warning_unexpected ("fd = 0x%x, err in transphysblock (err = %d)", fd, err); return err; } PUBLIC char *ROMlib_indexn(char *str, char tofind, INTEGER length) { while (--length >= 0) if (*str++ == tofind) return str - 1; return 0; } #if !defined(str255assign) PUBLIC void str255assign(StringPtr dstp, StringPtr srcp) { memmove(dstp, srcp, (size_t) srcp[0]+1); } #endif /* !defined(str255assign) */ /* * ROMlib_indexqueue returns a pointer to the n'th entry on a queue. * ROMlib_indexqueue is one based; not zero based. */ PUBLIC void *ROMlib_indexqueue(QHdr *qp, short index) { QElemPtr p; #if defined(MAC) for (p = CL(qp->qHead); (--index > 0) && p; p = CL(p->qLink)) ; #else for (p = MR(qp->qHead); (--index > 0) && p; p = MR(p->vcbQElem.qLink)) ; #endif return p; } PUBLIC OSErr ROMlib_writefcbp(filecontrolblock *fcbp) { Byte flags; OSErr retval; flags = fcbp->fcbMdRByt; if (!(flags & WRITEBIT)) retval = wrPermErr; else if (flags & FLOCKEDBIT) retval = fLckdErr; else retval = noErr; return retval; } PUBLIC OSErr ROMlib_writevcbp(HVCB *vcbp) { INTEGER vflags; OSErr retval; vflags = Cx(vcbp->vcbAtrb); if (vflags & VSOFTLOCKBIT) retval = vLckdErr; else if (vflags & VHARDLOCKBIT) retval = wPrErr; else retval = noErr; return retval; }