Annotation of previous/src/file.c, revision 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.