Annotation of previous/src/file.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

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