|
|
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.7 ! root 9: char File_rcsid[] = "Hatari $Id: file.c,v 1.16 2004/10/31 17:32:50 thothy Exp $";
1.1 root 10:
11: #include <sys/types.h>
12: #include <sys/stat.h>
13: #include <fcntl.h>
1.1.1.6 root 14: #include <unistd.h>
15:
16: #include <zlib.h>
1.1 root 17:
18: #include "main.h"
1.1.1.7 ! root 19: #include "dialog.h"
1.1 root 20: #include "file.h"
21: #include "floppy.h"
22: #include "createBlankImage.h"
23: #include "memAlloc.h"
24: #include "misc.h"
25:
26:
1.1.1.3 root 27:
1.1.1.6 root 28: #if defined(__BEOS__) || (defined(__sun) && defined(__SVR4))
29: /* The scandir() and alphasort() functions aren't available on
30: * BeOS and Solaris, so let's declare them here... */
1.1.1.3 root 31: #include <dirent.h>
32:
33: #undef DIRSIZ
34:
35: #define DIRSIZ(dp) \
36: ((sizeof(struct dirent) - sizeof(dp)->d_name) + \
37: (((dp)->d_reclen + 1 + 3) &~ 3))
38:
1.1.1.6 root 39: #if defined(__sun) && defined(__SVR4)
1.1.1.7 ! root 40: # define dirfd(d) ((d)->dd_fd)
! 41: #elif defined(__BEOS__)
! 42: # define dirfd(d) ((d)->fd)
1.1.1.6 root 43: #endif
44:
1.1 root 45:
46: /*-----------------------------------------------------------------------*/
47: /*
1.1.1.3 root 48: Alphabetic order comparison routine for those who want it.
1.1 root 49: */
1.1.1.3 root 50: int alphasort(const void *d1, const void *d2)
1.1 root 51: {
1.1.1.3 root 52: return(strcmp((*(struct dirent **)d1)->d_name, (*(struct dirent **)d2)->d_name));
53: }
1.1 root 54:
55:
1.1.1.3 root 56: /*-----------------------------------------------------------------------*/
57: /*
58: Scan a directory for all its entries
59: */
1.1.1.7 ! root 60: int scandir(const char *dirname, struct dirent ***namelist, int (*select)(struct dirent *), int (*dcomp)(const void *, const void *))
1.1.1.3 root 61: {
62: register struct dirent *d, *p, **names;
63: register size_t nitems;
64: struct stat stb;
65: long arraysz;
66: DIR *dirp;
1.1 root 67:
1.1.1.3 root 68: if ((dirp = opendir(dirname)) == NULL)
69: return(-1);
1.1 root 70:
1.1.1.7 ! root 71: if (fstat(dirfd(dirp), &stb) < 0)
1.1.1.3 root 72: return(-1);
1.1 root 73:
1.1.1.3 root 74: /*
75: * estimate the array size by taking the size of the directory file
76: * and dividing it by a multiple of the minimum size entry.
77: */
78: arraysz = (stb.st_size / 24);
1.1 root 79:
1.1.1.3 root 80: names = (struct dirent **)malloc(arraysz * sizeof(struct dirent *));
81: if (names == NULL)
82: return(-1);
1.1 root 83:
1.1.1.3 root 84: nitems = 0;
1.1 root 85:
1.1.1.3 root 86: while ((d = readdir(dirp)) != NULL) {
1.1 root 87:
1.1.1.3 root 88: if (select != NULL && !(*select)(d))
89: continue; /* just selected names */
1.1 root 90:
1.1.1.3 root 91: /*
92: * Make a minimum size copy of the data
93: */
1.1 root 94:
1.1.1.3 root 95: p = (struct dirent *)malloc(DIRSIZ(d));
96: if (p == NULL)
97: return(-1);
1.1 root 98:
1.1.1.3 root 99: p->d_ino = d->d_ino;
100: p->d_reclen = d->d_reclen;
101: /*p->d_namlen = d->d_namlen;*/
1.1.1.7 ! root 102: memcpy(p->d_name, d->d_name, p->d_reclen + 1);
1.1 root 103:
1.1.1.3 root 104: /*
105: * Check to make sure the array has space left and
106: * realloc the maximum size.
107: */
1.1 root 108:
1.1.1.3 root 109: if (++nitems >= arraysz) {
1.1 root 110:
1.1.1.7 ! root 111: if (fstat(dirfd(dirp), &stb) < 0)
1.1.1.3 root 112: return(-1); /* just might have grown */
1.1 root 113:
1.1.1.3 root 114: arraysz = stb.st_size / 12;
1.1 root 115:
1.1.1.3 root 116: names = (struct dirent **)realloc((char *)names, arraysz * sizeof(struct dirent *));
117: if (names == NULL)
118: return(-1);
119: }
1.1 root 120:
1.1.1.3 root 121: names[nitems-1] = p;
122: }
1.1 root 123:
1.1.1.3 root 124: closedir(dirp);
1.1 root 125:
1.1.1.3 root 126: if (nitems && dcomp != NULL)
127: qsort(names, nitems, sizeof(struct dirent *), dcomp);
1.1 root 128:
1.1.1.3 root 129: *namelist = names;
130:
131: return(nitems);
1.1 root 132: }
133:
134:
1.1.1.3 root 135: #endif /* __BEOS__ */
136:
1.1 root 137:
1.1.1.2 root 138:
139: /*-----------------------------------------------------------------------*/
1.1 root 140: /*
141: Remove any '/'s from end of filenames, but keeps / intact
142: */
143: void File_CleanFileName(char *pszFileName)
144: {
1.1.1.3 root 145: int len;
146:
147: len = strlen(pszFileName);
148:
149: /* Security length check: */
1.1.1.6 root 150: if (len > FILENAME_MAX)
1.1.1.3 root 151: {
1.1.1.6 root 152: pszFileName[FILENAME_MAX-1] = 0;
153: len = FILENAME_MAX;
1.1.1.3 root 154: }
1.1 root 155:
1.1.1.2 root 156: /* Remove end slash from filename! But / remains! Doh! */
1.1.1.3 root 157: if( len>2 && pszFileName[len-1]=='/' )
158: pszFileName[len-1] = 0;
1.1 root 159: }
160:
1.1.1.2 root 161:
162: /*-----------------------------------------------------------------------*/
1.1 root 163: /*
164: Add '/' to end of filename
165: */
166: void File_AddSlashToEndFileName(char *pszFileName)
167: {
1.1.1.2 root 168: /* Check dir/filenames */
1.1 root 169: if (strlen(pszFileName)!=0) {
170: if (pszFileName[strlen(pszFileName)-1]!='/')
1.1.1.2 root 171: strcat(pszFileName,"/"); /* Must use end slash */
1.1 root 172: }
173: }
174:
1.1.1.3 root 175:
1.1 root 176: /*-----------------------------------------------------------------------*/
177: /*
178: Does filename extension match? If so, return TRUE
179: */
180: BOOL File_DoesFileExtensionMatch(char *pszFileName, char *pszExtension)
181: {
182: if ( strlen(pszFileName) < strlen(pszExtension) )
183: return(FALSE);
184: /* Is matching extension? */
185: if ( !strcasecmp(&pszFileName[strlen(pszFileName)-strlen(pszExtension)], pszExtension) )
186: return(TRUE);
187:
188: /* No */
189: return(FALSE);
190: }
191:
1.1.1.2 root 192:
193: /*-----------------------------------------------------------------------*/
1.1 root 194: /*
195: Check if filename is from root
196:
197: Return TRUE if filename is '/', else give FALSE
198: */
199: BOOL File_IsRootFileName(char *pszFileName)
200: {
201: if (pszFileName[0]=='\0') /* If NULL string return! */
202: return(FALSE);
203:
204: if (pszFileName[0]=='/')
205: return(TRUE);
206:
207: return(FALSE);
208: }
209:
1.1.1.2 root 210:
211: /*-----------------------------------------------------------------------*/
1.1 root 212: /*
213: Return string, to remove 'C:' part of filename
214: */
215: char *File_RemoveFileNameDrive(char *pszFileName)
216: {
217: if ( (pszFileName[0]!='\0') && (pszFileName[1]==':') )
218: return(&pszFileName[2]);
219: else
220: return(pszFileName);
221: }
222:
223:
1.1.1.2 root 224: /*-----------------------------------------------------------------------*/
1.1 root 225: /*
226: Check if filename end with a '/'
227:
228: Return TRUE if filename ends with '/'
229: */
230: BOOL File_DoesFileNameEndWithSlash(char *pszFileName)
231: {
232: if (pszFileName[0]=='\0') /* If NULL string return! */
233: return(FALSE);
234:
1.1.1.3 root 235: /* Does string end in a '/'? */
1.1 root 236: if (pszFileName[strlen(pszFileName)-1]=='/')
237: return(TRUE);
238:
239: return(FALSE);
240: }
241:
1.1.1.2 root 242:
243: /*-----------------------------------------------------------------------*/
1.1 root 244: /*
245: Remove any double '/'s from end of filenames. So just the one
246: */
247: void File_RemoveFileNameTrailingSlashes(char *pszFileName)
248: {
249: int Length;
250:
251: /* Do have slash at end of filename? */
252: Length = strlen(pszFileName);
253: if (Length>=3) {
254: if (pszFileName[Length-1]=='/') { /* Yes, have one previous? */
255: if (pszFileName[Length-2]=='/')
256: pszFileName[Length-1] = '\0'; /* then remove it! */
257: }
258: }
259: }
260:
261:
1.1.1.2 root 262: /*-----------------------------------------------------------------------*/
1.1 root 263: /*
1.1.1.6 root 264: Read file from disc into memory, allocate memory for it if need to (pass
265: Address as NULL).
1.1 root 266: */
267: void *File_Read(char *pszFileName, void *pAddress, long *pFileSize, char *ppszExts[])
268: {
1.1.1.6 root 269: void *pFile = NULL;
270: long FileSize = 0;
1.1 root 271:
272: /* Does the file exist? If not, see if can scan for other extensions and try these */
1.1.1.6 root 273: if (!File_Exists(pszFileName) && ppszExts)
274: {
1.1 root 275: /* Try other extensions, if suceeds correct filename is now in 'pszFileName' */
1.1.1.6 root 276: File_FindPossibleExtFileName(pszFileName, ppszExts);
1.1 root 277: }
278:
1.1.1.6 root 279: /* Normal file or gzipped file? */
280: if (File_DoesFileExtensionMatch(pszFileName, ".gz"))
281: {
282: gzFile hGzFile;
283: /* Open and read gzipped file */
284: hGzFile = gzopen(pszFileName, "rb");
285: if (hGzFile != NULL)
286: {
287: /* Find size of file: */
288: do
289: {
290: /* Seek through the file until we hit the end... */
291: gzseek(hGzFile, 1024, SEEK_CUR);
292: }
293: while (!gzeof(hGzFile));
294: FileSize = gztell(hGzFile);
295: gzrewind(hGzFile);
296: /* Find pointer to where to load, allocate memory if pass NULL */
297: if (pAddress)
298: pFile = pAddress;
299: else
300: pFile = malloc(FileSize);
301: /* Read in... */
302: if (pFile)
303: gzread(hGzFile, pFile, FileSize);
1.1 root 304:
1.1.1.6 root 305: gzclose(hGzFile);
306: }
307: }
308: else
309: {
310: FILE *hDiscFile;
311: /* Open and read normal file */
312: hDiscFile = fopen(pszFileName, "rb");
313: if (hDiscFile != NULL)
314: {
315: /* Find size of file: */
316: fseek(hDiscFile, 0, SEEK_END);
317: FileSize = ftell(hDiscFile);
318: fseek(hDiscFile, 0, SEEK_SET);
319: /* Find pointer to where to load, allocate memory if pass NULL */
320: if (pAddress)
321: pFile = pAddress;
322: else
323: pFile = malloc(FileSize);
324: /* Read in... */
325: if (pFile)
326: fread(pFile, 1, FileSize, hDiscFile);
327:
328: fclose(hDiscFile);
329: }
1.1 root 330: }
1.1.1.6 root 331:
1.1.1.2 root 332: /* Store size of file we read in (or 0 if failed) */
1.1 root 333: if (pFileSize)
334: *pFileSize = FileSize;
335:
336: return(pFile); /* Return to where read in/allocated */
337: }
338:
1.1.1.2 root 339:
340: /*-----------------------------------------------------------------------*/
1.1 root 341: /*
1.1.1.6 root 342: Save file to disc, return FALSE if errors
1.1 root 343: */
1.1.1.6 root 344: BOOL File_Save(char *pszFileName, void *pAddress, size_t Size, BOOL bQueryOverwrite)
1.1 root 345: {
1.1.1.6 root 346: BOOL bRet = FALSE;
1.1 root 347:
348: /* Check if need to ask user if to overwrite */
1.1.1.6 root 349: if (bQueryOverwrite)
350: {
1.1 root 351: /* If file exists, ask if OK to overwrite */
352: if (!File_QueryOverwrite(pszFileName))
353: return(FALSE);
354: }
355:
1.1.1.6 root 356: /* Normal file or gzipped file? */
357: if (File_DoesFileExtensionMatch(pszFileName, ".gz"))
358: {
359: gzFile *hGzFile;
360: /* Create a gzipped file: */
361: hGzFile = gzopen(pszFileName, "wb");
362: if (hGzFile != NULL)
363: {
364: /* Write data, set success flag */
365: if (gzwrite(hGzFile, pAddress, Size) == Size)
366: bRet = TRUE;
1.1 root 367:
1.1.1.6 root 368: gzclose(hGzFile);
369: }
370: }
371: else
372: {
373: FILE *hDiscFile;
374: /* Create a normal file: */
375: hDiscFile = fopen(pszFileName, "wb");
376: if (hDiscFile != NULL)
377: {
378: /* Write data, set success flag */
379: if (fwrite(pAddress, 1, Size, hDiscFile) == Size)
380: bRet = TRUE;
381:
382: fclose(hDiscFile);
383: }
1.1 root 384: }
385:
386: return(bRet);
387: }
388:
1.1.1.2 root 389:
390: /*-----------------------------------------------------------------------*/
1.1 root 391: /*
392: Return size of file, -1 if error
393: */
394: int File_Length(char *pszFileName)
395: {
1.1.1.3 root 396: FILE *DiscFile;
1.1 root 397: int FileSize;
1.1.1.3 root 398: DiscFile = fopen(pszFileName, "rb");
399: if (DiscFile!=NULL) {
400: fseek(DiscFile, 0, SEEK_END);
401: FileSize = ftell(DiscFile);
402: fseek(DiscFile, 0, SEEK_SET);
403: fclose(DiscFile);
1.1 root 404: return(FileSize);
405: }
406:
407: return(-1);
408: }
409:
1.1.1.2 root 410:
411: /*-----------------------------------------------------------------------*/
1.1 root 412: /*
413: Return TRUE if file exists
414: */
415: BOOL File_Exists(char *pszFileName)
416: {
1.1.1.4 root 417: FILE *DiscFile;
1.1 root 418:
1.1.1.2 root 419: /* Attempt to open file */
1.1.1.4 root 420: DiscFile = fopen(pszFileName, "rb");
421: if (DiscFile!=NULL) {
422: fclose(DiscFile);
1.1 root 423: return(TRUE);
1.1.1.2 root 424: }
1.1 root 425: return(FALSE);
426: }
427:
1.1.1.2 root 428:
429: /*-----------------------------------------------------------------------*/
1.1 root 430: /*
431: Delete file, return TRUE if OK
432: */
433: BOOL File_Delete(char *pszFileName)
434: {
1.1.1.2 root 435: /* Delete the file (must be closed first) */
1.1 root 436: return( remove(pszFileName) );
437: }
438:
1.1.1.2 root 439:
440: /*-----------------------------------------------------------------------*/
1.1 root 441: /*
442: Find if file exists, and if so ask user if OK to overwrite
443: */
1.1.1.2 root 444: BOOL File_QueryOverwrite(char *pszFileName)
1.1 root 445: {
446:
1.1.1.7 ! root 447: char szString[FILENAME_MAX + 26];
1.1 root 448:
1.1.1.2 root 449: /* Try and find if file exists */
1.1.1.6 root 450: if (File_Exists(pszFileName))
451: {
1.1.1.2 root 452: /* File does exist, are we OK to overwrite? */
1.1.1.7 ! root 453: snprintf(szString, sizeof(szString), "File '%s' exists, overwrite?", pszFileName);
! 454: fprintf(stderr, "%s\n", szString);
! 455: return DlgAlert_Query(szString);
1.1 root 456: }
457:
458: return(TRUE);
459: }
460:
1.1.1.2 root 461:
462: /*-----------------------------------------------------------------------*/
1.1 root 463: /*
464: Try filename with various extensions and check if file exists - if so return correct name
465: */
1.1.1.3 root 466: BOOL File_FindPossibleExtFileName(char *pszFileName, char *ppszExts[])
1.1 root 467: {
1.1.1.3 root 468: char szSrcDir[256], szSrcName[128], szSrcExt[32];
1.1.1.6 root 469: char szTempFileName[FILENAME_MAX];
1.1 root 470: int i=0;
471:
1.1.1.3 root 472: /* Split filename into parts */
473: File_splitpath(pszFileName, szSrcDir, szSrcName, szSrcExt);
1.1 root 474:
1.1.1.3 root 475: /* Scan possible extensions */
1.1 root 476: while(ppszExts[i]) {
1.1.1.3 root 477: /* Re-build with new file extension */
478: File_makepath(szTempFileName, szSrcDir, szSrcName, ppszExts[i]);
479: /* Does this file exist? */
1.1 root 480: if (File_Exists(szTempFileName)) {
1.1.1.3 root 481: /* Copy name for return */
1.1 root 482: strcpy(pszFileName,szTempFileName);
483: return(TRUE);
484: }
485:
1.1.1.3 root 486: /* Next one */
1.1 root 487: i++;
488: }
1.1.1.3 root 489:
1.1.1.2 root 490: /* No, none of the files exist */
1.1 root 491: return(FALSE);
492: }
1.1.1.3 root 493:
494:
495: /*-----------------------------------------------------------------------*/
496: /*
497: Split a complete filename into path, filename and extension.
498: If pExt is NULL, don't split the extension from the file name!
499: */
500: void File_splitpath(char *pSrcFileName, char *pDir, char *pName, char *pExt)
501: {
502: char *ptr1, *ptr2;
503:
504: /* Build pathname: */
505: ptr1 = strrchr(pSrcFileName, '/');
506: if( ptr1 )
507: {
508: strcpy(pDir, pSrcFileName);
509: strcpy(pName, ptr1+1);
510: pDir[ptr1-pSrcFileName+1] = 0;
511: }
512: else
513: {
514: strcpy(pDir, "./");
515: strcpy(pName, pSrcFileName);
516: }
517:
518: /* Build the raw filename: */
519: if( pExt!=NULL )
520: {
521: ptr2 = strrchr(pName+1, '.');
522: if( ptr2 )
523: {
524: pName[ptr2-pName] = 0;
525: /* Copy the file extension: */
526: strcpy(pExt, ptr2+1);
527: }
528: else
529: pExt[0] = 0;
530: }
531: }
532:
533:
534: /*-----------------------------------------------------------------------*/
535: /*
536: Build a complete filename from path, filename and extension.
537: pExt can also be NULL.
538: */
539: void File_makepath(char *pDestFileName, char *pDir, char *pName, char *pExt)
540: {
541: strcpy(pDestFileName, pDir);
542: if( strlen(pDestFileName)==0 )
543: strcpy(pDestFileName, "./");
544: if( pDestFileName[strlen(pDestFileName)-1]!='/' )
545: strcat(pDestFileName, "/");
546:
547: strcat(pDestFileName, pName);
548:
549: if( pExt!=NULL )
550: {
551: if( strlen(pExt)>0 && pExt[0]!='.' )
552: strcat(pDestFileName, ".");
553: strcat(pDestFileName, pExt);
554: }
555: }
556:
557:
558: /*-----------------------------------------------------------------------*/
559: /*
560: Shrink a file name to a certain length and insert some dots if we cut
561: something away (usefull for showing file names in a dialog).
562: */
563: void File_ShrinkName(char *pDestFileName, char *pSrcFileName, int maxlen)
564: {
565: int srclen = strlen(pSrcFileName);
566: if( srclen<maxlen )
567: strcpy(pDestFileName, pSrcFileName); /* It fits! */
568: else
569: {
570: strncpy(pDestFileName, pSrcFileName, maxlen/2);
571: if(maxlen&1) /* even or uneven? */
572: pDestFileName[maxlen/2-1] = 0;
573: else
574: pDestFileName[maxlen/2-2] = 0;
575: strcat(pDestFileName, "...");
576: strcat(pDestFileName, &pSrcFileName[strlen(pSrcFileName)-maxlen/2+1]);
577: }
578: }
579:
1.1.1.6 root 580:
581: /*-----------------------------------------------------------------------*/
582: /*
583: Create a clean absolute file name from a (possibly) relative file name.
584: I.e. filter out all occurancies of "./" and "../".
585: pFileName needs to point to a buffer of at least FILENAME_MAX bytes.
586: */
587: void File_MakeAbsoluteName(char *pFileName)
588: {
589: char *pTempName = Memory_Alloc(FILENAME_MAX);
590: int inpos, outpos;
591:
592: inpos = 0;
593:
594: /* Is it already an absolute name? */
595: if(pFileName[0] == '/')
596: {
597: outpos = 0;
598: }
599: else
600: {
601: getcwd(pTempName, FILENAME_MAX);
602: File_AddSlashToEndFileName(pTempName);
603: outpos = strlen(pTempName);
604: }
605:
606: /* Now filter out the relative paths "./" and "../" */
607: while (pFileName[inpos] != 0 && outpos < FILENAME_MAX)
608: {
609: if (pFileName[inpos] == '.' && pFileName[inpos+1] == '/')
610: {
611: /* Ignore "./" */
612: inpos += 2;
613: }
614: else if (pFileName[inpos] == '.' && pFileName[inpos+1] == '.' && pFileName[inpos+2] == '/')
615: {
616: /* Handle "../" */
617: char *pSlashPos;
618: inpos += 3;
619: pTempName[outpos - 1] = 0;
620: pSlashPos = strrchr(pTempName, '/');
621: if (pSlashPos)
622: {
623: *(pSlashPos + 1) = 0;
624: outpos = strlen(pTempName);
625: }
626: else
627: {
628: pTempName[0] = '/';
629: outpos = 1;
630: }
631: }
632: else
633: {
634: /* Copy until next slash or end of input string */
635: while (pFileName[inpos] != 0 && outpos < FILENAME_MAX)
636: {
637: pTempName[outpos++] = pFileName[inpos++];
638: if (pFileName[inpos - 1] == '/') break;
639: }
640: }
641: }
642:
643: pTempName[outpos] = 0;
644:
645: strcpy(pFileName, pTempName); /* Copy back */
646: Memory_Free(pTempName);
647: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.