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