Annotation of embedaddon/ntp/lib/isc/win32/file.c, revision 1.1.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>