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

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

unix.superglobalmegacorp.com

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