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