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

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

unix.superglobalmegacorp.com

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