# include <Files.h> # include <StandardFile.h> # include <Errors.h> # define INCLUDE_FILE_IO # include "dgd.h" extern Uint m2utime(long t); typedef struct { short fref; /* file ref */ Str255 fname; /* file name */ } fdtype; static fdtype fdtab[20]; static long crea; /* creator */ static long type; /* file type */ static short vref; /* volume refNum of current directory */ static long dirid; /* directory ID */ /* * NAME: fsinit() * DESCRIPTION: initialize file functions */ void fsinit(long fcrea, long ftype) { WDPBRec buf; Str255 str; crea = fcrea; type = ftype; buf.ioNamePtr = str; PBHGetVolSync(&buf); vref = buf.ioVRefNum; dirid = buf.ioWDDirID; } /* * NAME: getpath() * DESCRIPTION: get the full path of a file */ char *getpath(char *buf, short vref, unsigned char *fname) { Str255 str; CInfoPBRec dir; buf += STRINGSZ - 1; buf[0] = '\0'; memcpy(str, fname, fname[0] + 1); dir.dirInfo.ioNamePtr = str; dir.dirInfo.ioCompletion = NULL; dir.dirInfo.ioFDirIndex = 0; dir.dirInfo.ioVRefNum = vref; dir.dirInfo.ioDrDirID = 0; for (;;) { PBGetCatInfoSync(&dir); memcpy(buf -= str[0], str + 1, str[0]); if (dir.dirInfo.ioDrDirID == 2) { return buf; } *--buf = ':'; dir.dirInfo.ioFDirIndex = -1; dir.dirInfo.ioDrDirID = dir.dirInfo.ioDrParID; } } /* * NAME: getfile() * DESCRIPTION: get the path of a specific file with a standard dialog */ char *getfile(char *buf, long type) { Point where; SFTypeList list; SFReply reply; where.h = 82; where.v = 124; list[0] = type; SFGetFile(where, NULL, NULL, 1, list, NULL, &reply); if (reply.good) { return getpath(buf, reply.vRefNum, reply.fName); } else { return NULL; } } /* * NAME: path_native() * DESCRIPTION: deal with path that's already native */ char *path_native(char *to, char *from) { to[0] = '/'; /* mark as native */ strncpy(to + 1, from, STRINGSZ - 1); to[STRINGSZ - 1] = '\0'; return to; } /* * NAME: path_file() * DESCRIPTION: translate a path to a pascal string */ static unsigned char *path_file(unsigned char *to, const char *from) { char *p, *q; int n; p = (char *) to + 1; q = (char *) from; if (*q == '/') { /* native path: copy directly */ q++; while (*q != '\0') { *p++ = *q++; } to[0] = (unsigned char *) p - to - 1; return to; } n = 0; *p++ = ':'; if (*q == '.' && q[1] == '\0') { *p = '\0'; to[0] = 1; return to; } n++; while (n < 255 && *q != '\0') { if (*q == '/') { *p = ':'; } else if (*q == ':') { *p = '/'; } else { *p = *q; } p++; q++; n++; } to[0] = n; return to; } /* * NAME: path_unfile() * DESCRIPTION: translate a pascal filename to a path */ static char *path_unfile(char *to, const unsigned char *from) { char *p, *q; int n; for (p = to, q = (char *) from + 1, n = from[0]; n != 0; p++, q++, --n) { if (*q == '/') { *p = ':'; } else { *p = *q; } } *p = '\0'; return to; } static long sdirid; /* scan directory ID */ static short sdiridx; /* scan directory index */ static CInfoPBRec sdirbuf; /* scan dir file info */ /* * NAME: P->opendir() * DESCRIPTION: open a directory */ bool P_opendir(char *path) { CInfoPBRec buf; Str255 str; buf.hFileInfo.ioVRefNum = vref; buf.hFileInfo.ioFDirIndex = 0; buf.hFileInfo.ioNamePtr = path_file(str, path); buf.hFileInfo.ioDirID = dirid; if (PBGetCatInfoSync(&buf) != noErr || (buf.hFileInfo.ioFlAttrib & ioDirMask) == 0) { return FALSE; } sdirid = buf.hFileInfo.ioDirID; sdiridx = 1; return TRUE; } /* * NAME: P->readdir() * DESCRIPTION: read the next filename from the currently open directory */ char *P_readdir(void) { Str255 str; static char path[34]; sdirbuf.hFileInfo.ioVRefNum = vref; sdirbuf.hFileInfo.ioFDirIndex = sdiridx++; sdirbuf.hFileInfo.ioNamePtr = str; sdirbuf.hFileInfo.ioDirID = sdirid; if (PBGetCatInfoSync(&sdirbuf) != noErr) { return NULL; } return path_unfile(path, str); } /* * NAME: P->closedir() * DESCRIPTION: close the currently open directory */ void P_closedir(void) { sdiridx = 0; } /* * NAME: P->open() * DESCRIPTION: open a file */ int P_open(char *path, int flags, int mode) { int fd; short fref; for (fd = 0; fdtab[fd].fref != 0; fd++) { if (fd == sizeof(fdtab) / sizeof(short) - 1) { return -1; } } switch (HOpen(vref, dirid, path_file(fdtab[fd].fname, path), fsRdWrShPerm, &fref)) { case noErr: if ((flags & O_EXCL) || ((flags & O_TRUNC) && SetEOF(fref, 0L) != noErr) || ((flags & O_APPEND) && SetFPos(fref, fsFromLEOF, 0) != noErr)) { FSClose(fref); return -1; } break; case fnfErr: case dirNFErr: if ((flags & O_CREAT) && HCreate(vref, dirid, fdtab[fd].fname, crea, type) == noErr && HOpen(vref, dirid, fdtab[fd].fname, fsRdWrShPerm, &fref) == noErr) { break; } /* fall through */ default: return -1; } fdtab[fd].fref = fref; return fd; } /* * NAME: P->close() * DESCRIPTION: close a file */ int P_close(int fd) { FSClose(fdtab[fd].fref); fdtab[fd].fref = 0; return 0; } /* * NAME: P->read() * DESCRIPTION: read from a file */ int P_read(int fd, char *buf, int nbytes) { long count; count = nbytes; switch (FSRead(fdtab[fd].fref, &count, buf)) { case noErr: case eofErr: return (int) count; default: return -1; } } /* * NAME: P->write() * DESCRIPTION: write to a file */ int P_write(int fd, char *buf, int nbytes) { long count; count = nbytes; switch (FSWrite(fdtab[fd].fref, &count, buf)) { case noErr: case dskFulErr: return (int) count; default: return -1; } } /* * NAME: P->lseek() * DESCRIPTION: seek on a file */ long P_lseek(int fd, long offset, int whence) { short mode; switch (whence) { case SEEK_SET: mode = fsFromStart; break; case SEEK_CUR: mode = fsFromMark; break; case SEEK_END: mode = fsFromLEOF; break; } /* * note: no seek beyond the end of the file */ if (SetFPos(fdtab[fd].fref, mode, offset) != noErr) { return -1; } if (mode != fsFromStart) { GetFPos(fdtab[fd].fref, &offset); } return offset; } /* * NAME: P->stat() * DESCRIPTION: get information about a file */ int P_stat(char *path, struct stat *sb) { CInfoPBRec buf; Str255 str; if (sdiridx != 0) { buf = sdirbuf; } else { buf.hFileInfo.ioVRefNum = vref; buf.hFileInfo.ioFDirIndex = 0; buf.hFileInfo.ioNamePtr = path_file(str, path); buf.hFileInfo.ioDirID = dirid; if (PBGetCatInfoSync(&buf) != noErr) { return -1; } } sb->st_mode = (buf.hFileInfo.ioFlAttrib & ioDirMask) ? S_IFDIR : S_IFREG; sb->st_size = buf.hFileInfo.ioFlLgLen; sb->st_mtime = (long) m2utime(buf.hFileInfo.ioFlMdDat); return 0; } /* * NAME: P->fstat() * DESCRIPTION: get information about an open file */ int P_fstat(int fd, struct stat *sb) { CInfoPBRec buf; buf.hFileInfo.ioVRefNum = vref; buf.hFileInfo.ioFDirIndex = 0; buf.hFileInfo.ioNamePtr = fdtab[fd].fname; buf.hFileInfo.ioDirID = dirid; if (PBGetCatInfoSync(&buf) != noErr) { return -1; } sb->st_mode = (buf.hFileInfo.ioFlAttrib & ioDirMask) ? S_IFDIR : S_IFREG; sb->st_size = buf.hFileInfo.ioFlLgLen; sb->st_mtime = (long) m2utime(buf.hFileInfo.ioFlMdDat); return 0; } /* * NAME: P->unlink() * DESCRIPTION: remove a file (but not a directory) */ int P_unlink(char *path) { CInfoPBRec buf; Str255 str; buf.hFileInfo.ioVRefNum = vref; buf.hFileInfo.ioFDirIndex = 0; buf.hFileInfo.ioNamePtr = path_file(str, path); buf.hFileInfo.ioDirID = dirid; if (PBGetCatInfoSync(&buf) != noErr || (buf.hFileInfo.ioFlAttrib & ioDirMask)) { return -1; } return (HDelete(vref, dirid, str) == noErr) ? 0 : -1; } /* * NAME: P->rename() * DESCRIPTION: rename a file */ int P_rename(char *from, char *to) { char *p, *q; Str255 dir1, dir2, file1, file2; CInfoPBRec buf; long xdirid; p = strrchr(from, '/'); if (p == NULL) { dir1[0] = 1; dir1[1] = '.'; p = from; } else { *p++ = '\0'; path_file(dir1, from); } path_file(file1, p); q = strrchr(to, '/'); if (q == NULL) { dir2[0] = 1; dir2[1] = '.'; q = to; } else { *q++ = '\0'; path_file(dir2, to); } path_file(file2, q); /* source directory must exist */ buf.hFileInfo.ioVRefNum = vref; buf.hFileInfo.ioFDirIndex = 0; buf.hFileInfo.ioNamePtr = dir1; buf.hFileInfo.ioDirID = dirid; if (PBGetCatInfoSync(&buf) != noErr || (buf.hFileInfo.ioFlAttrib & ioDirMask) == 0) { return -1; } xdirid = buf.hFileInfo.ioDirID; /* source file must exist */ buf.hFileInfo.ioNamePtr = file1; if (PBGetCatInfoSync(&buf) != noErr) { return -1; } if (buf.hFileInfo.ioFlAttrib & ioDirMask) { file1[++(file1[0])] = ':'; file2[++(file2[0])] = ':'; } if (p - from != q - to || memcmp(from, to, p - from) != 0) { CMovePBRec move; /* * move to different directory */ /* destination directory must exist */ buf.hFileInfo.ioNamePtr = dir2; buf.hFileInfo.ioDirID = dirid; if (PBGetCatInfoSync(&buf) != noErr || (buf.hFileInfo.ioFlAttrib & ioDirMask) == 0) { return -1; } move.ioNewDirID = buf.hFileInfo.ioDirID; /* destination must not already exist */ buf.hFileInfo.ioNamePtr = file2; if (PBGetCatInfoSync(&buf) == noErr) { return -1; } /* rename source */ memcpy(dir1, file1, file1[0] + 1); memcpy(file1, "\p:_tmp0000", 6); do { static short count; if (count == 9999) { count = 0; } sprintf((char *) file1 + 6, "%04d", ++count); buf.hFileInfo.ioNamePtr = file1; buf.hFileInfo.ioDirID = xdirid; } while (PBGetCatInfoSync(&buf) == noErr); if (dir1[dir1[0]] == ':') { file1[++(file1[0])] = ':'; } if (HRename(vref, xdirid, dir1, file1) != noErr) { return -1; } /* move source to new directory */ move.ioNamePtr = file1; move.ioVRefNum = vref; move.ioNewName = NULL; move.ioDirID = xdirid; if (PBCatMoveSync(&move) != noErr) { /* back to old name */ HRename(vref, xdirid, file1, dir1); return -1; } xdirid = move.ioNewDirID; } return (HRename(vref, xdirid, file1, file2) == noErr) ? 0 : -1; } /* * NAME: P->access() * DESCRIPTION: check access on a file */ int P_access(char *path, int mode) { CInfoPBRec buf; Str255 str; buf.hFileInfo.ioVRefNum = vref; buf.hFileInfo.ioFDirIndex = 0; buf.hFileInfo.ioNamePtr = path_file(str, path); buf.hFileInfo.ioDirID = dirid; if (PBGetCatInfoSync(&buf) != noErr) { return -1; } if (mode == W_OK) { return (buf.hFileInfo.ioFlAttrib & 0x01) ? -1 : 0; } return 0; } /* * NAME: P->mkdir() * DESCRIPTION: create a directory */ int P_mkdir(char *path, int mode) { Str255 str; long newdir; if (DirCreate(vref, dirid, path_file(str, path), &newdir) == noErr) { return 0; } else { return -1; } } /* * NAME: P->rmdir() * DESCRIPTION: remove an empty directory */ int P_rmdir(char *path) { CInfoPBRec buf; Str255 str; buf.hFileInfo.ioVRefNum = vref; buf.hFileInfo.ioFDirIndex = 0; buf.hFileInfo.ioNamePtr = path_file(str, path); buf.hFileInfo.ioDirID = dirid; if (PBGetCatInfoSync(&buf) != noErr || (buf.hFileInfo.ioFlAttrib & ioDirMask) == 0) { return -1; } return (HDelete(vref, dirid, str) == noErr) ? 0 : -1; } /* * NAME: P->chdir() * DESCRIPTION: change the current directory */ int P_chdir(char *path) { CInfoPBRec buf; Str255 str; buf.hFileInfo.ioVRefNum = vref; buf.hFileInfo.ioFDirIndex = 0; buf.hFileInfo.ioNamePtr = path_file(str, path); buf.hFileInfo.ioDirID = dirid; if (PBGetCatInfoSync(&buf) != noErr || (buf.hFileInfo.ioFlAttrib & ioDirMask) == 0) { return -1; } dirid = buf.hFileInfo.ioDirID; return 0; }