|
|
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.12! root 9: const char File_rcsid[] = "Hatari $Id: file.c,v 1.51 2008/03/18 00:56:32 thothy 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.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.12! root 722:
! 723: /* Make sure that path name ends with a slash */
! 724: File_AddSlashToEndFileName(pPathName);
1.1.1.6 root 725: }
1.1.1.11 root 726:
727:
728: /*-----------------------------------------------------------------------*/
729: /**
730: * Remove given number of path elements from the end of the given path.
731: * Leaves '/' at the end if path still has directories. Given path
732: * may not be empty.
733: */
734: void File_PathShorten(char *path, int dirs)
735: {
736: int i, n = 0;
737: /* ignore last char, it may or may not be '/' */
738: i = strlen(path)-1;
739: assert(i >= 0);
740: while(i > 0 && n < dirs) {
741: if (path[--i] == PATHSEP)
742: n++;
743: }
744: if (path[i] == PATHSEP) {
745: path[i+1] = '\0';
746: } else {
747: path[0] = PATHSEP;
748: path[1] = '\0';
749: }
750: }
751:
752:
753: /*-----------------------------------------------------------------------*/
754: /*
755: If "/." or "/.." at end, remove that and in case of ".." remove
756: also preceding dir (go one dir up). Leave '/' at the end of
757: the path.
758: */
759: void File_HandleDotDirs(char *path)
760: {
761: int len = strlen(path);
762: if (len >= 2 &&
763: path[len-2] == PATHSEP &&
764: path[len-1] == '.')
765: {
766: /* keep in same dir */
767: path[len-1] = '\0';
768: }
769: else if (len >= 3 &&
770: path[len-3] == PATHSEP &&
771: path[len-2] == '.' &&
772: path[len-1] == '.')
773: {
774: /* go one dir up */
775: if (len == 3) {
776: path[1] = 0; /* already root */
777: } else {
778: char *ptr;
779: path[len-3] = 0;
780: ptr = strrchr(path, PATHSEP);
781: if (ptr)
782: *(ptr+1) = 0;
783: }
784: }
785: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.