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