Annotation of hatari/src/file.c, revision 1.1.1.13

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.