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