/* * $Logfile: /DescentIII/Main/ddio_mac/macfile.cpp $ * $Revision: 1.1.1.1 $ * $Date: 2003/08/26 03:56:55 $ * $Author: kevinb $ * * File operations not covered properly in ANSI C * * $Log: macfile.cpp,v $ * Revision 1.1.1.1 2003/08/26 03:56:55 kevinb * initial 1.5 import * * * 4 10/21/99 3:33p Jeff * Macintosh merges * * 3 8/01/99 10:37p Duane * Works with paht+wildcard or just wildcard * * 2 7/28/99 3:31p Kevin * Mac Stuff! * * 6 5/15/97 1:44 AM Jeremy * changed mprintf's to be standard (with newline at end), fixed two bugs: * ddio_filediff was returning opposite of correct value, ddio function to * set file time stamp had arguments in reverse order * * 5 5/9/97 8:04 PM Jeremy * changed include of to * * 4 5/6/97 6:37 PM Jeremy * implemented splitpath * * 3 5/6/97 4:22 PM Jeremy * fixed a bug in ddio_MakePath * * 2 5/6/97 3:11 PM Jeremy * added implementation of ddio_MakePath * * 1 3/13/97 6:53 PM Jeremy * macintosh implementation of device dependent io functions * * $NoKeywords: $ */ // ANSI Headers #include #include #include #include #include #include #include #include //#include // Mac Headers #include #include #include // Descent 3 Headers #include "mono.h" #include "pserror.h" #include "ddio.h" #include "ddio_mac.h" #include "psglob.h" #include "mem.h" #include "cfile.h" // --------------------------------------------------------------------------- // File Level Globals // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- // Local File Prototypes // --------------------------------------------------------------------------- /******************************************* Utility functions specific to the Mac OS ******************************************* int stricmp(const char* s1, const char* s2) { char c1, c2; while (1) { c1 = tolower(*s1++); c2 = tolower(*s2++); if (c1 < c2) return -1; if (c1 > c2) return 1; if (c1 == 0) return 0; } } int strnicmp(const char *s1, const char *s2, int n) { int i; char c1, c2; for (i=0; i c2) return 1; if (!c1) return 0; } return 0; } /************************/ // --------------------------------------------------------------------------- // File Operations // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- // File operations bool ddio_CreateDir(const char *path) { bool failed = true; failed = mkdir(path, 0); return !failed; } bool ddio_RemoveDir(const char *path) { bool failed = true; failed = rmdir(path); return (!failed); } // retrieve the current working folder where file operation will occur. // Note ---> The path in Get/Set working directory is in the *LOCAL* file system's syntax // This pathname is relative *OR* fully qualified static char SavedWorkingDir[_MAX_PATH]; void ddio_GetWorkingDir(char *path, int len) { getcwd(path, len); len = strlen(path); if (path[len - 1] == ':') { path[len - 1] = '\0'; } } // set the current working folder where file operation will occur. // Note ---> The path in Get/Set working directory is in the *LOCAL* file system's syntax // This pathname is relative *OR* fully qualified bool ddio_SetWorkingDir(const char *path) { bool failed = true; failed = chdir(path); if (!failed) { // if(path[strlen(path)-1] != ':') // strcat(path, ":"); strcpy(SavedWorkingDir, path); return true; } else { return false; } } // check if two files are different bool ddio_FileDiff(const char *fileNameA, const char *fileNameB) { struct stat infoA; struct stat infoB; bool filesAreEqual = false; if (fileNameA && fileNameB) { if (!(strcmp(fileNameA, fileNameB))) { filesAreEqual = true; } else // test file info { stat(fileNameA, &infoA); stat(fileNameB, &infoB); if ((infoA.st_mode == infoB.st_mode) && (infoA.st_size == infoB.st_size) && (infoA.st_mtime == infoB.st_mtime)) { filesAreEqual = true; } } } return !filesAreEqual; } // get a file length of a FILE int ddio_GetFileLength(FILE *filePtr) { int size = -1; if (filePtr) { int filedes = fileno(filePtr); struct stat info; fstat(filedes, &info); size = info.st_size; } else { mprintf((0, "Tried getting length of NULL fileptr!\n")); Debugger(); } return size; } // Split a pathname into its component parts void ddio_SplitPath(const char *srcPath, char *path, char *filename, char *ext) { int pathStart = -1; int pathEnd = -1; int fileStart = -1; int fileEnd = -1; int extStart = -1; int extEnd = -1; int totalLen = strlen(srcPath); // Check for an extension /////////////////////////////////////// int t = totalLen - 1; while ((srcPath[t] != '.') && (srcPath[t] != ':') && (t >= 0)) t--; // see if we are at an extension if ((t >= 0) && (srcPath[t] == '.')) { // we have an extension extStart = t; extEnd = totalLen - 1; if (ext) { strncpy(ext, &(srcPath[extStart]), extEnd - extStart + 1); ext[extEnd - extStart + 1] = '\0'; } } else { // no extension if (ext) ext[0] = '\0'; } // Check for file name //////////////////////////////////// int temp = (extStart != -1) ? (extStart) : (totalLen - 1); while ((srcPath[temp] != ':') && (temp >= 0)) temp--; if (temp < 0) temp = 0; if (srcPath[temp] == ':') { // we have a file fileStart = temp + 1; if (extStart != -1) fileEnd = extStart - 1; else fileEnd = totalLen - 1; if (filename) { strncpy(filename, &(srcPath[fileStart]), fileEnd - fileStart + 1); filename[fileEnd - fileStart + 1] = '\0'; } pathStart = 0; pathEnd = fileStart - 2; // Copy the rest into the path name if (path) { strncpy(path, &(srcPath[pathStart]), pathEnd - pathStart + 1); path[pathEnd - pathStart + 1] = 0; } } else { // only file, no path fileStart = 0; if (extStart != -1) fileEnd = extStart - 1; else fileEnd = totalLen - 1; if (filename) { strncpy(filename, &(srcPath[fileStart]), fileEnd - fileStart + 1); filename[fileEnd - fileStart + 1] = 0; } // Only file no path if (path) { path[0] = 0; } } #if 0 // Check for an extension if (srcPath[totalLen - 4] == '.') { extStart = totalLen - 4; extEnd = totalLen - 1; strncpy(ext, &(srcPath[extStart]), extEnd - extStart + 1); ext[extEnd - extStart + 1] = 0; } else { ext[0] = 0; } // Check for file name char* namePtr = strrchr(srcPath, ':'); if (namePtr) { fileStart = namePtr - srcPath + 1; if (extStart != -1) { fileEnd = extStart - 2; } else { fileEnd = totalLen - 1; } strncpy(filename, &(srcPath[fileStart]), fileEnd - fileStart + 1); filename[fileEnd - fileStart + 1] = 0; pathStart = 0; pathEnd = fileStart - 2; // Copy the rest into the path name strncpy(path, &(srcPath[pathStart]), pathEnd - pathStart + 1); path[pathEnd - pathStart + 1] = 0; } else { fileStart = 0; if (extStart != -1) { fileEnd = extStart - 2; } else { fileEnd = totalLen - 1; } strncpy(filename, &(srcPath[fileStart]), fileEnd - fileStart + 1); filename[fileEnd - fileStart + 1] = 0; // Only file no path path[0] = 0; } #endif } void ddio_CopyFileTime(char *dstFile, const char *srcFile) { CInfoPBRec srcPB; CInfoPBRec dstPB; OSErr err = noErr; Str255 srcMacFile = "\p"; Str255 dstMacFile = "\p"; Str255 volName = "\p"; short volRefNum = 0; long dirID = 0; // Get the info for the current default volume (where the working directory lives) err = HGetVol(volName, &volRefNum, &dirID); if (err) { mprintf((0, "Error getting default volume info in ddio_CopyFileTime: %d\n", err)); Debugger(); } else { // Convert the c-string version of the path to a p-string strcpy((char *)srcMacFile, srcFile); c2pstr((char *)srcMacFile); // Set up the source file's parameter block memset(&srcPB, 0, sizeof(srcPB)); srcPB.hFileInfo.ioNamePtr = srcMacFile; srcPB.hFileInfo.ioFDirIndex = 0; srcPB.hFileInfo.ioVRefNum = volRefNum; srcPB.hFileInfo.ioDirID = dirID; // Get the source file's info err = PBGetCatInfoSync(&srcPB); if (err == noErr) { // Convert the c-string version of the path to a p-string strcpy((char *)dstMacFile, dstFile); c2pstr((char *)dstMacFile); // Set up the target file's parameter block memset(&dstPB, 0, sizeof(dstPB)); dstPB.hFileInfo.ioNamePtr = dstMacFile; dstPB.hFileInfo.ioVRefNum = volRefNum; dstPB.hFileInfo.ioFDirIndex = 0; dstPB.hFileInfo.ioDirID = dirID; // Get the target file's info err = PBGetCatInfoSync(&dstPB); if (err == noErr) { // Transfer the src file's time stamp to the target dstPB.hFileInfo.ioFlCrDat = srcPB.hFileInfo.ioFlCrDat; dstPB.hFileInfo.ioFlMdDat = srcPB.hFileInfo.ioFlMdDat; dstPB.hFileInfo.ioFlBkDat = srcPB.hFileInfo.ioFlBkDat; // Restore the directory id (which got bashed to the fileID by PBGetCatInfo dstPB.hFileInfo.ioDirID = dirID; err = PBSetCatInfoSync(&dstPB); if (err == noErr) { ; // success } else { mprintf((0, "Error setting target file's timestamp in ddio_CopyFileTime: %d\n", err)); Debugger(); } } else { mprintf((0, "Error getting target file's info in ddio_CopyFileTime: %d\n", err)); Debugger(); } } else { mprintf((0, "Error getting source file's time stamp in ddio_CopyFileTime: %d\n", err)); Int3(); } } } // deletes a file. Returns 1 if successful, 0 on failure int ddio_DeleteFile(char *name) { bool failed = true; failed = remove(name); return (!failed); } // Save/Restore the current working directory void ddio_SaveWorkingDir(void) { ddio_GetWorkingDir(SavedWorkingDir, _MAX_PATH); } void ddio_RestoreWorkingDir(void) { ddio_SetWorkingDir(SavedWorkingDir); } // Checks if a directory exists (returns 1 if it does, 0 if not) // This pathname is *RELATIVE* not fully qualified bool ddio_DirExists(const char *path) { bool res; ddio_SaveWorkingDir(); res = chdir(path); if (res) { char tempbuffer[_MAX_PATH]; strcpy(tempbuffer, ":"); strcat(tempbuffer, path); res = chdir(tempbuffer); } ddio_RestoreWorkingDir(); return (!res) ? true : false; } // Constructs a path in the local file system's syntax // newPath: stores the constructed path // absolutePathHeader: absolute path on which the sub directories will be appended // (specified in local file system syntax) // takes a variable number of subdirectories which will be concatenated on to the path // the last argument in the list of sub dirs *MUST* be NULL to terminate the list void ddio_MakePath(char *newPath, const char *absolutePathHeader, const char *subDir, ...) { const char delimiter = ':'; va_list args; char *currentDir = NULL; int pathLength = 0; assert(newPath); if (absolutePathHeader == 0) mprintf((2, "WOOPS\n")); assert(absolutePathHeader); assert(subDir); if (newPath != absolutePathHeader) { strcpy(newPath, absolutePathHeader); } // Add the first sub directory pathLength = strlen(newPath); if (newPath[pathLength - 1] != delimiter) { newPath[pathLength] = delimiter; // add the delimiter newPath[pathLength + 1] = 0; // terminate the string } strcat(newPath, subDir); // Add the additional subdirectories va_start(args, subDir); while ((currentDir = va_arg(args, char *)) != NULL) { pathLength = strlen(newPath); if (newPath[pathLength - 1] != delimiter) { newPath[pathLength] = delimiter; // add the delimiter newPath[pathLength + 1] = 0; // terminate the string } strcat(newPath, currentDir); } va_end(args); } bool ddio_GetTempFileName(char *basedir, char *prefix, char *filename) { char old_workdir[_MAX_PATH]; bool success = false; if (strlen(prefix) > 64) return false; ddio_GetWorkingDir(old_workdir, _MAX_PATH); if (!ddio_DirExists(basedir)) { return false; // invalid base directory } char randname[10]; int index; int tries = 0; char rc; bool created = false; index = 0; while (!success && tries < 20) { // generate a bunch of random characters rc = (rand() % 128); if ((rc >= 'a' && rc <= 'z') || (rc >= 'A' && rc <= 'Z') || (rc >= '0' && rc <= '9')) { // valid character randname[index] = rc; index++; if (index == 10) { // we hit the size of our max, see if we generated a unique filename char t[_MAX_PATH]; randname[9] = '\0'; sprintf(t, "%s%s.tmp", prefix, randname); // see if we can find this file FILE *fd = mac_fopen(t, "rb"); if (!fd) { // we found a good file! ddio_MakePath(filename, basedir, t, NULL); success = true; created = true; } else { // already taken fclose(fd); tries++; index = 0; } } } else { continue; // try again } } ddio_SetWorkingDir(old_workdir); return created; } // These functions allow one to find a file // You use FindFileStart by giving it a wildcard (like *.*, *.txt, u??.*, whatever). It returns // a filename in namebuf. // Use FindNextFile to get the next file found with the wildcard given in FindFileStart. // Use FindFileClose to end your search. // These functions allow one to find a file // You use FindFileStart by giving it a wildcard (like *.*, *.txt, u??.*, whatever). It returns // a filename in namebuf. // Use FindNextFile to get the next file found with the wildcard given in FindFileStart. // Use FindFileClose to end your search. int fileIndex = 1; char wildsave[10]; bool ddio_FindFileStart(const char *wildcard, char *namebuf) { ASSERT(wildcard); ASSERT(namebuf); fileIndex = 1; char tempbuffer[_MAX_PATH]; if (strrchr(wildcard, ':')) { strcpy(tempbuffer, wildcard); char *c = strrchr(tempbuffer, '*'); strcpy(wildsave, c); *c = '\0'; if (!ddio_DirExists(tempbuffer)) return (false); } else { strcpy(wildsave, wildcard); } ddio_SaveWorkingDir(); ddio_SetWorkingDir(tempbuffer); if (ddio_FindNextFile(namebuf)) return (true); else return (false); } bool ddio_FindNextFile(char *namebuf) { short err; FileParam fpb; CInfoPBRec cpb; Str255 volName = "\p"; short volRefNum = 0; long dirID = 0; ASSERT(namebuf); getAnother: namebuf[0] = 0; err = HGetVol(volName, &volRefNum, &dirID); if (err) return false; /* fpb.ioNamePtr=(unsigned char *)namebuf; fpb.ioFDirIndex=fileIndex; fpb.ioVRefNum=0; // retrun just file info err = PBGetFInfoSync( (ParmBlkPtr)&fpb ); */ // returns both file & dir info cpb.hFileInfo.ioVRefNum = volRefNum; cpb.hFileInfo.ioDirID = dirID; cpb.hFileInfo.ioNamePtr = (unsigned char *)namebuf; cpb.hFileInfo.ioFDirIndex = fileIndex; err = PBGetCatInfoSync(&cpb); // if((cpb.hFileInfo.io.FlAttrib & (1<<4))) if (err == fnfErr) { return (false); } else { p2cstr((unsigned char *)namebuf); fileIndex++; if (PSGlobMatch(wildsave, namebuf, 0, 0)) { return (true); } else { goto getAnother; } } return (false); } void ddio_FindFileClose() { ddio_RestoreWorkingDir(); fileIndex = 1; wildsave[0] = NULL; } // pass in a pathname (could be from ddio_SplitPath), root_path will have the drive name. void ddio_GetRootFromPath(const char *srcPath, char *root_path) { assert(root_path); assert(srcPath); // the first char should be drive letter, second char should be a : // if(!(srcPath[0]==':')){ // everything is ok // strncpy(root_path,srcPath,2); // root_path[2] = '\0'; // }else{ // invalid path (no root) root_path[0] = '\0'; // } } // retrieve root names, free up roots array (allocated with malloc) after use int ddio_GetFileSysRoots(char **roots, int max_roots) { #ifdef FIXED char buffer[100]; int ret = GetLogicalDriveStrings(100, buffer); if (ret == 0) { // there was an error return 0; } if (ret > 100) { // we didn't have enough space return 0; } int count = 0; bool done = false; char *strptr = buffer; char *string; int strsize; while ((count < max_roots) && (!done)) { if (*strptr != 0) { strsize = strlen(strptr); string = roots[count] = (char *)mem_malloc(strsize); if (!string) break; // remove the trailing \ from windows strncpy(string, strptr, strsize - 1); string[strsize - 1] = '\0'; strptr += (strsize + 1); count++; } else done = true; } return count; #endif // FIXED return 0; } // given a path, it cleans it up (if the path is c:\windows\..\dos it would make it c:\dos) // srcPath is the original path // dest is the finished cleaned path. // dest should be at least _MAX_PATH in size void ddio_CleanPath(char *dest, const char *srcPath) { strcpy(dest, srcPath); // break the path into directories char **directories; int dirs; int path_length; // make sure the path ends with a \ for sanity path_length = strlen(dest); if (dest[path_length - 1] != ':') { dest[path_length] = ':'; dest[path_length + 1] = '\0'; path_length++; } // now divide the full path into seperate NULL terminated strings,counting the number // of directories in the process dirs = 0; char *strptr = dest; while (*strptr != '\0') { if (*strptr == ':') { *strptr = '\0'; dirs++; } strptr++; } // check to make sure we have a directory, if we don't then return the original path given if (dirs == 0) { strcpy(dest, srcPath); return; } // allocate the memory needed for the seperate strings of each directory directories = (char **)mem_malloc(sizeof(char *) * dirs); if (!directories) { strcpy(dest, srcPath); return; } // now get all the directories, and place into the individual strings strptr = dest; int count = 0; while (count < dirs) { directories[count] = mem_strdup(strptr); strptr += strlen(strptr) + 1; count++; } // now the fun part, figure out the correct order of the directories int *dir_order; dir_order = (int *)mem_malloc(sizeof(int) * dirs); if (!dir_order) { strcpy(dest, srcPath); return; } for (count = 0; count < dirs; count++) dir_order[count] = -1; // a -1 means the end of the sequence // now build the order based on the indicies int curr_index = 0; for (count = 0; count < dirs; count++) { if (!stricmp(directories[count], "..")) { // we have to back up a directory curr_index--; // back up if (curr_index < 0) curr_index = 0; // can't go further than root dir_order[curr_index] = -1; // invalidate current slot } else if (stricmp(directories[count], ".")) { // we have a normal directory, add it's index dir_order[curr_index] = count; curr_index++; } } // now rebuild the correct path for use, when we hit -1, we're done dest[0] = '\0'; for (count = 0; count < dirs; count++) { if (dir_order[count] == -1) break; else { strcat(dest, directories[dir_order[count]]); strcat(dest, ":"); } } // now remove trailing \ char path_length = strlen(dest); if ((path_length > 0) && (dest[path_length - 1] == ':')) dest[path_length - 1] = '\0'; // free up all the allocated memory and we're done for (count = 0; count < dirs; count++) { if (directories[count]) mem_free(directories[count]); } if (directories) mem_free(directories); if (dir_order) mem_free(dir_order); } // given a path (with no filename), it will return the parent path // srcPath is the source given path // dest is where the parent path will be placed // returns true on success // dest should be at least _MAX_PATH in length bool ddio_GetParentPath(char *dest, const char *srcPath) { assert(srcPath); assert(dest); strcpy(dest, srcPath); char *c = strrchr(dest, ':'); *c = '\0'; return true; } // Finds a full path from a relative path // Parameters: full_path - filled in with the fully-specified path. Buffer must be at least _MAX_PATH bytes long // rel_path - a path specification, either relative or absolute // Returns TRUE if successful, FALSE if an error bool ddio_GetFullPath(char *full_path, const char *rel_path) { char old_path[_MAX_PATH]; ddio_GetWorkingDir(old_path, sizeof(old_path)); // save old directory if (!ddio_SetWorkingDir(rel_path)) // try switching to new directory return 0; // couldn't switch, so return error ddio_GetWorkingDir(full_path, _MAX_PATH); // get path from the OS ddio_SetWorkingDir(old_path); // now restore old path return 1; } // Renames file // Returns true on success or false on an error bool ddio_RenameFile(char *oldfile, char *newfile) { int rcode = rename(oldfile, newfile); if (!rcode) return true; else return false; } // Give a volume label to look for, and if it's found returns a path // If it isn't found, return "" char *ddio_GetCDDrive(char *vol) { bool res = true; ddio_SaveWorkingDir(); res = ddio_DirExists(vol); ddio_RestoreWorkingDir(); if (res) return mem_strdup(vol); else return '\0'; } int ddio_CheckLockFile(const char *dir) { return 0; } int ddio_CreateLockFile(const char *dir) { return 0; } int ddio_DeleteLockFile(const char *dir) { return 0; } // routine to take a DOS path and turn it into a macintosh // pathname. void macify_dospath(const char *dos_path, char *mac_path) { assert(dos_path != NULL); assert(mac_path != NULL); mac_path[0] = 0; // Remove leading relative directory references int i = 0; if (dos_path[i] == '.') { if (!strnicmp(dos_path, "..\\", 3)) { strcat(mac_path, "::"); i += 3; } else if (!strnicmp(dos_path, ".\\", 2)) { strcat(mac_path, ":"); i += 2; } while (dos_path[i] == '.') { if (!strnicmp(&(dos_path[i]), "..\\", 3)) { strcat(mac_path, ":"); i += 3; } else if (!strnicmp(&(dos_path[i]), ".\\", 2)) { i += 2; } } strcat(mac_path, &(dos_path[i])); } else // no leading relative references { // Check if this is a full pathname if (dos_path[0] == '\\') { // Get current volume name Str255 volName = "\p"; short volRefNum = 0; long dirID = 0; OSErr err = noErr; err = HGetVol(volName, &volRefNum, &dirID); assert(err == noErr); p2cstr(volName); strcat(mac_path, (char *)volName); strcat(mac_path, ":"); strcat(mac_path, &(dos_path[1])); } else { strcat(mac_path, ":"); strcat(mac_path, dos_path); } } // Leading references have been resolved // Now replace remaining '/' with ':' char *p = NULL; while ((p = strchr(mac_path, '\\')) != NULL) { *p = ':'; } } #include //#include #include #include "file_io.h" #define text_type 'TEXT' #define binary_type 'BINA' #define creator 'GSCe' FILE *mac_fopen(char *filename, const char *open_mode) { __file_modes mode; short permission; OSErr ioResult; short refNum; OSType file_type; FILE *file; FSSpec spec; Str255 macName; strcpy((char *)macName, filename); c2pstr((char *)macName); ioResult = FSMakeFSSpec(0, 0L, macName, &spec); if (!__get_file_modes(open_mode, &mode)) return (NULL); permission = (mode.io_mode == __read) ? fsRdPerm : fsRdWrPerm; ioResult = FSpOpenDF(&spec, permission, &refNum); if (ioResult) { if (ioResult != fnfErr || mode.open_mode == __must_exist) return (NULL); file_type = 'GSCf'; // file_type = (mode.binary_io) ? binary_type : text_type; if (!(ioResult = FSpCreate(&spec, creator, file_type, smSystemScript))) ioResult = FSpOpenDF(&spec, permission, &refNum); if (ioResult) return (NULL); } else if (mode.open_mode == __create_or_truncate) { ioResult = SetEOF(refNum, 0); if (ioResult) { FSClose(refNum); return (NULL); } } file = __handle_open(refNum, open_mode); if (!file) FSClose(refNum); return (file); } FILE *FSp_fopen(ConstFSSpecPtr spec, const char *open_mode, OSType type) { __file_modes mode; short permission; OSErr ioResult; short refNum; OSType file_type; FILE *file; if (!__get_file_modes(open_mode, &mode)) return (NULL); permission = (mode.io_mode == __read) ? fsRdPerm : fsRdWrPerm; ioResult = FSpOpenDF(spec, permission, &refNum); if (ioResult) { if (ioResult != fnfErr || mode.open_mode == __must_exist) return (NULL); if (!(ioResult = FSpCreate(spec, creator, type, smSystemScript))) ioResult = FSpOpenDF(spec, permission, &refNum); if (ioResult) return (NULL); } else if (mode.open_mode == __create_or_truncate) { ioResult = SetEOF(refNum, 0); if (ioResult) { FSClose(refNum); return (NULL); } } file = __handle_open(refNum, open_mode); if (!file) FSClose(refNum); return (file); }