|
|
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.10! root 9: const char File_rcsid[] = "Hatari $Id: file.c,v 1.33 2006/08/08 07:19:15 thothy Exp $";
1.1 root 10:
1.1.1.10! root 11: #include <string.h>
! 12: #include <strings.h>
1.1 root 13: #include <sys/types.h>
14: #include <sys/stat.h>
15: #include <fcntl.h>
1.1.1.6 root 16: #include <unistd.h>
17:
18: #include <zlib.h>
1.1 root 19:
20: #include "main.h"
1.1.1.7 root 21: #include "dialog.h"
1.1 root 22: #include "file.h"
23: #include "createBlankImage.h"
1.1.1.10! root 24: #include "zip.h"
1.1 root 25:
1.1.1.2 root 26:
27: /*-----------------------------------------------------------------------*/
1.1 root 28: /*
29: Remove any '/'s from end of filenames, but keeps / intact
30: */
31: void File_CleanFileName(char *pszFileName)
32: {
1.1.1.10! root 33: int len;
1.1.1.3 root 34:
1.1.1.10! root 35: len = strlen(pszFileName);
1.1.1.3 root 36:
1.1.1.10! root 37: /* Security length check: */
! 38: if (len > FILENAME_MAX)
! 39: {
! 40: pszFileName[FILENAME_MAX-1] = 0;
! 41: len = FILENAME_MAX;
! 42: }
! 43:
! 44: /* Remove end slash from filename! But / remains! Doh! */
! 45: if (len > 2 && pszFileName[len-1] == PATHSEP)
! 46: pszFileName[len-1] = 0;
1.1 root 47: }
48:
1.1.1.2 root 49:
50: /*-----------------------------------------------------------------------*/
1.1 root 51: /*
52: Add '/' to end of filename
53: */
54: void File_AddSlashToEndFileName(char *pszFileName)
55: {
1.1.1.10! root 56: int len;
! 57:
! 58: len = strlen(pszFileName);
! 59:
! 60: /* Check dir/filenames */
! 61: if (len != 0)
! 62: {
! 63: if (pszFileName[strlen(pszFileName)-1] != PATHSEP)
! 64: {
! 65: pszFileName[len] = PATHSEP; /* Must use end slash */
! 66: pszFileName[len+1] = 0;
! 67: }
! 68: }
1.1 root 69: }
70:
1.1.1.3 root 71:
1.1 root 72: /*-----------------------------------------------------------------------*/
73: /*
74: Does filename extension match? If so, return TRUE
75: */
1.1.1.8 root 76: BOOL File_DoesFileExtensionMatch(const char *pszFileName, const char *pszExtension)
1.1 root 77: {
1.1.1.10! root 78: if (strlen(pszFileName) < strlen(pszExtension))
! 79: return FALSE;
! 80: /* Is matching extension? */
! 81: if (!strcasecmp(&pszFileName[strlen(pszFileName)-strlen(pszExtension)], pszExtension))
! 82: return TRUE;
1.1 root 83:
1.1.1.10! root 84: /* No */
! 85: return FALSE;
1.1 root 86: }
87:
1.1.1.2 root 88:
89: /*-----------------------------------------------------------------------*/
1.1 root 90: /*
91: Check if filename is from root
92:
93: Return TRUE if filename is '/', else give FALSE
94: */
95: BOOL File_IsRootFileName(char *pszFileName)
96: {
1.1.1.10! root 97: if (pszFileName[0]=='\0') /* If NULL string return! */
! 98: return FALSE;
1.1 root 99:
1.1.1.10! root 100: if (pszFileName[0]==PATHSEP)
! 101: return TRUE;
1.1 root 102:
1.1.1.10! root 103: #ifdef WIN32
! 104:
! 105: if (pszFileName[1]==':')
! 106: return TRUE;
! 107: #endif
! 108:
! 109: return FALSE;
1.1 root 110: }
111:
1.1.1.2 root 112:
113: /*-----------------------------------------------------------------------*/
1.1 root 114: /*
115: Return string, to remove 'C:' part of filename
116: */
1.1.1.8 root 117: const char *File_RemoveFileNameDrive(const char *pszFileName)
1.1 root 118: {
1.1.1.10! root 119: if ( (pszFileName[0]!='\0') && (pszFileName[1]==':') )
! 120: return &pszFileName[2];
! 121: else
! 122: return pszFileName;
1.1 root 123: }
124:
125:
1.1.1.2 root 126: /*-----------------------------------------------------------------------*/
1.1 root 127: /*
128: Check if filename end with a '/'
129:
130: Return TRUE if filename ends with '/'
131: */
132: BOOL File_DoesFileNameEndWithSlash(char *pszFileName)
133: {
1.1.1.10! root 134: if (pszFileName[0] == '\0') /* If NULL string return! */
! 135: return FALSE;
1.1 root 136:
1.1.1.10! root 137: /* Does string end in a '/'? */
! 138: if (pszFileName[strlen(pszFileName)-1] == PATHSEP)
! 139: return TRUE;
1.1 root 140:
1.1.1.10! root 141: return FALSE;
1.1 root 142: }
143:
144:
1.1.1.2 root 145: /*-----------------------------------------------------------------------*/
1.1 root 146: /*
1.1.1.9 root 147: Read file from disk into memory, allocate memory for it if need to (pass
1.1.1.6 root 148: Address as NULL).
1.1 root 149: */
1.1.1.10! root 150: void *File_Read(char *pszFileName, void *pAddress, long *pFileSize, const char * const ppszExts[])
1.1 root 151: {
1.1.1.10! root 152: void *pFile = NULL;
! 153: long FileSize = 0;
1.1 root 154:
1.1.1.10! root 155: /* Does the file exist? If not, see if can scan for other extensions and try these */
! 156: if (!File_Exists(pszFileName) && ppszExts)
! 157: {
! 158: /* Try other extensions, if suceeds correct filename is now in 'pszFileName' */
! 159: File_FindPossibleExtFileName(pszFileName, ppszExts);
! 160: }
! 161:
! 162: /* Is it a gzipped file? */
! 163: if (File_DoesFileExtensionMatch(pszFileName, ".gz"))
! 164: {
! 165: gzFile hGzFile;
! 166: /* Open and read gzipped file */
! 167: hGzFile = gzopen(pszFileName, "rb");
! 168: if (hGzFile != NULL)
! 169: {
! 170: /* Find size of file: */
! 171: do
! 172: {
! 173: /* Seek through the file until we hit the end... */
! 174: gzseek(hGzFile, 1024, SEEK_CUR);
! 175: }
! 176: while (!gzeof(hGzFile));
! 177: FileSize = gztell(hGzFile);
! 178: gzrewind(hGzFile);
! 179: /* Find pointer to where to load, allocate memory if pass NULL */
! 180: if (pAddress)
! 181: pFile = pAddress;
! 182: else
! 183: pFile = malloc(FileSize);
! 184: /* Read in... */
! 185: if (pFile)
! 186: FileSize = gzread(hGzFile, pFile, FileSize);
! 187:
! 188: gzclose(hGzFile);
! 189: }
! 190: }
! 191: else if (File_DoesFileExtensionMatch(pszFileName, ".zip"))
! 192: {
! 193: /* It is a .ZIP file! -> Try to load the first file in the archive */
! 194: pFile = ZIP_ReadFirstFile(pszFileName, &FileSize, ppszExts);
! 195: if (pFile && pAddress)
! 196: {
! 197: memcpy(pAddress, pFile, FileSize);
! 198: free(pFile);
! 199: pFile = pAddress;
! 200: }
! 201: }
! 202: else /* It is a normal file */
! 203: {
! 204: FILE *hDiskFile;
! 205: /* Open and read normal file */
! 206: hDiskFile = fopen(pszFileName, "rb");
! 207: if (hDiskFile != NULL)
! 208: {
! 209: /* Find size of file: */
! 210: fseek(hDiskFile, 0, SEEK_END);
! 211: FileSize = ftell(hDiskFile);
! 212: fseek(hDiskFile, 0, SEEK_SET);
! 213: /* Find pointer to where to load, allocate memory if pass NULL */
! 214: if (pAddress)
! 215: pFile = pAddress;
! 216: else
! 217: pFile = malloc(FileSize);
! 218: /* Read in... */
! 219: if (pFile)
! 220: FileSize = fread(pFile, 1, FileSize, hDiskFile);
! 221:
! 222: fclose(hDiskFile);
! 223: }
! 224: }
! 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 root 235: /*
1.1.1.9 root 236: Save file to disk, return FALSE if errors
1.1 root 237: */
1.1.1.10! root 238: BOOL File_Save(char *pszFileName, const void *pAddress, size_t Size, BOOL bQueryOverwrite)
1.1 root 239: {
1.1.1.10! 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))
! 247: return FALSE;
! 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)
! 260: bRet = TRUE;
! 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)
! 274: bRet = TRUE;
! 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 root 285: /*
286: Return size of file, -1 if error
287: */
1.1.1.8 root 288: int File_Length(const char *pszFileName)
1.1 root 289: {
1.1.1.10! root 290: FILE *hDiskFile;
! 291: int 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);
! 297: FileSize = ftell(hDiskFile);
! 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 root 308: /*
309: Return TRUE if file exists
310: */
1.1.1.8 root 311: BOOL File_Exists(const char *pszFileName)
1.1 root 312: {
1.1.1.10! root 313: FILE *hDiskFile;
1.1 root 314:
1.1.1.10! root 315: /* Attempt to open file */
! 316: hDiskFile = fopen(pszFileName, "rb");
! 317: if (hDiskFile!=NULL)
! 318: {
! 319: fclose(hDiskFile);
! 320: return TRUE;
! 321: }
! 322: return FALSE;
1.1 root 323: }
324:
1.1.1.2 root 325:
326: /*-----------------------------------------------------------------------*/
1.1 root 327: /*
328: Find if file exists, and if so ask user if OK to overwrite
329: */
1.1.1.8 root 330: BOOL File_QueryOverwrite(const char *pszFileName)
1.1 root 331: {
1.1.1.10! root 332: char szString[FILENAME_MAX + 26];
1.1 root 333:
1.1.1.10! root 334: /* Try and find if file exists */
! 335: if (File_Exists(pszFileName))
! 336: {
! 337: /* File does exist, are we OK to overwrite? */
! 338: snprintf(szString, sizeof(szString), "File '%s' exists, overwrite?", pszFileName);
! 339: fprintf(stderr, "%s\n", szString);
! 340: return DlgAlert_Query(szString);
! 341: }
1.1 root 342:
1.1.1.10! root 343: return TRUE;
1.1 root 344: }
345:
1.1.1.2 root 346:
347: /*-----------------------------------------------------------------------*/
1.1 root 348: /*
349: Try filename with various extensions and check if file exists - if so return correct name
350: */
1.1.1.10! root 351: BOOL File_FindPossibleExtFileName(char *pszFileName, const char * const ppszExts[])
1.1 root 352: {
1.1.1.10! root 353: char *szSrcDir, *szSrcName, *szSrcExt;
! 354: char *szTempFileName;
! 355: int i = 0;
! 356: BOOL bFileExists = FALSE;
! 357:
! 358: /* Allocate temporary memory for strings: */
! 359: szTempFileName = malloc(4 * FILENAME_MAX);
! 360: if (!szTempFileName)
! 361: {
! 362: perror("File_FindPossibleExtFileName");
! 363: return FALSE;
! 364: }
! 365: szSrcDir = szTempFileName + FILENAME_MAX;
! 366: szSrcName = szSrcDir + FILENAME_MAX;
! 367: szSrcExt = szSrcName + FILENAME_MAX;
! 368:
! 369: /* Split filename into parts */
! 370: File_splitpath(pszFileName, szSrcDir, szSrcName, szSrcExt);
! 371:
! 372: /* Scan possible extensions */
! 373: while(ppszExts[i] && !bFileExists)
! 374: {
! 375: /* Re-build with new file extension */
! 376: File_makepath(szTempFileName, szSrcDir, szSrcName, ppszExts[i]);
! 377: /* Does this file exist? */
! 378: if (File_Exists(szTempFileName))
! 379: {
! 380: /* Copy name for return */
! 381: strcpy(pszFileName, szTempFileName);
! 382: bFileExists = TRUE;
! 383: }
! 384:
! 385: /* Next one */
! 386: i++;
! 387: }
1.1.1.3 root 388:
1.1.1.10! root 389: free(szTempFileName);
1.1.1.8 root 390:
1.1.1.10! root 391: return bFileExists;
1.1 root 392: }
1.1.1.3 root 393:
394:
395: /*-----------------------------------------------------------------------*/
396: /*
397: Split a complete filename into path, filename and extension.
398: If pExt is NULL, don't split the extension from the file name!
399: */
1.1.1.8 root 400: void File_splitpath(const char *pSrcFileName, char *pDir, char *pName, char *pExt)
1.1.1.3 root 401: {
1.1.1.10! root 402: char *ptr1, *ptr2;
1.1.1.3 root 403:
1.1.1.10! root 404: /* Build pathname: */
! 405: ptr1 = strrchr(pSrcFileName, PATHSEP);
! 406: if (ptr1)
! 407: {
! 408: strcpy(pDir, pSrcFileName);
! 409: strcpy(pName, ptr1+1);
! 410: pDir[ptr1-pSrcFileName+1] = 0;
! 411: }
! 412: else
! 413: {
! 414: sprintf(pDir, ".%c", PATHSEP);
! 415: strcpy(pName, pSrcFileName);
! 416: }
! 417:
! 418: /* Build the raw filename: */
! 419: if (pExt != NULL)
! 420: {
! 421: ptr2 = strrchr(pName+1, '.');
! 422: if (ptr2)
! 423: {
! 424: pName[ptr2-pName] = 0;
! 425: /* Copy the file extension: */
! 426: strcpy(pExt, ptr2+1);
! 427: }
! 428: else
! 429: pExt[0] = 0;
! 430: }
1.1.1.3 root 431: }
432:
433:
434: /*-----------------------------------------------------------------------*/
435: /*
436: Build a complete filename from path, filename and extension.
437: pExt can also be NULL.
438: */
1.1.1.8 root 439: void File_makepath(char *pDestFileName, const char *pDir, const char *pName, const char *pExt)
1.1.1.3 root 440: {
1.1.1.10! root 441: int len;
! 442:
! 443: strcpy(pDestFileName, pDir);
! 444: len = strlen(pDestFileName);
! 445:
! 446: if (len == 0)
! 447: sprintf(pDestFileName, ".%c", PATHSEP);
! 448: else if (pDestFileName[len-1] != PATHSEP)
! 449: {
! 450: pDestFileName[len] = PATHSEP;
! 451: pDestFileName[len+1] = 0;
! 452: }
! 453:
! 454: strcat(pDestFileName, pName);
! 455:
! 456: if (pExt != NULL)
! 457: {
! 458: if (strlen(pExt) > 0 && pExt[0] != '.')
! 459: strcat(pDestFileName, ".");
! 460: strcat(pDestFileName, pExt);
! 461: }
1.1.1.3 root 462: }
463:
464:
465: /*-----------------------------------------------------------------------*/
466: /*
467: Shrink a file name to a certain length and insert some dots if we cut
468: something away (usefull for showing file names in a dialog).
469: */
470: void File_ShrinkName(char *pDestFileName, char *pSrcFileName, int maxlen)
471: {
1.1.1.10! root 472: int srclen = strlen(pSrcFileName);
! 473: if (srclen < maxlen)
! 474: strcpy(pDestFileName, pSrcFileName); /* It fits! */
! 475: else
! 476: {
! 477: strncpy(pDestFileName, pSrcFileName, maxlen/2);
! 478: if (maxlen&1) /* even or uneven? */
! 479: pDestFileName[maxlen/2-1] = 0;
! 480: else
! 481: pDestFileName[maxlen/2-2] = 0;
! 482: strcat(pDestFileName, "...");
! 483: strcat(pDestFileName, &pSrcFileName[strlen(pSrcFileName)-maxlen/2+1]);
! 484: }
1.1.1.3 root 485: }
486:
1.1.1.6 root 487:
488: /*-----------------------------------------------------------------------*/
489: /*
490: Create a clean absolute file name from a (possibly) relative file name.
491: I.e. filter out all occurancies of "./" and "../".
492: pFileName needs to point to a buffer of at least FILENAME_MAX bytes.
493: */
494: void File_MakeAbsoluteName(char *pFileName)
495: {
1.1.1.10! root 496: char *pTempName;
! 497: int inpos, outpos;
1.1.1.6 root 498:
1.1.1.10! root 499: inpos = 0;
! 500: pTempName = malloc(FILENAME_MAX);
! 501: if (!pTempName)
! 502: {
! 503: perror("File_MakeAbsoluteName - malloc");
! 504: return;
! 505: }
! 506:
! 507: /* Is it already an absolute name? */
! 508: if (File_IsRootFileName(pFileName))
! 509: {
! 510: outpos = 0;
! 511: }
! 512: else
! 513: {
! 514: if (!getcwd(pTempName, FILENAME_MAX))
! 515: {
! 516: perror("File_MakeAbsoluteName - getcwd");
! 517: free(pTempName);
! 518: return;
! 519: }
! 520: File_AddSlashToEndFileName(pTempName);
! 521: outpos = strlen(pTempName);
! 522: }
! 523:
! 524: /* Now filter out the relative paths "./" and "../" */
! 525: while (pFileName[inpos] != 0 && outpos < FILENAME_MAX)
! 526: {
! 527: if (pFileName[inpos] == '.' && pFileName[inpos+1] == PATHSEP)
! 528: {
! 529: /* Ignore "./" */
! 530: inpos += 2;
! 531: }
! 532: else if (pFileName[inpos] == '.' && pFileName[inpos+1] == '.' && pFileName[inpos+2] == PATHSEP)
! 533: {
! 534: /* Handle "../" */
! 535: char *pSlashPos;
! 536: inpos += 3;
! 537: pTempName[outpos - 1] = 0;
! 538: pSlashPos = strrchr(pTempName, PATHSEP);
! 539: if (pSlashPos)
! 540: {
! 541: *(pSlashPos + 1) = 0;
! 542: outpos = strlen(pTempName);
! 543: }
! 544: else
! 545: {
! 546: pTempName[0] = PATHSEP;
! 547: outpos = 1;
! 548: }
! 549: }
! 550: else
! 551: {
! 552: /* Copy until next slash or end of input string */
! 553: while (pFileName[inpos] != 0 && outpos < FILENAME_MAX)
! 554: {
! 555: pTempName[outpos++] = pFileName[inpos++];
! 556: if (pFileName[inpos - 1] == PATHSEP)
! 557: break;
! 558: }
! 559: }
! 560: }
1.1.1.6 root 561:
1.1.1.10! root 562: pTempName[outpos] = 0;
1.1.1.6 root 563:
1.1.1.10! root 564: strcpy(pFileName, pTempName); /* Copy back */
! 565: free(pTempName);
1.1.1.8 root 566: }
567:
568:
569: /*-----------------------------------------------------------------------*/
570: /*
571: Create a valid path name from a possibly invalid name by erasing invalid
572: path parts at the end of the string.
573: pPathName needs to point to a buffer of at least FILENAME_MAX bytes.
574: */
575: void File_MakeValidPathName(char *pPathName)
576: {
1.1.1.10! root 577: struct stat dirstat;
! 578: char *pLastSlash;
1.1.1.8 root 579:
1.1.1.10! root 580: do
! 581: {
! 582: /* Check for a valid path */
! 583: if (stat(pPathName, &dirstat) == 0 && S_ISDIR(dirstat.st_mode))
! 584: {
! 585: break;
! 586: }
! 587:
! 588: pLastSlash = strrchr(pPathName, PATHSEP);
! 589: if (pLastSlash)
! 590: {
! 591: /* Erase the (probably invalid) part after the last slash */
! 592: *pLastSlash = 0;
! 593: }
! 594: else
! 595: {
! 596: /* Path name seems to be completely invalid -> set to root directory */
! 597: pPathName[0] = PATHSEP;
! 598: pPathName[1] = 0;
! 599: }
! 600: }
! 601: while (pLastSlash);
1.1.1.6 root 602: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.