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