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

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

unix.superglobalmegacorp.com

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