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

1.1     ! misho       1: /*
        !             2:  * Copyright (C) 2004, 2005, 2007, 2009  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: /*
        !            19:  * Portions Copyright (c) 1987, 1993
        !            20:  *      The Regents of the University of California.  All rights reserved.
        !            21:  *
        !            22:  * Redistribution and use in source and binary forms, with or without
        !            23:  * modification, are permitted provided that the following conditions
        !            24:  * are met:
        !            25:  * 1. Redistributions of source code must retain the above copyright
        !            26:  *    notice, this list of conditions and the following disclaimer.
        !            27:  * 2. Redistributions in binary form must reproduce the above copyright
        !            28:  *    notice, this list of conditions and the following disclaimer in the
        !            29:  *    documentation and/or other materials provided with the distribution.
        !            30:  * 3. All advertising materials mentioning features or use of this software
        !            31:  *    must display the following acknowledgement:
        !            32:  *      This product includes software developed by the University of
        !            33:  *      California, Berkeley and its contributors.
        !            34:  * 4. Neither the name of the University nor the names of its contributors
        !            35:  *    may be used to endorse or promote products derived from this software
        !            36:  *    without specific prior written permission.
        !            37:  *
        !            38:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            39:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            40:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            41:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            42:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            43:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            44:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            45:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            46:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            47:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            48:  * SUCH DAMAGE.
        !            49:  */
        !            50: 
        !            51: /* $Id: file.c,v 1.51.332.2 2009/02/16 23:47:15 tbox Exp $ */
        !            52: 
        !            53: /*! \file */
        !            54: 
        !            55: #include <config.h>
        !            56: 
        !            57: #include <errno.h>
        !            58: #include <fcntl.h>
        !            59: #include <limits.h>
        !            60: #include <stdlib.h>
        !            61: #include <time.h>              /* Required for utimes on some platforms. */
        !            62: #include <unistd.h>            /* Required for mkstemp on NetBSD. */
        !            63: 
        !            64: 
        !            65: #include <sys/stat.h>
        !            66: #include <sys/time.h>
        !            67: 
        !            68: #include <isc/dir.h>
        !            69: #include <isc/file.h>
        !            70: #include <isc/log.h>
        !            71: #include <isc/random.h>
        !            72: #include <isc/string.h>
        !            73: #include <isc/time.h>
        !            74: #include <isc/util.h>
        !            75: 
        !            76: #include "errno2result.h"
        !            77: 
        !            78: /*
        !            79:  * XXXDCL As the API for accessing file statistics undoubtedly gets expanded,
        !            80:  * it might be good to provide a mechanism that allows for the results
        !            81:  * of a previous stat() to be used again without having to do another stat,
        !            82:  * such as perl's mechanism of using "_" in place of a file name to indicate
        !            83:  * that the results of the last stat should be used.  But then you get into
        !            84:  * annoying MP issues.   BTW, Win32 has stat().
        !            85:  */
        !            86: static isc_result_t
        !            87: file_stats(const char *file, struct stat *stats) {
        !            88:        isc_result_t result = ISC_R_SUCCESS;
        !            89: 
        !            90:        REQUIRE(file != NULL);
        !            91:        REQUIRE(stats != NULL);
        !            92: 
        !            93:        if (stat(file, stats) != 0)
        !            94:                result = isc__errno2result(errno);
        !            95: 
        !            96:        return (result);
        !            97: }
        !            98: 
        !            99: isc_result_t
        !           100: isc_file_getmodtime(const char *file, isc_time_t *time) {
        !           101:        isc_result_t result;
        !           102:        struct stat stats;
        !           103: 
        !           104:        REQUIRE(file != NULL);
        !           105:        REQUIRE(time != NULL);
        !           106: 
        !           107:        result = file_stats(file, &stats);
        !           108: 
        !           109:        if (result == ISC_R_SUCCESS)
        !           110:                /*
        !           111:                 * XXXDCL some operating systems provide nanoseconds, too,
        !           112:                 * such as BSD/OS via st_mtimespec.
        !           113:                 */
        !           114:                isc_time_set(time, stats.st_mtime, 0);
        !           115: 
        !           116:        return (result);
        !           117: }
        !           118: 
        !           119: isc_result_t
        !           120: isc_file_settime(const char *file, isc_time_t *time) {
        !           121:        struct timeval times[2];
        !           122: 
        !           123:        REQUIRE(file != NULL && time != NULL);
        !           124: 
        !           125:        /*
        !           126:         * tv_sec is at least a 32 bit quantity on all platforms we're
        !           127:         * dealing with, but it is signed on most (all?) of them,
        !           128:         * so we need to make sure the high bit isn't set.  This unfortunately
        !           129:         * loses when either:
        !           130:         *   * tv_sec becomes a signed 64 bit integer but long is 32 bits
        !           131:         *      and isc_time_seconds > LONG_MAX, or
        !           132:         *   * isc_time_seconds is changed to be > 32 bits but long is 32 bits
        !           133:         *      and isc_time_seconds has at least 33 significant bits.
        !           134:         */
        !           135:        times[0].tv_sec = times[1].tv_sec = (long)isc_time_seconds(time);
        !           136: 
        !           137:        /*
        !           138:         * Here is the real check for the high bit being set.
        !           139:         */
        !           140:        if ((times[0].tv_sec &
        !           141:             (1ULL << (sizeof(times[0].tv_sec) * CHAR_BIT - 1))) != 0)
        !           142:                return (ISC_R_RANGE);
        !           143: 
        !           144:        /*
        !           145:         * isc_time_nanoseconds guarantees a value that divided by 1000 will
        !           146:         * fit into the minimum possible size tv_usec field.  Unfortunately,
        !           147:         * we don't know what that type is so can't cast directly ... but
        !           148:         * we can at least cast to signed so the IRIX compiler shuts up.
        !           149:         */
        !           150:        times[0].tv_usec = times[1].tv_usec =
        !           151:                (isc_int32_t)(isc_time_nanoseconds(time) / 1000);
        !           152: 
        !           153:        if (utimes(file, times) < 0)
        !           154:                return (isc__errno2result(errno));
        !           155: 
        !           156:        return (ISC_R_SUCCESS);
        !           157: }
        !           158: 
        !           159: #undef TEMPLATE
        !           160: #define TEMPLATE "tmp-XXXXXXXXXX" /*%< 14 characters. */
        !           161: 
        !           162: isc_result_t
        !           163: isc_file_mktemplate(const char *path, char *buf, size_t buflen) {
        !           164:        return (isc_file_template(path, TEMPLATE, buf, buflen));
        !           165: }
        !           166: 
        !           167: isc_result_t
        !           168: isc_file_template(const char *path, const char *templet, char *buf,
        !           169:                        size_t buflen) {
        !           170:        char *s;
        !           171: 
        !           172:        REQUIRE(path != NULL);
        !           173:        REQUIRE(templet != NULL);
        !           174:        REQUIRE(buf != NULL);
        !           175: 
        !           176:        s = strrchr(templet, '/');
        !           177:        if (s != NULL)
        !           178:                templet = s + 1;
        !           179: 
        !           180:        s = strrchr(path, '/');
        !           181: 
        !           182:        if (s != NULL) {
        !           183:                if ((s - path + 1 + strlen(templet) + 1) > buflen)
        !           184:                        return (ISC_R_NOSPACE);
        !           185: 
        !           186:                strncpy(buf, path, s - path + 1);
        !           187:                buf[s - path + 1] = '\0';
        !           188:                strcat(buf, templet);
        !           189:        } else {
        !           190:                if ((strlen(templet) + 1) > buflen)
        !           191:                        return (ISC_R_NOSPACE);
        !           192: 
        !           193:                strcpy(buf, templet);
        !           194:        }
        !           195: 
        !           196:        return (ISC_R_SUCCESS);
        !           197: }
        !           198: 
        !           199: static char alphnum[] =
        !           200:        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
        !           201: 
        !           202: isc_result_t
        !           203: isc_file_renameunique(const char *file, char *templet) {
        !           204:        char *x;
        !           205:        char *cp;
        !           206:        isc_uint32_t which;
        !           207: 
        !           208:        REQUIRE(file != NULL);
        !           209:        REQUIRE(templet != NULL);
        !           210: 
        !           211:        cp = templet;
        !           212:        while (*cp != '\0')
        !           213:                cp++;
        !           214:        if (cp == templet)
        !           215:                return (ISC_R_FAILURE);
        !           216: 
        !           217:        x = cp--;
        !           218:        while (cp >= templet && *cp == 'X') {
        !           219:                isc_random_get(&which);
        !           220:                *cp = alphnum[which % (sizeof(alphnum) - 1)];
        !           221:                x = cp--;
        !           222:        }
        !           223:        while (link(file, templet) == -1) {
        !           224:                if (errno != EEXIST)
        !           225:                        return (isc__errno2result(errno));
        !           226:                for (cp = x;;) {
        !           227:                        char *t;
        !           228:                        if (*cp == '\0')
        !           229:                                return (ISC_R_FAILURE);
        !           230:                        t = strchr(alphnum, *cp);
        !           231:                        if (t == NULL || *++t == '\0')
        !           232:                                *cp++ = alphnum[0];
        !           233:                        else {
        !           234:                                *cp = *t;
        !           235:                                break;
        !           236:                        }
        !           237:                }
        !           238:        }
        !           239:        if (unlink(file) < 0)
        !           240:                if (errno != ENOENT)
        !           241:                        return (isc__errno2result(errno));
        !           242:        return (ISC_R_SUCCESS);
        !           243: }
        !           244: 
        !           245: 
        !           246: isc_result_t
        !           247: isc_file_openunique(char *templet, FILE **fp) {
        !           248:        int fd;
        !           249:        FILE *f;
        !           250:        isc_result_t result = ISC_R_SUCCESS;
        !           251:        char *x;
        !           252:        char *cp;
        !           253:        isc_uint32_t which;
        !           254:        int mode;
        !           255: 
        !           256:        REQUIRE(templet != NULL);
        !           257:        REQUIRE(fp != NULL && *fp == NULL);
        !           258: 
        !           259:        cp = templet;
        !           260:        while (*cp != '\0')
        !           261:                cp++;
        !           262:        if (cp == templet)
        !           263:                return (ISC_R_FAILURE);
        !           264: 
        !           265:        x = cp--;
        !           266:        while (cp >= templet && *cp == 'X') {
        !           267:                isc_random_get(&which);
        !           268:                *cp = alphnum[which % (sizeof(alphnum) - 1)];
        !           269:                x = cp--;
        !           270:        }
        !           271: 
        !           272:        mode = S_IWUSR|S_IRUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
        !           273: 
        !           274:        while ((fd = open(templet, O_RDWR|O_CREAT|O_EXCL, mode)) == -1) {
        !           275:                if (errno != EEXIST)
        !           276:                        return (isc__errno2result(errno));
        !           277:                for (cp = x;;) {
        !           278:                        char *t;
        !           279:                        if (*cp == '\0')
        !           280:                                return (ISC_R_FAILURE);
        !           281:                        t = strchr(alphnum, *cp);
        !           282:                        if (t == NULL || *++t == '\0')
        !           283:                                *cp++ = alphnum[0];
        !           284:                        else {
        !           285:                                *cp = *t;
        !           286:                                break;
        !           287:                        }
        !           288:                }
        !           289:        }
        !           290:        f = fdopen(fd, "w+");
        !           291:        if (f == NULL) {
        !           292:                result = isc__errno2result(errno);
        !           293:                if (remove(templet) < 0) {
        !           294:                        isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
        !           295:                                      ISC_LOGMODULE_FILE, ISC_LOG_ERROR,
        !           296:                                      "remove '%s': failed", templet);
        !           297:                }
        !           298:                (void)close(fd);
        !           299:        } else
        !           300:                *fp = f;
        !           301: 
        !           302:        return (result);
        !           303: }
        !           304: 
        !           305: isc_result_t
        !           306: isc_file_remove(const char *filename) {
        !           307:        int r;
        !           308: 
        !           309:        REQUIRE(filename != NULL);
        !           310: 
        !           311:        r = unlink(filename);
        !           312:        if (r == 0)
        !           313:                return (ISC_R_SUCCESS);
        !           314:        else
        !           315:                return (isc__errno2result(errno));
        !           316: }
        !           317: 
        !           318: isc_result_t
        !           319: isc_file_rename(const char *oldname, const char *newname) {
        !           320:        int r;
        !           321: 
        !           322:        REQUIRE(oldname != NULL);
        !           323:        REQUIRE(newname != NULL);
        !           324: 
        !           325:        r = rename(oldname, newname);
        !           326:        if (r == 0)
        !           327:                return (ISC_R_SUCCESS);
        !           328:        else
        !           329:                return (isc__errno2result(errno));
        !           330: }
        !           331: 
        !           332: isc_boolean_t
        !           333: isc_file_exists(const char *pathname) {
        !           334:        struct stat stats;
        !           335: 
        !           336:        REQUIRE(pathname != NULL);
        !           337: 
        !           338:        return (ISC_TF(file_stats(pathname, &stats) == ISC_R_SUCCESS));
        !           339: }
        !           340: 
        !           341: isc_boolean_t
        !           342: isc_file_isabsolute(const char *filename) {
        !           343:        REQUIRE(filename != NULL);
        !           344:        return (ISC_TF(filename[0] == '/'));
        !           345: }
        !           346: 
        !           347: isc_boolean_t
        !           348: isc_file_iscurrentdir(const char *filename) {
        !           349:        REQUIRE(filename != NULL);
        !           350:        return (ISC_TF(filename[0] == '.' && filename[1] == '\0'));
        !           351: }
        !           352: 
        !           353: isc_boolean_t
        !           354: isc_file_ischdiridempotent(const char *filename) {
        !           355:        REQUIRE(filename != NULL);
        !           356:        if (isc_file_isabsolute(filename))
        !           357:                return (ISC_TRUE);
        !           358:        if (isc_file_iscurrentdir(filename))
        !           359:                return (ISC_TRUE);
        !           360:        return (ISC_FALSE);
        !           361: }
        !           362: 
        !           363: const char *
        !           364: isc_file_basename(const char *filename) {
        !           365:        char *s;
        !           366: 
        !           367:        REQUIRE(filename != NULL);
        !           368: 
        !           369:        s = strrchr(filename, '/');
        !           370:        if (s == NULL)
        !           371:                return (filename);
        !           372: 
        !           373:        return (s + 1);
        !           374: }
        !           375: 
        !           376: isc_result_t
        !           377: isc_file_progname(const char *filename, char *buf, size_t buflen) {
        !           378:        const char *base;
        !           379:        size_t len;
        !           380: 
        !           381:        REQUIRE(filename != NULL);
        !           382:        REQUIRE(buf != NULL);
        !           383: 
        !           384:        base = isc_file_basename(filename);
        !           385:        len = strlen(base) + 1;
        !           386: 
        !           387:        if (len > buflen)
        !           388:                return (ISC_R_NOSPACE);
        !           389:        memcpy(buf, base, len);
        !           390: 
        !           391:        return (ISC_R_SUCCESS);
        !           392: }
        !           393: 
        !           394: /*
        !           395:  * Put the absolute name of the current directory into 'dirname', which is
        !           396:  * a buffer of at least 'length' characters.  End the string with the
        !           397:  * appropriate path separator, such that the final product could be
        !           398:  * concatenated with a relative pathname to make a valid pathname string.
        !           399:  */
        !           400: static isc_result_t
        !           401: dir_current(char *dirname, size_t length) {
        !           402:        char *cwd;
        !           403:        isc_result_t result = ISC_R_SUCCESS;
        !           404: 
        !           405:        REQUIRE(dirname != NULL);
        !           406:        REQUIRE(length > 0U);
        !           407: 
        !           408:        cwd = getcwd(dirname, length);
        !           409: 
        !           410:        if (cwd == NULL) {
        !           411:                if (errno == ERANGE)
        !           412:                        result = ISC_R_NOSPACE;
        !           413:                else
        !           414:                        result = isc__errno2result(errno);
        !           415:        } else {
        !           416:                if (strlen(dirname) + 1 == length)
        !           417:                        result = ISC_R_NOSPACE;
        !           418:                else if (dirname[1] != '\0')
        !           419:                        strcat(dirname, "/");
        !           420:        }
        !           421: 
        !           422:        return (result);
        !           423: }
        !           424: 
        !           425: isc_result_t
        !           426: isc_file_absolutepath(const char *filename, char *path, size_t pathlen) {
        !           427:        isc_result_t result;
        !           428:        result = dir_current(path, pathlen);
        !           429:        if (result != ISC_R_SUCCESS)
        !           430:                return (result);
        !           431:        if (strlen(path) + strlen(filename) + 1 > pathlen)
        !           432:                return (ISC_R_NOSPACE);
        !           433:        strcat(path, filename);
        !           434:        return (ISC_R_SUCCESS);
        !           435: }
        !           436: 
        !           437: isc_result_t
        !           438: isc_file_truncate(const char *filename, isc_offset_t size) {
        !           439:        isc_result_t result = ISC_R_SUCCESS;
        !           440: 
        !           441:        if (truncate(filename, size) < 0)
        !           442:                result = isc__errno2result(errno);
        !           443:        return (result);
        !           444: }

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