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