|
|
1.1 root 1: /* 1.1.1.6 root 2: Hatari - file.c 1.1 root 3: 1.1.1.19! root 4: This file is distributed under the GNU General Public License, version 2 ! 5: or at your option any later version. Read the file gpl.txt for details. 1.1.1.5 root 6: 1.1.1.6 root 7: Common file access functions. 1.1 root 8: */ 1.1.1.14 root 9: const char File_fileid[] = "Hatari file.c : " __DATE__ " " __TIME__; 1.1.1.11 root 10: 1.1 root 11: #include <sys/types.h> 12: #include <sys/stat.h> 1.1.1.15 root 13: #include <sys/time.h> 1.1 root 14: #include <fcntl.h> 1.1.1.6 root 15: #include <unistd.h> 1.1.1.11 root 16: #include <assert.h> 17: #include <errno.h> 1.1.1.6 root 18: #include <zlib.h> 1.1 root 19: 1.1.1.15 root 20: #if defined(WIN32) && !defined(_VCWIN_) 1.1.1.14 root 21: #include <winsock2.h> 22: #endif 23: 1.1 root 24: #include "main.h" 1.1.1.7 root 25: #include "dialog.h" 1.1 root 26: #include "file.h" 27: #include "createBlankImage.h" 1.1.1.15 root 28: #include "str.h" 1.1.1.10 root 29: #include "zip.h" 1.1 root 30: 1.1.1.16 root 31: #if defined(WIN32) 32: #define ftello ftell 33: #endif 1.1.1.2 root 34: 35: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 36: /** 37: * Remove any '/'s from end of filenames, but keeps / intact 38: */ 1.1 root 39: void File_CleanFileName(char *pszFileName) 40: { 1.1.1.10 root 41: int len; 1.1.1.3 root 42: 1.1.1.10 root 43: len = strlen(pszFileName); 1.1.1.3 root 44: 1.1.1.16 root 45: /* Remove end slashes from filename! But / remains! Doh! */ 46: while (len > 2 && pszFileName[--len] == PATHSEP) 47: pszFileName[len] = '\0'; 1.1 root 48: } 49: 1.1.1.2 root 50: 51: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 52: /** 53: * Add '/' to end of filename 54: */ 1.1 root 55: void File_AddSlashToEndFileName(char *pszFileName) 56: { 1.1.1.10 root 57: int len; 58: 59: len = strlen(pszFileName); 60: 61: /* Check dir/filenames */ 62: if (len != 0) 63: { 1.1.1.11 root 64: if (pszFileName[len-1] != PATHSEP) 1.1.1.10 root 65: { 66: pszFileName[len] = PATHSEP; /* Must use end slash */ 1.1.1.11 root 67: pszFileName[len+1] = '\0'; 1.1.1.10 root 68: } 69: } 1.1 root 70: } 71: 1.1.1.3 root 72: 1.1 root 73: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 74: /** 75: * Does filename extension match? If so, return TRUE 76: */ 1.1.1.13 root 77: bool File_DoesFileExtensionMatch(const char *pszFileName, const char *pszExtension) 1.1 root 78: { 1.1.1.10 root 79: if (strlen(pszFileName) < strlen(pszExtension)) 1.1.1.15 root 80: return false; 1.1.1.10 root 81: /* Is matching extension? */ 82: if (!strcasecmp(&pszFileName[strlen(pszFileName)-strlen(pszExtension)], pszExtension)) 1.1.1.15 root 83: return true; 1.1 root 84: 1.1.1.10 root 85: /* No */ 1.1.1.15 root 86: return false; 1.1 root 87: } 88: 1.1.1.2 root 89: 90: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 91: /** 92: * Check if filename is from root 1.1.1.16 root 93: * 1.1.1.11 root 94: * Return TRUE if filename is '/', else give FALSE 95: */ 1.1.1.13 root 96: static bool File_IsRootFileName(const char *pszFileName) 1.1 root 97: { 1.1.1.11 root 98: if (pszFileName[0] == '\0') /* If NULL string return! */ 1.1.1.15 root 99: return false; 1.1 root 100: 1.1.1.11 root 101: if (pszFileName[0] == PATHSEP) 1.1.1.15 root 102: return true; 1.1 root 103: 1.1.1.10 root 104: #ifdef WIN32 1.1.1.11 root 105: if (pszFileName[1] == ':') 1.1.1.15 root 106: return true; 107: #endif 108: 109: #ifdef GEKKO 110: if (strlen(pszFileName) > 2 && pszFileName[2] == ':') // sd: 111: return true; 112: if (strlen(pszFileName) > 3 && pszFileName[3] == ':') // fat: 113: return true; 114: if (strlen(pszFileName) > 4 && pszFileName[4] == ':') // fat3: 115: return true; 1.1.1.10 root 116: #endif 117: 1.1.1.15 root 118: return false; 1.1 root 119: } 120: 1.1.1.2 root 121: 122: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 123: /** 124: * Return string, to remove 'C:' part of filename 125: */ 1.1.1.8 root 126: const char *File_RemoveFileNameDrive(const char *pszFileName) 1.1 root 127: { 1.1.1.11 root 128: if ( (pszFileName[0] != '\0') && (pszFileName[1] == ':') ) 1.1.1.10 root 129: return &pszFileName[2]; 130: else 131: return pszFileName; 1.1 root 132: } 133: 134: 1.1.1.2 root 135: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 136: /** 137: * Check if filename end with a '/' 1.1.1.16 root 138: * 1.1.1.11 root 139: * Return TRUE if filename ends with '/' 140: */ 1.1.1.13 root 141: bool File_DoesFileNameEndWithSlash(char *pszFileName) 1.1 root 142: { 1.1.1.10 root 143: if (pszFileName[0] == '\0') /* If NULL string return! */ 1.1.1.15 root 144: return false; 1.1.1.16 root 145: 1.1.1.10 root 146: /* Does string end in a '/'? */ 147: if (pszFileName[strlen(pszFileName)-1] == PATHSEP) 1.1.1.15 root 148: return true; 1.1.1.16 root 149: 1.1.1.15 root 150: return false; 1.1 root 151: } 152: 153: 1.1.1.2 root 154: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 155: /** 156: * Read file from disk into allocated buffer and return the buffer 157: * or NULL for error. If pFileSize is non-NULL, read file size 158: * is set to that. 159: */ 160: Uint8 *File_Read(const char *pszFileName, long *pFileSize, const char * const ppszExts[]) 1.1 root 161: { 1.1.1.11 root 162: char *filepath = NULL; 1.1.1.15 root 163: Uint8 *pFile = NULL; 1.1.1.10 root 164: long FileSize = 0; 1.1 root 165: 1.1.1.10 root 166: /* Does the file exist? If not, see if can scan for other extensions and try these */ 167: if (!File_Exists(pszFileName) && ppszExts) 168: { 1.1.1.11 root 169: /* Try other extensions, if succeeds, returns correct one */ 170: filepath = File_FindPossibleExtFileName(pszFileName, ppszExts); 1.1.1.10 root 171: } 1.1.1.11 root 172: if (!filepath) 173: filepath = strdup(pszFileName); 1.1.1.10 root 174: 175: /* Is it a gzipped file? */ 1.1.1.11 root 176: if (File_DoesFileExtensionMatch(filepath, ".gz")) 1.1.1.10 root 177: { 178: gzFile hGzFile; 179: /* Open and read gzipped file */ 1.1.1.11 root 180: hGzFile = gzopen(filepath, "rb"); 1.1.1.10 root 181: if (hGzFile != NULL) 182: { 183: /* Find size of file: */ 184: do 185: { 186: /* Seek through the file until we hit the end... */ 1.1.1.19! root 187: char tmp[1024]; ! 188: if (gzread(hGzFile, tmp, sizeof(tmp)) < 0) ! 189: { ! 190: fprintf(stderr, "Failed to read gzip file!\n"); ! 191: return NULL; ! 192: } 1.1.1.10 root 193: } 194: while (!gzeof(hGzFile)); 195: FileSize = gztell(hGzFile); 196: gzrewind(hGzFile); 197: /* Read in... */ 1.1.1.11 root 198: pFile = malloc(FileSize); 1.1.1.10 root 199: if (pFile) 200: FileSize = gzread(hGzFile, pFile, FileSize); 201: 202: gzclose(hGzFile); 203: } 204: } 1.1.1.11 root 205: else if (File_DoesFileExtensionMatch(filepath, ".zip")) 1.1.1.10 root 206: { 207: /* It is a .ZIP file! -> Try to load the first file in the archive */ 1.1.1.11 root 208: pFile = ZIP_ReadFirstFile(filepath, &FileSize, ppszExts); 1.1.1.10 root 209: } 210: else /* It is a normal file */ 211: { 212: FILE *hDiskFile; 213: /* Open and read normal file */ 1.1.1.11 root 214: hDiskFile = fopen(filepath, "rb"); 1.1.1.10 root 215: if (hDiskFile != NULL) 216: { 217: /* Find size of file: */ 218: fseek(hDiskFile, 0, SEEK_END); 219: FileSize = ftell(hDiskFile); 220: fseek(hDiskFile, 0, SEEK_SET); 221: /* Read in... */ 1.1.1.11 root 222: pFile = malloc(FileSize); 1.1.1.10 root 223: if (pFile) 224: FileSize = fread(pFile, 1, FileSize, hDiskFile); 225: 226: fclose(hDiskFile); 227: } 228: } 1.1.1.11 root 229: free(filepath); 1.1.1.10 root 230: 231: /* Store size of file we read in (or 0 if failed) */ 232: if (pFileSize) 233: *pFileSize = FileSize; 1.1 root 234: 1.1.1.10 root 235: return pFile; /* Return to where read in/allocated */ 1.1 root 236: } 237: 1.1.1.2 root 238: 239: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 240: /** 241: * Save file to disk, return FALSE if errors 242: */ 1.1.1.13 root 243: bool File_Save(const char *pszFileName, const Uint8 *pAddress, size_t Size, bool bQueryOverwrite) 1.1 root 244: { 1.1.1.15 root 245: bool bRet = false; 1.1 root 246: 1.1.1.10 root 247: /* Check if need to ask user if to overwrite */ 248: if (bQueryOverwrite) 249: { 250: /* If file exists, ask if OK to overwrite */ 251: if (!File_QueryOverwrite(pszFileName)) 1.1.1.15 root 252: return false; 1.1.1.10 root 253: } 254: 255: /* Normal file or gzipped file? */ 256: if (File_DoesFileExtensionMatch(pszFileName, ".gz")) 257: { 258: gzFile hGzFile; 259: /* Create a gzipped file: */ 260: hGzFile = gzopen(pszFileName, "wb"); 261: if (hGzFile != NULL) 262: { 263: /* Write data, set success flag */ 264: if (gzwrite(hGzFile, pAddress, Size) == (int)Size) 1.1.1.15 root 265: bRet = true; 1.1.1.10 root 266: 267: gzclose(hGzFile); 268: } 269: } 270: else 271: { 272: FILE *hDiskFile; 273: /* Create a normal file: */ 274: hDiskFile = fopen(pszFileName, "wb"); 275: if (hDiskFile != NULL) 276: { 277: /* Write data, set success flag */ 278: if (fwrite(pAddress, 1, Size, hDiskFile) == Size) 1.1.1.15 root 279: bRet = true; 1.1.1.10 root 280: 281: fclose(hDiskFile); 282: } 283: } 1.1 root 284: 1.1.1.10 root 285: return bRet; 1.1 root 286: } 287: 1.1.1.2 root 288: 289: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 290: /** 291: * Return size of file, -1 if error 292: */ 1.1.1.16 root 293: off_t File_Length(const char *pszFileName) 1.1 root 294: { 1.1.1.10 root 295: FILE *hDiskFile; 1.1.1.16 root 296: off_t FileSize; 1.1.1.9 root 297: 1.1.1.10 root 298: hDiskFile = fopen(pszFileName, "rb"); 299: if (hDiskFile!=NULL) 300: { 301: fseek(hDiskFile, 0, SEEK_END); 1.1.1.16 root 302: FileSize = ftello(hDiskFile); 1.1.1.10 root 303: fseek(hDiskFile, 0, SEEK_SET); 304: fclose(hDiskFile); 305: return FileSize; 306: } 1.1 root 307: 1.1.1.10 root 308: return -1; 1.1 root 309: } 310: 1.1.1.2 root 311: 312: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 313: /** 314: * Return TRUE if file exists, is readable or writable at least and is not 1.1.1.16 root 315: * a directory. 1.1.1.11 root 316: */ 1.1.1.13 root 317: bool File_Exists(const char *filename) 1.1.1.11 root 318: { 319: struct stat buf; 320: if (stat(filename, &buf) == 0 && 321: (buf.st_mode & (S_IRUSR|S_IWUSR)) && !(buf.st_mode & S_IFDIR)) 322: { 323: /* file points to user readable regular file */ 1.1.1.15 root 324: return true; 1.1.1.11 root 325: } 1.1.1.15 root 326: return false; 1.1.1.11 root 327: } 1.1 root 328: 1.1.1.11 root 329: 330: /*-----------------------------------------------------------------------*/ 331: /** 1.1.1.16 root 332: * Return TRUE if directory exists. 1.1.1.11 root 333: */ 1.1.1.17 root 334: bool File_DirExists(const char *path) 1.1.1.11 root 335: { 336: struct stat buf; 1.1.1.17 root 337: return (stat(path, &buf) == 0 && S_ISDIR(buf.st_mode)); 1.1 root 338: } 339: 1.1.1.2 root 340: 341: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 342: /** 343: * Find if file exists, and if so ask user if OK to overwrite 344: */ 1.1.1.13 root 345: bool File_QueryOverwrite(const char *pszFileName) 1.1 root 346: { 1.1.1.11 root 347: const char *fmt; 348: char *szString; 1.1.1.15 root 349: bool ret = true; 1.1 root 350: 1.1.1.10 root 351: /* Try and find if file exists */ 352: if (File_Exists(pszFileName)) 353: { 1.1.1.11 root 354: fmt = "File '%s' exists, overwrite?"; 1.1.1.10 root 355: /* File does exist, are we OK to overwrite? */ 1.1.1.11 root 356: szString = malloc(strlen(pszFileName) + strlen(fmt) + 1); 357: sprintf(szString, fmt, pszFileName); 1.1.1.10 root 358: fprintf(stderr, "%s\n", szString); 1.1.1.11 root 359: ret = DlgAlert_Query(szString); 360: free(szString); 1.1.1.10 root 361: } 1.1.1.11 root 362: return ret; 1.1 root 363: } 364: 1.1.1.2 root 365: 366: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 367: /** 368: * Try filename with various extensions and check if file exists 369: * - if so, return allocated string which caller should free, 370: * otherwise return NULL 371: */ 372: char * File_FindPossibleExtFileName(const char *pszFileName, const char * const ppszExts[]) 1.1 root 373: { 1.1.1.10 root 374: char *szSrcDir, *szSrcName, *szSrcExt; 1.1.1.11 root 375: int i; 1.1.1.16 root 376: 1.1.1.10 root 377: /* Allocate temporary memory for strings: */ 1.1.1.11 root 378: szSrcDir = malloc(3 * FILENAME_MAX); 379: if (!szSrcDir) 1.1.1.10 root 380: { 381: perror("File_FindPossibleExtFileName"); 1.1.1.15 root 382: return false; 1.1.1.10 root 383: } 384: szSrcName = szSrcDir + FILENAME_MAX; 385: szSrcExt = szSrcName + FILENAME_MAX; 1.1.1.16 root 386: 1.1.1.10 root 387: /* Split filename into parts */ 1.1.1.11 root 388: File_SplitPath(pszFileName, szSrcDir, szSrcName, szSrcExt); 1.1.1.10 root 389: 390: /* Scan possible extensions */ 1.1.1.11 root 391: for (i = 0; ppszExts[i]; i++) 1.1.1.10 root 392: { 1.1.1.11 root 393: char *szTempFileName; 394: 1.1.1.10 root 395: /* Re-build with new file extension */ 1.1.1.11 root 396: szTempFileName = File_MakePath(szSrcDir, szSrcName, ppszExts[i]); 397: if (szTempFileName) 1.1.1.10 root 398: { 1.1.1.11 root 399: /* Does this file exist? */ 400: if (File_Exists(szTempFileName)) 401: { 402: free(szSrcDir); 403: /* return filename without extra strings */ 404: return szTempFileName; 405: } 406: free(szTempFileName); 1.1.1.10 root 407: } 408: } 1.1.1.11 root 409: free(szSrcDir); 410: return NULL; 1.1 root 411: } 1.1.1.3 root 412: 413: 414: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 415: /** 416: * Split a complete filename into path, filename and extension. 417: * If pExt is NULL, don't split the extension from the file name! 418: * It's safe for pSrcFileName and pDir to be the same string. 419: */ 420: void File_SplitPath(const char *pSrcFileName, char *pDir, char *pName, char *pExt) 1.1.1.3 root 421: { 1.1.1.10 root 422: char *ptr1, *ptr2; 1.1.1.3 root 423: 1.1.1.10 root 424: /* Build pathname: */ 425: ptr1 = strrchr(pSrcFileName, PATHSEP); 426: if (ptr1) 427: { 428: strcpy(pName, ptr1+1); 1.1.1.16 root 429: memmove(pDir, pSrcFileName, ptr1-pSrcFileName); 430: pDir[ptr1-pSrcFileName] = 0; 1.1.1.10 root 431: } 432: else 433: { 1.1.1.11 root 434: strcpy(pName, pSrcFileName); 1.1.1.10 root 435: sprintf(pDir, ".%c", PATHSEP); 436: } 437: 438: /* Build the raw filename: */ 439: if (pExt != NULL) 440: { 441: ptr2 = strrchr(pName+1, '.'); 442: if (ptr2) 443: { 444: pName[ptr2-pName] = 0; 445: /* Copy the file extension: */ 446: strcpy(pExt, ptr2+1); 447: } 448: else 449: pExt[0] = 0; 450: } 1.1.1.3 root 451: } 452: 453: 454: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 455: /** 456: * Construct a complete filename from path, filename and extension. 457: * Return the constructed filename. 458: * pExt can also be NULL. 459: */ 460: char * File_MakePath(const char *pDir, const char *pName, const char *pExt) 1.1.1.3 root 461: { 1.1.1.11 root 462: char *filepath; 1.1.1.10 root 463: int len; 464: 1.1.1.11 root 465: /* dir or "." + "/" + name + "." + ext + \0 */ 466: len = strlen(pDir) + 2 + strlen(pName) + 1 + (pExt ? strlen(pExt) : 0) + 1; 467: filepath = malloc(len); 468: if (!filepath) 1.1.1.10 root 469: { 1.1.1.11 root 470: perror("File_MakePath"); 471: return NULL; 1.1.1.10 root 472: } 1.1.1.11 root 473: if (!pDir[0]) 474: { 475: filepath[0] = '.'; 476: filepath[1] = '\0'; 477: } else { 478: strcpy(filepath, pDir); 479: } 480: len = strlen(filepath); 481: if (filepath[len-1] != PATHSEP) 482: { 483: filepath[len++] = PATHSEP; 484: } 485: strcpy(&filepath[len], pName); 1.1.1.10 root 486: 1.1.1.11 root 487: if (pExt != NULL && pExt[0]) 1.1.1.10 root 488: { 1.1.1.11 root 489: len += strlen(pName); 490: if (pExt[0] != '.') 491: strcat(&filepath[len++], "."); 492: strcat(&filepath[len], pExt); 1.1.1.10 root 493: } 1.1.1.11 root 494: return filepath; 1.1.1.3 root 495: } 496: 497: 498: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 499: /** 500: * Shrink a file name to a certain length and insert some dots if we cut 501: * something away (useful for showing file names in a dialog). 502: */ 503: void File_ShrinkName(char *pDestFileName, const char *pSrcFileName, int maxlen) 1.1.1.3 root 504: { 1.1.1.10 root 505: int srclen = strlen(pSrcFileName); 506: if (srclen < maxlen) 507: strcpy(pDestFileName, pSrcFileName); /* It fits! */ 508: else 509: { 1.1.1.11 root 510: assert(maxlen > 6); 1.1.1.10 root 511: strncpy(pDestFileName, pSrcFileName, maxlen/2); 512: if (maxlen&1) /* even or uneven? */ 513: pDestFileName[maxlen/2-1] = 0; 514: else 515: pDestFileName[maxlen/2-2] = 0; 516: strcat(pDestFileName, "..."); 517: strcat(pDestFileName, &pSrcFileName[strlen(pSrcFileName)-maxlen/2+1]); 518: } 1.1.1.3 root 519: } 520: 1.1.1.6 root 521: 522: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 523: /** 524: * Open given filename in given mode and handle "stdout" & "stderr" 525: * filenames specially. Return FILE* to the opened file or NULL on error. 526: */ 527: FILE *File_Open(const char *path, const char *mode) 528: { 529: int wr = 0, rd = 0; 530: FILE *fp; 531: 1.1.1.14 root 532: /* empty name signifies file that shouldn't be opened/enabled */ 533: if (!*path) 534: return NULL; 1.1.1.16 root 535: 1.1.1.11 root 536: /* special "stdout" and "stderr" files can be used 537: * for files which are written or appended 538: */ 539: if (strchr(mode, 'w') || strchr(mode, 'a')) 540: wr = 1; 541: if (strchr(mode, 'r')) 542: rd = 1; 543: if (strcmp(path, "stdin") == 0) 544: { 545: assert(rd && !wr); 546: return stdin; 547: } 548: if (strcmp(path, "stdout") == 0) 549: { 550: assert(wr && !rd); 551: return stdout; 552: } 553: if (strcmp(path, "stderr") == 0) 554: { 555: assert(wr && !rd); 556: return stderr; 557: } 558: /* Open a normal log file */ 559: fp = fopen(path, mode); 560: if (!fp) 1.1.1.18 root 561: fprintf(stderr, "Can't open file '%s' (wr=%i, rd=%i):\n %s\n", 562: path, wr, rd, strerror(errno)); 563: 1.1.1.11 root 564: /* printf("'%s' opened in mode '%s'\n", path, mode, fp); */ 565: return fp; 566: } 567: 568: 569: /*-----------------------------------------------------------------------*/ 570: /** 571: * Close given FILE pointer and return the closed pointer 572: * as NULL for the idiom "fp = File_Close(fp);" 573: */ 574: FILE *File_Close(FILE *fp) 575: { 576: if (fp && fp != stdin && fp != stdout && fp != stderr) 577: { 578: fclose(fp); 579: } 580: return NULL; 581: } 582: 583: 584: /*-----------------------------------------------------------------------*/ 585: /** 1.1.1.14 root 586: * Check if input is available at the specified file descriptor. 587: */ 588: bool File_InputAvailable(FILE *fp) 589: { 1.1.1.15 root 590: #if HAVE_SELECT 1.1.1.14 root 591: fd_set rfds; 592: struct timeval tv; 593: int fh; 594: int ret; 595: 596: if (!fp || (fh = fileno(fp)) == -1) 597: return false; 598: 599: /* Add the file handle to the file descriptor set */ 600: FD_ZERO(&rfds); 601: FD_SET(fh, &rfds); 602: 603: /* Return immediately */ 604: tv.tv_sec = 0; 605: tv.tv_usec = 0; 606: 607: /* Check if file descriptor is ready for a read */ 608: ret = select(fh+1, &rfds, NULL, NULL, &tv); 609: 610: if (ret > 0) 611: return true; /* Data available */ 1.1.1.15 root 612: #endif 1.1.1.14 root 613: 614: return false; 615: } 616: 617: 618: /*-----------------------------------------------------------------------*/ 619: /** 1.1.1.11 root 620: * Wrapper for File_MakeAbsoluteName() which special-cases stdin/out/err 1.1.1.14 root 621: * named files and empty file name. The given buffer should be opened 622: * with File_Open() and closed with File_Close() if this function is used! 1.1.1.11 root 623: * (On Linux one can use /dev/stdout etc, this is intended for other OSes) 624: */ 625: void File_MakeAbsoluteSpecialName(char *path) 626: { 1.1.1.14 root 627: if (path[0] && 628: strcmp(path, "stdin") != 0 && 1.1.1.11 root 629: strcmp(path, "stdout") != 0 && 630: strcmp(path, "stderr") != 0) 631: File_MakeAbsoluteName(path); 632: } 633: 634: /*-----------------------------------------------------------------------*/ 635: /** 636: * Create a clean absolute file name from a (possibly) relative file name. 637: * I.e. filter out all occurancies of "./" and "../". 638: * pFileName needs to point to a buffer of at least FILENAME_MAX bytes. 639: */ 1.1.1.6 root 640: void File_MakeAbsoluteName(char *pFileName) 641: { 1.1.1.10 root 642: char *pTempName; 643: int inpos, outpos; 1.1.1.6 root 644: 1.1.1.11 root 645: #if defined (__AMIGAOS4__) 646: /* This function does not work on Amiga OS */ 647: return; 648: #endif 649: 1.1.1.10 root 650: inpos = 0; 651: pTempName = malloc(FILENAME_MAX); 652: if (!pTempName) 653: { 654: perror("File_MakeAbsoluteName - malloc"); 655: return; 656: } 657: 658: /* Is it already an absolute name? */ 659: if (File_IsRootFileName(pFileName)) 660: { 661: outpos = 0; 662: } 663: else 664: { 665: if (!getcwd(pTempName, FILENAME_MAX)) 666: { 667: perror("File_MakeAbsoluteName - getcwd"); 668: free(pTempName); 669: return; 670: } 671: File_AddSlashToEndFileName(pTempName); 672: outpos = strlen(pTempName); 673: } 674: 675: /* Now filter out the relative paths "./" and "../" */ 676: while (pFileName[inpos] != 0 && outpos < FILENAME_MAX) 677: { 678: if (pFileName[inpos] == '.' && pFileName[inpos+1] == PATHSEP) 679: { 680: /* Ignore "./" */ 681: inpos += 2; 682: } 1.1.1.11 root 683: else if (pFileName[inpos] == '.' && pFileName[inpos+1] == 0) 684: { 685: inpos += 1; /* Ignore "." at the end of the path string */ 686: if (outpos > 1) 687: pTempName[outpos - 1] = 0; /* Remove the last slash, too */ 688: } 689: else if (pFileName[inpos] == '.' && pFileName[inpos+1] == '.' 690: && (pFileName[inpos+2] == PATHSEP || pFileName[inpos+2] == 0)) 1.1.1.10 root 691: { 692: /* Handle "../" */ 693: char *pSlashPos; 1.1.1.11 root 694: inpos += 2; 1.1.1.10 root 695: pTempName[outpos - 1] = 0; 696: pSlashPos = strrchr(pTempName, PATHSEP); 697: if (pSlashPos) 698: { 699: *(pSlashPos + 1) = 0; 700: outpos = strlen(pTempName); 701: } 702: else 703: { 704: pTempName[0] = PATHSEP; 705: outpos = 1; 706: } 1.1.1.11 root 707: /* Were we already at the end of the string or is there more to come? */ 708: if (pFileName[inpos] == PATHSEP) 709: { 710: /* There was a slash after the '..', so skip slash and 711: * simply proceed with next part */ 712: inpos += 1; 713: } 714: else 715: { 716: /* We were at the end of the string, so let's remove the slash 717: * from the new string, too */ 718: if (outpos > 1) 719: pTempName[outpos - 1] = 0; 720: } 1.1.1.10 root 721: } 722: else 723: { 724: /* Copy until next slash or end of input string */ 725: while (pFileName[inpos] != 0 && outpos < FILENAME_MAX) 726: { 727: pTempName[outpos++] = pFileName[inpos++]; 728: if (pFileName[inpos - 1] == PATHSEP) 729: break; 730: } 731: } 732: } 1.1.1.6 root 733: 1.1.1.10 root 734: pTempName[outpos] = 0; 1.1.1.6 root 735: 1.1.1.10 root 736: strcpy(pFileName, pTempName); /* Copy back */ 737: free(pTempName); 1.1.1.8 root 738: } 739: 740: 741: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 742: /** 743: * Create a valid path name from a possibly invalid name by erasing invalid 1.1.1.16 root 744: * path parts at the end of the string. If string doesn't contain any path 745: * component, it will be pointed to the root directory. Empty string will 746: * be left as-is to prevent overwriting past allocated area. 1.1.1.11 root 747: */ 1.1.1.8 root 748: void File_MakeValidPathName(char *pPathName) 749: { 1.1.1.10 root 750: struct stat dirstat; 751: char *pLastSlash; 1.1.1.8 root 752: 1.1.1.10 root 753: do 754: { 755: /* Check for a valid path */ 756: if (stat(pPathName, &dirstat) == 0 && S_ISDIR(dirstat.st_mode)) 757: { 758: break; 759: } 760: 761: pLastSlash = strrchr(pPathName, PATHSEP); 762: if (pLastSlash) 763: { 764: /* Erase the (probably invalid) part after the last slash */ 765: *pLastSlash = 0; 766: } 1.1.1.16 root 767: else 1.1.1.10 root 768: { 1.1.1.16 root 769: if (pPathName[0]) 770: { 771: /* point to root */ 772: pPathName[0] = PATHSEP; 773: pPathName[1] = 0; 774: } 775: return; 1.1.1.10 root 776: } 777: } 778: while (pLastSlash); 1.1.1.12 root 779: 780: /* Make sure that path name ends with a slash */ 781: File_AddSlashToEndFileName(pPathName); 1.1.1.6 root 782: } 1.1.1.11 root 783: 784: 785: /*-----------------------------------------------------------------------*/ 786: /** 787: * Remove given number of path elements from the end of the given path. 788: * Leaves '/' at the end if path still has directories. Given path 789: * may not be empty. 790: */ 791: void File_PathShorten(char *path, int dirs) 792: { 793: int i, n = 0; 794: /* ignore last char, it may or may not be '/' */ 795: i = strlen(path)-1; 796: assert(i >= 0); 797: while(i > 0 && n < dirs) { 798: if (path[--i] == PATHSEP) 799: n++; 800: } 801: if (path[i] == PATHSEP) { 802: path[i+1] = '\0'; 803: } else { 804: path[0] = PATHSEP; 805: path[1] = '\0'; 806: } 807: } 808: 809: 810: /*-----------------------------------------------------------------------*/ 811: /* 812: If "/." or "/.." at end, remove that and in case of ".." remove 813: also preceding dir (go one dir up). Leave '/' at the end of 814: the path. 815: */ 816: void File_HandleDotDirs(char *path) 817: { 818: int len = strlen(path); 819: if (len >= 2 && 820: path[len-2] == PATHSEP && 821: path[len-1] == '.') 822: { 823: /* keep in same dir */ 824: path[len-1] = '\0'; 825: } 826: else if (len >= 3 && 827: path[len-3] == PATHSEP && 828: path[len-2] == '.' && 829: path[len-1] == '.') 830: { 831: /* go one dir up */ 832: if (len == 3) { 833: path[1] = 0; /* already root */ 834: } else { 835: char *ptr; 836: path[len-3] = 0; 837: ptr = strrchr(path, PATHSEP); 838: if (ptr) 839: *(ptr+1) = 0; 840: } 841: } 842: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.