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>