file.c revision bbb3705e4cbdacf7cf6da7e448d79d97fdab2411
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson/*
3759f10fc543747668b1ca4b4671f35b0dea8445Francis Dupont * Copyright (C) 2004, 2007, 2009, 2011, 2012 Internet Systems Consortium, Inc. ("ISC")
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * Copyright (C) 2000-2002 Internet Software Consortium.
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence *
ec5347e2c775f027573ce5648b910361aa926c01Automatic Updater * Permission to use, copy, modify, and/or distribute this software for any
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson * purpose with or without fee is hereby granted, provided that the above
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson * copyright notice and this permission notice appear in all copies.
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence *
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * PERFORMANCE OF THIS SOFTWARE.
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson */
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson
70e5a7403f0e0a3bd292b8287c5fed5772c15270Automatic Updater/* $Id$ */
9c3531d72aeaad6c5f01efe6a1c82023e1379e4dDavid Lawrence
ab023a65562e62b85a824509d829b6fad87e00b1Rob Austein#include <config.h>
ab023a65562e62b85a824509d829b6fad87e00b1Rob Austein
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson#undef rename
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson#include <errno.h>
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson#include <limits.h>
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence#include <stdlib.h>
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson#include <io.h>
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson#include <process.h>
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson#include <sys/stat.h>
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson#include <fcntl.h>
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson#include <sys/utime.h>
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson
3759f10fc543747668b1ca4b4671f35b0dea8445Francis Dupont#include <isc/file.h>
3759f10fc543747668b1ca4b4671f35b0dea8445Francis Dupont#include <isc/mem.h>
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson#include <isc/result.h>
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson#include <isc/time.h>
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson#include <isc/util.h>
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson#include <isc/stat.h>
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson#include <isc/string.h>
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson#include "errno2result.h"
431a83fb29482c5170b3e4026e59bb14849a6707Tinderbox User
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson/*
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson * Emulate UNIX mkstemp, which returns an open FD to the new file
92ef1a9b9dbd48ecb507b42ac62c15afefdaf838David Lawrence *
92ef1a9b9dbd48ecb507b42ac62c15afefdaf838David Lawrence */
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafssonstatic int
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafssongettemp(char *path, isc_boolean_t binary, int *doopen) {
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson char *start, *trv;
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson struct stat sbuf;
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson int pid;
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson int flags = O_CREAT|O_EXCL|O_RDWR;
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson if (binary)
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson flags |= _O_BINARY;
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson trv = strrchr(path, 'X');
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson trv++;
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson pid = getpid();
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson /* extra X's get set to 0's */
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson while (*--trv == 'X') {
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence *trv = (pid % 10) + '0';
431a83fb29482c5170b3e4026e59bb14849a6707Tinderbox User pid /= 10;
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson }
431a83fb29482c5170b3e4026e59bb14849a6707Tinderbox User /*
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson * check the target directory; if you have six X's and it
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson * doesn't exist this runs for a *very* long time.
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence */
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson for (start = trv + 1;; --trv) {
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrence if (trv <= path)
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson break;
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson if (*trv == '\\') {
79c08618e9f27da052ad6bbc0b232f23ff2e568eAndreas Gustafsson *trv = '\0';
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence if (stat(path, &sbuf))
4b87939256ede703385e9cab92d3c58d03c31098Mark Andrews return (0);
4b87939256ede703385e9cab92d3c58d03c31098Mark Andrews if (!S_ISDIR(sbuf.st_mode)) {
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson errno = ENOTDIR;
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson return (0);
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson }
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence *trv = '\\';
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson break;
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson }
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson }
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson for (;;) {
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson if (doopen) {
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson if ((*doopen =
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrence open(path, flags, _S_IREAD | _S_IWRITE)) >= 0)
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrence return (1);
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrence if (errno != EEXIST)
79c08618e9f27da052ad6bbc0b232f23ff2e568eAndreas Gustafsson return (0);
79c08618e9f27da052ad6bbc0b232f23ff2e568eAndreas Gustafsson } else if (stat(path, &sbuf))
4b87939256ede703385e9cab92d3c58d03c31098Mark Andrews return (errno == ENOENT ? 1 : 0);
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence
9cd6d409b78a6f833b681c13a68fbdc7c024fe66David Lawrence /* tricky little algorithm for backward compatibility */
9cd6d409b78a6f833b681c13a68fbdc7c024fe66David Lawrence for (trv = start;;) {
9cd6d409b78a6f833b681c13a68fbdc7c024fe66David Lawrence if (!*trv)
9cd6d409b78a6f833b681c13a68fbdc7c024fe66David Lawrence return (0);
9cd6d409b78a6f833b681c13a68fbdc7c024fe66David Lawrence if (*trv == 'z')
4b87939256ede703385e9cab92d3c58d03c31098Mark Andrews *trv++ = 'a';
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson else {
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson if (isdigit(*trv))
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson *trv = 'a';
79c08618e9f27da052ad6bbc0b232f23ff2e568eAndreas Gustafsson else
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson ++*trv;
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson break;
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson }
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson }
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson }
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson /*NOTREACHED*/
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson}
79c08618e9f27da052ad6bbc0b232f23ff2e568eAndreas Gustafsson
79c08618e9f27da052ad6bbc0b232f23ff2e568eAndreas Gustafssonstatic int
4b87939256ede703385e9cab92d3c58d03c31098Mark Andrewsmkstemp(char *path, isc_boolean_t binary) {
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence int fd;
9cd6d409b78a6f833b681c13a68fbdc7c024fe66David Lawrence
9cd6d409b78a6f833b681c13a68fbdc7c024fe66David Lawrence return (gettemp(path, binary, &fd) ? fd : -1);
9cd6d409b78a6f833b681c13a68fbdc7c024fe66David Lawrence}
9cd6d409b78a6f833b681c13a68fbdc7c024fe66David Lawrence
9cd6d409b78a6f833b681c13a68fbdc7c024fe66David Lawrence/*
4b87939256ede703385e9cab92d3c58d03c31098Mark Andrews * XXXDCL As the API for accessing file statistics undoubtedly gets expanded,
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson * it might be good to provide a mechanism that allows for the results
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson * of a previous stat() to be used again without having to do another stat,
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson * such as perl's mechanism of using "_" in place of a file name to indicate
79c08618e9f27da052ad6bbc0b232f23ff2e568eAndreas Gustafsson * that the results of the last stat should be used. But then you get into
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson * annoying MP issues. BTW, Win32 has stat().
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson */
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafssonstatic isc_result_t
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafssonfile_stats(const char *file, struct stat *stats) {
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson isc_result_t result = ISC_R_SUCCESS;
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson REQUIRE(file != NULL);
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson REQUIRE(stats != NULL);
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson if (stat(file, stats) != 0)
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson result = isc__errno2result(errno);
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson return (result);
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson}
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafssonstatic isc_result_t
91cd0f93ad34d23e8b09dca337120f64fbe8f0a1Andreas Gustafssonfd_stats(int fd, struct stat *stats) {
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson isc_result_t result = ISC_R_SUCCESS;
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson REQUIRE(stats != NULL);
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson if (fstat(fd, stats) != 0)
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson result = isc__errno2result(errno);
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson
461a00bbdee50a46ba7fcfb3f9f2847d3bda5ad3Andreas Gustafsson return (result);
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson}
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafssonisc_result_t
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafssonisc_file_getsizefd(int fd, off_t *size) {
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson isc_result_t result;
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson struct stat stats;
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson REQUIRE(size != NULL);
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson result = fd_stats(fd, &stats);
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson if (result == ISC_R_SUCCESS)
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence *size = stats.st_size;
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson return (result);
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson}
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafssonisc_result_t
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafssonisc_file_mode(const char *file, mode_t *modep) {
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson isc_result_t result;
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence struct stat stats;
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson REQUIRE(modep != NULL);
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence result = file_stats(file, &stats);
2305225a1c70bf80dd544f801f3259d35d4220ceBrian Wellington if (result == ISC_R_SUCCESS)
e851ea826066ac5a5b01c2c23218faa0273a12e8Evan Hunt *modep = (stats.st_mode & 07777);
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson return (result);
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson}
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson/*
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson * isc_file_safemovefile is needed to be defined here to ensure that
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence * any file with the new name is renamed to a backup name and then the
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson * rename is done. If all goes well then the backup can be deleted,
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson * otherwise it gets renamed back.
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence */
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafssonint
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafssonisc_file_safemovefile(const char *oldname, const char *newname) {
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson BOOL filestatus;
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson char buf[512];
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson struct stat sbuf;
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson BOOL exists = FALSE;
461a00bbdee50a46ba7fcfb3f9f2847d3bda5ad3Andreas Gustafsson int tmpfd;
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson /*
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson * Make sure we have something to do
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson */
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson if (stat(oldname, &sbuf) != 0) {
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson errno = ENOENT;
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson return (-1);
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson }
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson /*
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson * Rename to a backup the new file if it still exists
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson */
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson if (stat(newname, &sbuf) == 0) {
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson exists = TRUE;
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson strcpy(buf, newname);
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson strcat(buf, ".XXXXX");
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence tmpfd = mkstemp(buf, ISC_TRUE);
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson if (tmpfd > 0)
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson _close(tmpfd);
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson (void)DeleteFile(buf);
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson _chmod(newname, _S_IREAD | _S_IWRITE);
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson filestatus = MoveFile(newname, buf);
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson }
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson /* Now rename the file to the new name
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson */
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson _chmod(oldname, _S_IREAD | _S_IWRITE);
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson
91c49d591c79159a965adb9d78c03cc2f334991eAndreas Gustafsson filestatus = MoveFile(oldname, newname);
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson if (filestatus == 0) {
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson /*
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson * Try to rename the backup back to the original name
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson * if the backup got created
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrence */
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrence if (exists == TRUE) {
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrence filestatus = MoveFile(buf, newname);
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson if (filestatus == 0)
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson errno = EACCES;
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson }
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson return (-1);
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson }
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson /*
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson * Delete the backup file if it got created
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson */
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson if (exists == TRUE)
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson (void)DeleteFile(buf);
461a00bbdee50a46ba7fcfb3f9f2847d3bda5ad3Andreas Gustafsson return (0);
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence}
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson
c549b3a4d5fedba2ae960df667864e824acb1ef9Mark Andrewsisc_result_t
461a00bbdee50a46ba7fcfb3f9f2847d3bda5ad3Andreas Gustafssonisc_file_getmodtime(const char *file, isc_time_t *time) {
757a38d502c1d921c2318c00f6cb72251d8f15edMark Andrews int fh;
757a38d502c1d921c2318c00f6cb72251d8f15edMark Andrews
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence REQUIRE(file != NULL);
846f974d5737710588eb676b64ba138da27c45ddMark Andrews REQUIRE(time != NULL);
846f974d5737710588eb676b64ba138da27c45ddMark Andrews
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson if ((fh = open(file, _O_RDONLY | _O_BINARY)) < 0)
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson return (isc__errno2result(errno));
846f974d5737710588eb676b64ba138da27c45ddMark Andrews
846f974d5737710588eb676b64ba138da27c45ddMark Andrews if (!GetFileTime((HANDLE) _get_osfhandle(fh),
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence NULL,
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson NULL,
5a4854e226ce5eca99bcfb5557b36ea210bb25bcMark Andrews &time->absolute))
846f974d5737710588eb676b64ba138da27c45ddMark Andrews {
846f974d5737710588eb676b64ba138da27c45ddMark Andrews close(fh);
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson errno = EINVAL;
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson return (isc__errno2result(errno));
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson }
5456bddd393aafd9fa5ac4cc905d3ac1b9854635Mukund Sivaraman close(fh);
5456bddd393aafd9fa5ac4cc905d3ac1b9854635Mukund Sivaraman return (ISC_R_SUCCESS);
9cd6d409b78a6f833b681c13a68fbdc7c024fe66David Lawrence}
9cd6d409b78a6f833b681c13a68fbdc7c024fe66David Lawrence
9cd6d409b78a6f833b681c13a68fbdc7c024fe66David Lawrenceisc_result_t
461a00bbdee50a46ba7fcfb3f9f2847d3bda5ad3Andreas Gustafssonisc_file_settime(const char *file, isc_time_t *time) {
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson int fh;
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson REQUIRE(file != NULL && time != NULL);
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence if ((fh = open(file, _O_RDWR | _O_BINARY)) < 0)
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson return (isc__errno2result(errno));
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson /*
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson * Set the date via the filedate system call and return. Failing
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson * this call implies the new file times are not supported by the
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson * underlying file system.
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson */
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson if (!SetFileTime((HANDLE) _get_osfhandle(fh),
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson NULL,
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence &time->absolute,
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson &time->absolute))
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson {
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson close(fh);
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson errno = EINVAL;
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson return (isc__errno2result(errno));
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson }
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson close(fh);
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson return (ISC_R_SUCCESS);
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson}
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrence#undef TEMPLATE
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrence#define TEMPLATE "XXXXXXXXXX.tmp" /* 14 characters. */
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrence
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrenceisc_result_t
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafssonisc_file_mktemplate(const char *path, char *buf, size_t buflen) {
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson return (isc_file_template(path, TEMPLATE, buf, buflen));
21ba6c18e4ccc73933af5cf28701a5cc3b7963ecMark Andrews}
21ba6c18e4ccc73933af5cf28701a5cc3b7963ecMark Andrews
21ba6c18e4ccc73933af5cf28701a5cc3b7963ecMark Andrewsisc_result_t
21ba6c18e4ccc73933af5cf28701a5cc3b7963ecMark Andrewsisc_file_template(const char *path, const char *templet, char *buf,
size_t buflen) {
char *s;
REQUIRE(path != NULL);
REQUIRE(templet != NULL);
REQUIRE(buf != NULL);
s = strrchr(templet, '\\');
if (s != NULL)
templet = s + 1;
s = strrchr(path, '\\');
if (s != NULL) {
if ((s - path + 1 + strlen(templet) + 1) > buflen)
return (ISC_R_NOSPACE);
strncpy(buf, path, s - path + 1);
buf[s - path + 1] = '\0';
strcat(buf, templet);
} else {
if ((strlen(templet) + 1) > buflen)
return (ISC_R_NOSPACE);
strcpy(buf, templet);
}
return (ISC_R_SUCCESS);
}
isc_result_t
isc_file_renameunique(const char *file, char *templet) {
int fd;
int res = 0;
isc_result_t result = ISC_R_SUCCESS;
REQUIRE(file != NULL);
REQUIRE(templet != NULL);
fd = mkstemp(templet, ISC_TRUE);
if (fd == -1)
result = isc__errno2result(errno);
else
close(fd);
if (result == ISC_R_SUCCESS) {
res = isc_file_safemovefile(file, templet);
if (res != 0) {
result = isc__errno2result(errno);
(void)unlink(templet);
}
}
return (result);
}
static isc_result_t
openuniquemode(char *templet, int mode, isc_boolean_t binary, FILE **fp) {
int fd;
FILE *f;
isc_result_t result = ISC_R_SUCCESS;
REQUIRE(templet != NULL);
REQUIRE(fp != NULL && *fp == NULL);
/*
* Win32 does not have mkstemp. Using emulation above.
*/
fd = mkstemp(templet, binary);
if (fd == -1)
result = isc__errno2result(errno);
if (result == ISC_R_SUCCESS) {
#if 1
UNUSED(mode);
#else
(void)fchmod(fd, mode);
#endif
f = fdopen(fd, binary ? "wb+" : "w+");
if (f == NULL) {
result = isc__errno2result(errno);
(void)remove(templet);
(void)close(fd);
} else
*fp = f;
}
return (result);
}
isc_result_t
isc_file_openuniqueprivate(char *templet, FILE **fp) {
int mode = _S_IREAD | _S_IWRITE;
return (openuniquemode(templet, mode, ISC_FALSE, fp));
}
isc_result_t
isc_file_openunique(char *templet, FILE **fp) {
int mode = _S_IREAD | _S_IWRITE;
return (openuniquemode(templet, mode, ISC_FALSE, fp));
}
isc_result_t
isc_file_openuniquemode(char *templet, int mode, FILE **fp) {
return (openuniquemode(templet, mode, ISC_FALSE, fp));
}
isc_result_t
isc_file_bopenuniqueprivate(char *templet, FILE **fp) {
int mode = _S_IREAD | _S_IWRITE;
return (openuniquemode(templet, mode, ISC_TRUE, fp));
}
isc_result_t
isc_file_bopenunique(char *templet, FILE **fp) {
int mode = _S_IREAD | _S_IWRITE;
return (openuniquemode(templet, mode, ISC_TRUE, fp));
}
isc_result_t
isc_file_bopenuniquemode(char *templet, int mode, FILE **fp) {
return (openuniquemode(templet, mode, ISC_TRUE, fp));
}
isc_result_t
isc_file_remove(const char *filename) {
int r;
REQUIRE(filename != NULL);
r = unlink(filename);
if (r == 0)
return (ISC_R_SUCCESS);
else
return (isc__errno2result(errno));
}
isc_result_t
isc_file_rename(const char *oldname, const char *newname) {
int r;
REQUIRE(oldname != NULL);
REQUIRE(newname != NULL);
r = isc_file_safemovefile(oldname, newname);
if (r == 0)
return (ISC_R_SUCCESS);
else
return (isc__errno2result(errno));
}
isc_boolean_t
isc_file_exists(const char *pathname) {
struct stat stats;
REQUIRE(pathname != NULL);
return (ISC_TF(file_stats(pathname, &stats) == ISC_R_SUCCESS));
}
isc_result_t
isc_file_isplainfile(const char *filename) {
/*
* This function returns success if filename is a plain file.
*/
struct stat filestat;
memset(&filestat,0,sizeof(struct stat));
if ((stat(filename, &filestat)) == -1)
return(isc__errno2result(errno));
if(! S_ISREG(filestat.st_mode))
return(ISC_R_INVALIDFILE);
return(ISC_R_SUCCESS);
}
isc_result_t
isc_file_isplainfilefd(int fd) {
/*
* This function returns success if filename is a plain file.
*/
struct stat filestat;
memset(&filestat,0,sizeof(struct stat));
if ((fstat(fd, &filestat)) == -1)
return(isc__errno2result(errno));
if(! S_ISREG(filestat.st_mode))
return(ISC_R_INVALIDFILE);
return(ISC_R_SUCCESS);
}
isc_result_t
isc_file_isdirectory(const char *filename) {
/*
* This function returns success if filename is a directory.
*/
struct stat filestat;
memset(&filestat,0,sizeof(struct stat));
if ((stat(filename, &filestat)) == -1)
return(isc__errno2result(errno));
if(! S_ISDIR(filestat.st_mode))
return(ISC_R_INVALIDFILE);
return(ISC_R_SUCCESS);
}
isc_boolean_t
isc_file_isabsolute(const char *filename) {
REQUIRE(filename != NULL);
/*
* Look for c:\path\... style, c:/path/... or \\computer\shar\path...
* the UNC style file specs
*/
if ((filename[0] == '\\') && (filename[1] == '\\'))
return (ISC_TRUE);
if (isalpha(filename[0]) && filename[1] == ':' && filename[2] == '\\')
return (ISC_TRUE);
if (isalpha(filename[0]) && filename[1] == ':' && filename[2] == '/')
return (ISC_TRUE);
return (ISC_FALSE);
}
isc_boolean_t
isc_file_iscurrentdir(const char *filename) {
REQUIRE(filename != NULL);
return (ISC_TF(filename[0] == '.' && filename[1] == '\0'));
}
isc_boolean_t
isc_file_ischdiridempotent(const char *filename) {
REQUIRE(filename != NULL);
if (isc_file_isabsolute(filename))
return (ISC_TRUE);
if (filename[0] == '\\')
return (ISC_TRUE);
if (filename[0] == '/')
return (ISC_TRUE);
if (isc_file_iscurrentdir(filename))
return (ISC_TRUE);
return (ISC_FALSE);
}
const char *
isc_file_basename(const char *filename) {
char *s;
REQUIRE(filename != NULL);
s = strrchr(filename, '\\');
if (s == NULL)
return (filename);
return (s + 1);
}
isc_result_t
isc_file_progname(const char *filename, char *progname, size_t namelen) {
const char *s;
char *p;
size_t len;
REQUIRE(filename != NULL);
REQUIRE(progname != NULL);
/*
* Strip the path from the name
*/
s = isc_file_basename(filename);
if (s == NULL) {
return (ISC_R_NOSPACE);
}
/*
* Strip any and all suffixes
*/
p = strchr(s, '.');
if (p == NULL) {
if (namelen <= strlen(s))
return (ISC_R_NOSPACE);
strcpy(progname, s);
return (ISC_R_SUCCESS);
}
/*
* Copy the result to the buffer
*/
len = p - s;
if (len >= namelen)
return (ISC_R_NOSPACE);
strncpy(progname, s, len);
progname[len] = '\0';
return (ISC_R_SUCCESS);
}
isc_result_t
isc_file_absolutepath(const char *filename, char *path, size_t pathlen) {
char *ptrname;
DWORD retval;
REQUIRE(filename != NULL);
REQUIRE(path != NULL);
retval = GetFullPathName(filename, pathlen, path, &ptrname);
/* Something went wrong in getting the path */
if (retval == 0)
return (ISC_R_NOTFOUND);
/* Caller needs to provide a larger buffer to contain the string */
if (retval >= pathlen)
return (ISC_R_NOSPACE);
return (ISC_R_SUCCESS);
}
isc_result_t
isc_file_truncate(const char *filename, isc_offset_t size) {
int fh;
REQUIRE(filename != NULL && size >= 0);
if ((fh = open(filename, _O_RDWR | _O_BINARY)) < 0)
return (isc__errno2result(errno));
if(_chsize(fh, size) != 0) {
close(fh);
return (isc__errno2result(errno));
}
close(fh);
return (ISC_R_SUCCESS);
}
isc_result_t
isc_file_safecreate(const char *filename, FILE **fp) {
isc_result_t result;
int flags;
struct stat sb;
FILE *f;
int fd;
REQUIRE(filename != NULL);
REQUIRE(fp != NULL && *fp == NULL);
result = file_stats(filename, &sb);
if (result == ISC_R_SUCCESS) {
if ((sb.st_mode & S_IFREG) == 0)
return (ISC_R_INVALIDFILE);
flags = O_WRONLY | O_TRUNC;
} else if (result == ISC_R_FILENOTFOUND) {
flags = O_WRONLY | O_CREAT | O_EXCL;
} else
return (result);
fd = open(filename, flags, S_IRUSR | S_IWUSR);
if (fd == -1)
return (isc__errno2result(errno));
f = fdopen(fd, "w");
if (f == NULL) {
result = isc__errno2result(errno);
close(fd);
return (result);
}
*fp = f;
return (ISC_R_SUCCESS);
}
isc_result_t
isc_file_splitpath(isc_mem_t *mctx, char *path, char **dirname, char **basename)
{
char *dir, *file, *slash;
char *backslash;
slash = strrchr(path, '/');
backslash = strrchr(path, '\\');
if ((slash != NULL && backslash != NULL && backslash > slash) ||
(slash == NULL && backslash != NULL))
slash = backslash;
if (slash == path) {
file = ++slash;
dir = isc_mem_strdup(mctx, "/");
} else if (slash != NULL) {
file = ++slash;
dir = isc_mem_allocate(mctx, slash - path);
if (dir != NULL)
strlcpy(dir, path, slash - path);
} else {
file = path;
dir = isc_mem_strdup(mctx, ".");
}
if (dir == NULL)
return (ISC_R_NOMEMORY);
if (*file == '\0') {
isc_mem_free(mctx, dir);
return (ISC_R_INVALIDFILE);
}
*dirname = dir;
*basename = file;
return (ISC_R_SUCCESS);
}
void *
isc_file_mmap(void *addr, size_t len, int prot,
int flags, int fd, off_t offset)
{
void *buf;
ssize_t ret;
off_t end;
UNUSED(addr);
UNUSED(prot);
UNUSED(flags);
end = lseek(fd, 0, SEEK_END);
lseek(fd, offset, SEEK_SET);
if (end - offset < (off_t) len)
len = end - offset;
buf = malloc(len);
ret = read(fd, buf, len);
if (ret != (ssize_t) len) {
free(buf);
buf = NULL;
}
return (buf);
}
int
isc_file_munmap(void *addr, size_t len) {
UNUSED(len);
free(addr);
return (0);
}