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>