Annotation of embedaddon/ntp/lib/isc/win32/file.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (C) 2004, 2007  Internet Systems Consortium, Inc. ("ISC")
        !             3:  * Copyright (C) 2000-2002  Internet Software Consortium.
        !             4:  *
        !             5:  * Permission to use, copy, modify, and/or distribute this software for any
        !             6:  * purpose with or without fee is hereby granted, provided that the above
        !             7:  * copyright notice and this permission notice appear in all copies.
        !             8:  *
        !             9:  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
        !            10:  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
        !            11:  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
        !            12:  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
        !            13:  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
        !            14:  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
        !            15:  * PERFORMANCE OF THIS SOFTWARE.
        !            16:  */
        !            17: 
        !            18: /* $Id: file.c,v 1.31 2007/06/19 23:47:19 tbox Exp $ */
        !            19: 
        !            20: #include <config.h>
        !            21: 
        !            22: #undef rename
        !            23: #include <errno.h>
        !            24: #include <limits.h>
        !            25: #include <stdlib.h>
        !            26: #include <io.h>
        !            27: #include <process.h>
        !            28: 
        !            29: #include <sys/stat.h>
        !            30: #include <fcntl.h>
        !            31: #include <sys/utime.h>
        !            32: 
        !            33: #include <isc/file.h>
        !            34: #include <isc/result.h>
        !            35: #include <isc/time.h>
        !            36: #include <isc/util.h>
        !            37: #include <isc/stat.h>
        !            38: 
        !            39: #include "errno2result.h"
        !            40: 
        !            41: /*
        !            42:  * Emulate UNIX mkstemp, which returns an open FD to the new file
        !            43:  *
        !            44:  */
        !            45: static int
        !            46: gettemp(char *path, int *doopen) {
        !            47:        char *start, *trv;
        !            48:        struct stat sbuf;
        !            49:        int pid;
        !            50: 
        !            51:        trv = strrchr(path, 'X');
        !            52:        trv++;
        !            53:        pid = getpid();
        !            54:        /* extra X's get set to 0's */
        !            55:        while (*--trv == 'X') {
        !            56:                *trv = (pid % 10) + '0';
        !            57:                pid /= 10;
        !            58:        }
        !            59:        /*
        !            60:         * check the target directory; if you have six X's and it
        !            61:         * doesn't exist this runs for a *very* long time.
        !            62:         */
        !            63:        for (start = trv + 1;; --trv) {
        !            64:                if (trv <= path)
        !            65:                        break;
        !            66:                if (*trv == '\\') {
        !            67:                        *trv = '\0';
        !            68:                        if (stat(path, &sbuf))
        !            69:                                return (0);
        !            70:                        if (!S_ISDIR(sbuf.st_mode)) {
        !            71:                                errno = ENOTDIR;
        !            72:                                return (0);
        !            73:                        }
        !            74:                        *trv = '\\';
        !            75:                        break;
        !            76:                }
        !            77:        }
        !            78: 
        !            79:        for (;;) {
        !            80:                if (doopen) {
        !            81:                        if ((*doopen =
        !            82:                            open(path, O_CREAT|O_EXCL|O_RDWR,
        !            83:                                 _S_IREAD | _S_IWRITE)) >= 0)
        !            84:                                return (1);
        !            85:                        if (errno != EEXIST)
        !            86:                                return (0);
        !            87:                } else if (stat(path, &sbuf))
        !            88:                        return (errno == ENOENT ? 1 : 0);
        !            89: 
        !            90:                /* tricky little algorithm for backward compatibility */
        !            91:                for (trv = start;;) {
        !            92:                        if (!*trv)
        !            93:                                return (0);
        !            94:                        if (*trv == 'z')
        !            95:                                *trv++ = 'a';
        !            96:                        else {
        !            97:                                if (isdigit(*trv))
        !            98:                                        *trv = 'a';
        !            99:                                else
        !           100:                                        ++*trv;
        !           101:                                break;
        !           102:                        }
        !           103:                }
        !           104:        }
        !           105:        /*NOTREACHED*/
        !           106: }
        !           107: 
        !           108: static int
        !           109: mkstemp(char *path) {
        !           110:        int fd;
        !           111: 
        !           112:        return (gettemp(path, &fd) ? fd : -1);
        !           113: }
        !           114: 
        !           115: /*
        !           116:  * XXXDCL As the API for accessing file statistics undoubtedly gets expanded,
        !           117:  * it might be good to provide a mechanism that allows for the results
        !           118:  * of a previous stat() to be used again without having to do another stat,
        !           119:  * such as perl's mechanism of using "_" in place of a file name to indicate
        !           120:  * that the results of the last stat should be used.  But then you get into
        !           121:  * annoying MP issues.   BTW, Win32 has stat().
        !           122:  */
        !           123: static isc_result_t
        !           124: file_stats(const char *file, struct stat *stats) {
        !           125:        isc_result_t result = ISC_R_SUCCESS;
        !           126: 
        !           127:        REQUIRE(file != NULL);
        !           128:        REQUIRE(stats != NULL);
        !           129: 
        !           130:        if (stat(file, stats) != 0)
        !           131:                result = isc__errno2result(errno);
        !           132: 
        !           133:        return (result);
        !           134: }
        !           135: 
        !           136: /*
        !           137:  * isc_file_safemovefile is needed to be defined here to ensure that
        !           138:  * any file with the new name is renamed to a backup name and then the
        !           139:  * rename is done. If all goes well then the backup can be deleted,
        !           140:  * otherwise it gets renamed back.
        !           141:  */
        !           142: 
        !           143: int
        !           144: isc_file_safemovefile(const char *oldname, const char *newname) {
        !           145:        BOOL filestatus;
        !           146:        char buf[512];
        !           147:        struct stat sbuf;
        !           148:        BOOL exists = FALSE;
        !           149:        int tmpfd;
        !           150: 
        !           151:        /*
        !           152:         * Make sure we have something to do
        !           153:         */
        !           154:        if (stat(oldname, &sbuf) != 0) {
        !           155:                errno = ENOENT;
        !           156:                return (-1);
        !           157:        }
        !           158: 
        !           159:        /*
        !           160:         * Rename to a backup the new file if it still exists
        !           161:         */
        !           162:        if (stat(newname, &sbuf) == 0) {
        !           163:                exists = TRUE;
        !           164:                strcpy(buf, newname);
        !           165:                strcat(buf, ".XXXXX");
        !           166:                tmpfd = mkstemp(buf);
        !           167:                if (tmpfd > 0)
        !           168:                        _close(tmpfd);
        !           169:                DeleteFile(buf);
        !           170:                _chmod(newname, _S_IREAD | _S_IWRITE);
        !           171: 
        !           172:                filestatus = MoveFile(newname, buf);
        !           173:        }
        !           174:        /* Now rename the file to the new name
        !           175:         */
        !           176:        _chmod(oldname, _S_IREAD | _S_IWRITE);
        !           177: 
        !           178:        filestatus = MoveFile(oldname, newname);
        !           179:        if (filestatus == 0) {
        !           180:                /*
        !           181:                 * Try to rename the backup back to the original name
        !           182:                 * if the backup got created
        !           183:                 */
        !           184:                if (exists == TRUE) {
        !           185:                        filestatus = MoveFile(buf, newname);
        !           186:                        if (filestatus == 0)
        !           187:                                errno = EACCES;
        !           188:                }
        !           189:                return (-1);
        !           190:        }
        !           191: 
        !           192:        /*
        !           193:         * Delete the backup file if it got created
        !           194:         */
        !           195:        if (exists == TRUE)
        !           196:                filestatus = DeleteFile(buf);
        !           197:        return (0);
        !           198: }
        !           199: 
        !           200: isc_result_t
        !           201: isc_file_getmodtime(const char *file, isc_time_t *time) {
        !           202:        int fh;
        !           203: 
        !           204:        REQUIRE(file != NULL);
        !           205:        REQUIRE(time != NULL);
        !           206: 
        !           207:        if ((fh = open(file, _O_RDONLY | _O_BINARY)) < 0)
        !           208:                return (isc__errno2result(errno));
        !           209: 
        !           210:        if (!GetFileTime((HANDLE) _get_osfhandle(fh),
        !           211:                         NULL,
        !           212:                         NULL,
        !           213:                         &time->absolute))
        !           214:        {
        !           215:                close(fh);
        !           216:                 errno = EINVAL;
        !           217:                 return (isc__errno2result(errno));
        !           218:         }
        !           219:        close(fh);
        !           220:        return (ISC_R_SUCCESS);
        !           221: }
        !           222: 
        !           223: isc_result_t
        !           224: isc_file_settime(const char *file, isc_time_t *time) {
        !           225:        int fh;
        !           226: 
        !           227:        REQUIRE(file != NULL && time != NULL);
        !           228: 
        !           229:        if ((fh = open(file, _O_RDWR | _O_BINARY)) < 0)
        !           230:                return (isc__errno2result(errno));
        !           231: 
        !           232:         /*
        !           233:         * Set the date via the filedate system call and return.  Failing
        !           234:          * this call implies the new file times are not supported by the
        !           235:          * underlying file system.
        !           236:          */
        !           237:        if (!SetFileTime((HANDLE) _get_osfhandle(fh),
        !           238:                         NULL,
        !           239:                         &time->absolute,
        !           240:                         &time->absolute))
        !           241:        {
        !           242:                close(fh);
        !           243:                 errno = EINVAL;
        !           244:                 return (isc__errno2result(errno));
        !           245:         }
        !           246: 
        !           247:        close(fh);
        !           248:         return (ISC_R_SUCCESS);
        !           249: 
        !           250: }
        !           251: 
        !           252: #undef TEMPLATE
        !           253: #define TEMPLATE "XXXXXXXXXX.tmp" /* 14 characters. */
        !           254: 
        !           255: isc_result_t
        !           256: isc_file_mktemplate(const char *path, char *buf, size_t buflen) {
        !           257:        return (isc_file_template(path, TEMPLATE, buf, buflen));
        !           258: }
        !           259: 
        !           260: isc_result_t
        !           261: isc_file_template(const char *path, const char *templet, char *buf,
        !           262:                        size_t buflen) {
        !           263:        char *s;
        !           264: 
        !           265:        REQUIRE(path != NULL);
        !           266:        REQUIRE(templet != NULL);
        !           267:        REQUIRE(buf != NULL);
        !           268: 
        !           269:        s = strrchr(templet, '\\');
        !           270:        if (s != NULL)
        !           271:                templet = s + 1;
        !           272: 
        !           273:        s = strrchr(path, '\\');
        !           274: 
        !           275:        if (s != NULL) {
        !           276:                if ((s - path + 1 + strlen(templet) + 1) > buflen)
        !           277:                        return (ISC_R_NOSPACE);
        !           278: 
        !           279:                strncpy(buf, path, s - path + 1);
        !           280:                buf[s - path + 1] = '\0';
        !           281:                strcat(buf, templet);
        !           282:        } else {
        !           283:                if ((strlen(templet) + 1) > buflen)
        !           284:                        return (ISC_R_NOSPACE);
        !           285: 
        !           286:                strcpy(buf, templet);
        !           287:        }
        !           288: 
        !           289:        return (ISC_R_SUCCESS);
        !           290: }
        !           291: 
        !           292: isc_result_t
        !           293: isc_file_renameunique(const char *file, char *templet) {
        !           294:        int fd = -1;
        !           295:        int res = 0;
        !           296:        isc_result_t result = ISC_R_SUCCESS;
        !           297: 
        !           298:        REQUIRE(file != NULL);
        !           299:        REQUIRE(templet != NULL);
        !           300: 
        !           301:        fd = mkstemp(templet);
        !           302:        if (fd == -1)
        !           303:                result = isc__errno2result(errno);
        !           304:        else
        !           305:                close(fd);
        !           306: 
        !           307:        if (result == ISC_R_SUCCESS) {
        !           308:                res = isc_file_safemovefile(file, templet);
        !           309:                if (res != 0) {
        !           310:                        result = isc__errno2result(errno);
        !           311:                        (void)unlink(templet);
        !           312:                }
        !           313:        }
        !           314:        return (result);
        !           315: }
        !           316: 
        !           317: isc_result_t
        !           318: isc_file_openunique(char *templet, FILE **fp) {
        !           319:        int fd;
        !           320:        FILE *f;
        !           321:        isc_result_t result = ISC_R_SUCCESS;
        !           322: 
        !           323:        REQUIRE(templet != NULL);
        !           324:        REQUIRE(fp != NULL && *fp == NULL);
        !           325: 
        !           326:        /*
        !           327:         * Win32 does not have mkstemp. Using emulation above.
        !           328:         */
        !           329:        fd = mkstemp(templet);
        !           330: 
        !           331:        if (fd == -1)
        !           332:                result = isc__errno2result(errno);
        !           333:        if (result == ISC_R_SUCCESS) {
        !           334:                f = fdopen(fd, "w+");
        !           335:                if (f == NULL) {
        !           336:                        result = isc__errno2result(errno);
        !           337:                        (void)remove(templet);
        !           338:                        (void)close(fd);
        !           339:                } else
        !           340:                        *fp = f;
        !           341:        }
        !           342: 
        !           343:        return (result);
        !           344: }
        !           345: 
        !           346: isc_result_t
        !           347: isc_file_remove(const char *filename) {
        !           348:        int r;
        !           349: 
        !           350:        REQUIRE(filename != NULL);
        !           351: 
        !           352:        r = unlink(filename);
        !           353:        if (r == 0)
        !           354:                return (ISC_R_SUCCESS);
        !           355:        else
        !           356:                return (isc__errno2result(errno));
        !           357: }
        !           358: 
        !           359: isc_result_t
        !           360: isc_file_rename(const char *oldname, const char *newname) {
        !           361:        int r;
        !           362: 
        !           363:        REQUIRE(oldname != NULL);
        !           364:        REQUIRE(newname != NULL);
        !           365: 
        !           366:        r = isc_file_safemovefile(oldname, newname);
        !           367:        if (r == 0)
        !           368:                return (ISC_R_SUCCESS);
        !           369:        else
        !           370:                return (isc__errno2result(errno));
        !           371: }
        !           372: 
        !           373: isc_boolean_t
        !           374: isc_file_exists(const char *pathname) {
        !           375:        struct stat stats;
        !           376: 
        !           377:        REQUIRE(pathname != NULL);
        !           378: 
        !           379:        return (ISC_TF(file_stats(pathname, &stats) == ISC_R_SUCCESS));
        !           380: }
        !           381: 
        !           382: isc_boolean_t
        !           383: isc_file_isabsolute(const char *filename) {
        !           384:        REQUIRE(filename != NULL);
        !           385:        /*
        !           386:         * Look for c:\path\... style, c:/path/... or \\computer\shar\path...
        !           387:         * the UNC style file specs
        !           388:         */
        !           389:        if ((filename[0] == '\\') && (filename[1] == '\\'))
        !           390:                return (ISC_TRUE);
        !           391:        if (isalpha(filename[0]) && filename[1] == ':' && filename[2] == '\\')
        !           392:                return (ISC_TRUE);
        !           393:        if (isalpha(filename[0]) && filename[1] == ':' && filename[2] == '/')
        !           394:                return (ISC_TRUE);
        !           395:        return (ISC_FALSE);
        !           396: }
        !           397: 
        !           398: isc_boolean_t
        !           399: isc_file_iscurrentdir(const char *filename) {
        !           400:        REQUIRE(filename != NULL);
        !           401:        return (ISC_TF(filename[0] == '.' && filename[1] == '\0'));
        !           402: }
        !           403: 
        !           404: isc_boolean_t
        !           405: isc_file_ischdiridempotent(const char *filename) {
        !           406:        REQUIRE(filename != NULL);
        !           407: 
        !           408:        if (isc_file_isabsolute(filename))
        !           409:                return (ISC_TRUE);
        !           410:        if (filename[0] == '\\')
        !           411:                return (ISC_TRUE);
        !           412:        if (filename[0] == '/')
        !           413:                return (ISC_TRUE);
        !           414:        if (isc_file_iscurrentdir(filename))
        !           415:                return (ISC_TRUE);
        !           416:        return (ISC_FALSE);
        !           417: }
        !           418: 
        !           419: const char *
        !           420: isc_file_basename(const char *filename) {
        !           421:        char *s;
        !           422: 
        !           423:        REQUIRE(filename != NULL);
        !           424: 
        !           425:        s = strrchr(filename, '\\');
        !           426:        if (s == NULL)
        !           427:                return (filename);
        !           428:        return (s + 1);
        !           429: }
        !           430: 
        !           431: isc_result_t
        !           432: isc_file_progname(const char *filename, char *progname, size_t namelen) {
        !           433:        const char *s;
        !           434:        char *p;
        !           435:        size_t len;
        !           436: 
        !           437:        REQUIRE(filename != NULL);
        !           438:        REQUIRE(progname != NULL);
        !           439: 
        !           440:        /*
        !           441:         * Strip the path from the name
        !           442:         */
        !           443:        s = isc_file_basename(filename);
        !           444:        if (s == NULL) {
        !           445:                return (ISC_R_NOSPACE);
        !           446:        }
        !           447: 
        !           448:        /*
        !           449:         * Strip any and all suffixes
        !           450:         */
        !           451:        p = strchr(s, '.');
        !           452:        if (p == NULL) {
        !           453:                if (namelen <= strlen(s))
        !           454:                        return (ISC_R_NOSPACE);
        !           455: 
        !           456:                strcpy(progname, s);
        !           457:                return (ISC_R_SUCCESS);
        !           458:        }
        !           459: 
        !           460:        /* 
        !           461:         * Copy the result to the buffer
        !           462:         */
        !           463:        len = p - s;
        !           464:        if (len >= namelen)
        !           465:                return (ISC_R_NOSPACE);
        !           466: 
        !           467:        strncpy(progname, s, len);
        !           468:        progname[len] = '\0';
        !           469:        return (ISC_R_SUCCESS);
        !           470: }
        !           471: 
        !           472: isc_result_t
        !           473: isc_file_absolutepath(const char *filename, char *path, size_t pathlen) {
        !           474:        char *ptrname;
        !           475:        DWORD retval;
        !           476: 
        !           477:        REQUIRE(filename != NULL);
        !           478:        REQUIRE(path != NULL);
        !           479: 
        !           480:        retval = GetFullPathName(filename, pathlen, path, &ptrname);
        !           481: 
        !           482:        /* Something went wrong in getting the path */
        !           483:        if (retval == 0)
        !           484:                return (ISC_R_NOTFOUND);
        !           485:        /* Caller needs to provide a larger buffer to contain the string */
        !           486:        if (retval >= pathlen)
        !           487:                return (ISC_R_NOSPACE);
        !           488:        return (ISC_R_SUCCESS);
        !           489: }
        !           490: 
        !           491: isc_result_t
        !           492: isc_file_truncate(const char *filename, isc_offset_t size) {
        !           493:        int fh;
        !           494: 
        !           495:        REQUIRE(filename != NULL && size >= 0);
        !           496: 
        !           497:        if ((fh = open(filename, _O_RDWR | _O_BINARY)) < 0)
        !           498:                return (isc__errno2result(errno));
        !           499: 
        !           500:        if(_chsize(fh, size) != 0) {
        !           501:                close(fh);
        !           502:                return (isc__errno2result(errno));
        !           503:        }
        !           504:        close(fh);
        !           505: 
        !           506:        return (ISC_R_SUCCESS);
        !           507: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>