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