1*eabc0478Schristos /* $NetBSD: file.c,v 1.2 2024/08/18 20:47:15 christos Exp $ */ 2897be3a4Schristos 3897be3a4Schristos /* 4897be3a4Schristos * Copyright (C) 2004, 2005, 2007, 2009, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") 5897be3a4Schristos * Copyright (C) 2000-2002 Internet Software Consortium. 6897be3a4Schristos * 7897be3a4Schristos * Permission to use, copy, modify, and/or distribute this software for any 8897be3a4Schristos * purpose with or without fee is hereby granted, provided that the above 9897be3a4Schristos * copyright notice and this permission notice appear in all copies. 10897be3a4Schristos * 11897be3a4Schristos * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 12897be3a4Schristos * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 13897be3a4Schristos * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 14897be3a4Schristos * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 15897be3a4Schristos * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 16897be3a4Schristos * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17897be3a4Schristos * PERFORMANCE OF THIS SOFTWARE. 18897be3a4Schristos */ 19897be3a4Schristos 20897be3a4Schristos /* 21897be3a4Schristos * Portions Copyright (c) 1987, 1993 22897be3a4Schristos * The Regents of the University of California. All rights reserved. 23897be3a4Schristos * 24897be3a4Schristos * Redistribution and use in source and binary forms, with or without 25897be3a4Schristos * modification, are permitted provided that the following conditions 26897be3a4Schristos * are met: 27897be3a4Schristos * 1. Redistributions of source code must retain the above copyright 28897be3a4Schristos * notice, this list of conditions and the following disclaimer. 29897be3a4Schristos * 2. Redistributions in binary form must reproduce the above copyright 30897be3a4Schristos * notice, this list of conditions and the following disclaimer in the 31897be3a4Schristos * documentation and/or other materials provided with the distribution. 32897be3a4Schristos * 3. All advertising materials mentioning features or use of this software 33897be3a4Schristos * must display the following acknowledgement: 34897be3a4Schristos * This product includes software developed by the University of 35897be3a4Schristos * California, Berkeley and its contributors. 36897be3a4Schristos * 4. Neither the name of the University nor the names of its contributors 37897be3a4Schristos * may be used to endorse or promote products derived from this software 38897be3a4Schristos * without specific prior written permission. 39897be3a4Schristos * 40897be3a4Schristos * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 41897be3a4Schristos * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 42897be3a4Schristos * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 43897be3a4Schristos * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 44897be3a4Schristos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 45897be3a4Schristos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 46897be3a4Schristos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 47897be3a4Schristos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 48897be3a4Schristos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 49897be3a4Schristos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 50897be3a4Schristos * SUCH DAMAGE. 51897be3a4Schristos */ 52897be3a4Schristos 53897be3a4Schristos /* Id */ 54897be3a4Schristos 55897be3a4Schristos /*! \file */ 56897be3a4Schristos 57897be3a4Schristos #include <config.h> 58897be3a4Schristos 59897be3a4Schristos #include <errno.h> 60897be3a4Schristos #include <fcntl.h> 61897be3a4Schristos #include <limits.h> 62897be3a4Schristos #include <stdlib.h> 63897be3a4Schristos #include <time.h> /* Required for utimes on some platforms. */ 64897be3a4Schristos #include <unistd.h> /* Required for mkstemp on NetBSD. */ 65897be3a4Schristos 66897be3a4Schristos 67897be3a4Schristos #include <sys/stat.h> 68897be3a4Schristos #include <sys/time.h> 69897be3a4Schristos 70897be3a4Schristos #include <isc/dir.h> 71897be3a4Schristos #include <isc/file.h> 72897be3a4Schristos #include <isc/log.h> 73897be3a4Schristos #include <isc/mem.h> 74897be3a4Schristos #include <isc/random.h> 75897be3a4Schristos #include <isc/string.h> 76897be3a4Schristos #include <isc/time.h> 77897be3a4Schristos #include <isc/util.h> 78897be3a4Schristos 79897be3a4Schristos #include "errno2result.h" 80897be3a4Schristos #include "ntp_stdlib.h" /* NTP change for strlcpy, strlcat */ 81897be3a4Schristos 82897be3a4Schristos /* 83897be3a4Schristos * XXXDCL As the API for accessing file statistics undoubtedly gets expanded, 84897be3a4Schristos * it might be good to provide a mechanism that allows for the results 85897be3a4Schristos * of a previous stat() to be used again without having to do another stat, 86897be3a4Schristos * such as perl's mechanism of using "_" in place of a file name to indicate 87897be3a4Schristos * that the results of the last stat should be used. But then you get into 88897be3a4Schristos * annoying MP issues. BTW, Win32 has stat(). 89897be3a4Schristos */ 90897be3a4Schristos static isc_result_t 91897be3a4Schristos file_stats(const char *file, struct stat *stats) { 92897be3a4Schristos isc_result_t result = ISC_R_SUCCESS; 93897be3a4Schristos 94897be3a4Schristos REQUIRE(file != NULL); 95897be3a4Schristos REQUIRE(stats != NULL); 96897be3a4Schristos 97897be3a4Schristos if (stat(file, stats) != 0) 98897be3a4Schristos result = isc__errno2result(errno); 99897be3a4Schristos 100897be3a4Schristos return (result); 101897be3a4Schristos } 102897be3a4Schristos 103897be3a4Schristos isc_result_t 104897be3a4Schristos isc_file_getmodtime(const char *file, isc_time_t *itime) { 105897be3a4Schristos isc_result_t result; 106897be3a4Schristos struct stat stats; 107897be3a4Schristos 108897be3a4Schristos REQUIRE(file != NULL); 109897be3a4Schristos REQUIRE(itime != NULL); 110897be3a4Schristos 111897be3a4Schristos result = file_stats(file, &stats); 112897be3a4Schristos 113897be3a4Schristos if (result == ISC_R_SUCCESS) 114897be3a4Schristos /* 115897be3a4Schristos * XXXDCL some operating systems provide nanoseconds, too, 116897be3a4Schristos * such as BSD/OS via st_mtimespec. 117897be3a4Schristos */ 118897be3a4Schristos isc_time_set(itime, stats.st_mtime, 0); 119897be3a4Schristos 120897be3a4Schristos return (result); 121897be3a4Schristos } 122897be3a4Schristos 123897be3a4Schristos isc_result_t 124897be3a4Schristos isc_file_settime(const char *file, isc_time_t *itime) { 125897be3a4Schristos struct timeval times[2]; 126897be3a4Schristos 127897be3a4Schristos REQUIRE(file != NULL && itime != NULL); 128897be3a4Schristos 129897be3a4Schristos /* 130897be3a4Schristos * tv_sec is at least a 32 bit quantity on all platforms we're 131897be3a4Schristos * dealing with, but it is signed on most (all?) of them, 132897be3a4Schristos * so we need to make sure the high bit isn't set. This unfortunately 133897be3a4Schristos * loses when either: 134897be3a4Schristos * * tv_sec becomes a signed 64 bit integer but long is 32 bits 135897be3a4Schristos * and isc_time_seconds > LONG_MAX, or 136897be3a4Schristos * * isc_time_seconds is changed to be > 32 bits but long is 32 bits 137897be3a4Schristos * and isc_time_seconds has at least 33 significant bits. 138897be3a4Schristos */ 139897be3a4Schristos times[0].tv_sec = times[1].tv_sec = (long)isc_time_seconds(itime); 140897be3a4Schristos 141897be3a4Schristos /* 142897be3a4Schristos * Here is the real check for the high bit being set. 143897be3a4Schristos */ 144897be3a4Schristos if ((times[0].tv_sec & 145897be3a4Schristos (1ULL << (sizeof(times[0].tv_sec) * CHAR_BIT - 1))) != 0) 146897be3a4Schristos return (ISC_R_RANGE); 147897be3a4Schristos 148897be3a4Schristos /* 149897be3a4Schristos * isc_time_nanoseconds guarantees a value that divided by 1000 will 150897be3a4Schristos * fit into the minimum possible size tv_usec field. Unfortunately, 151897be3a4Schristos * we don't know what that type is so can't cast directly ... but 152897be3a4Schristos * we can at least cast to signed so the IRIX compiler shuts up. 153897be3a4Schristos */ 154897be3a4Schristos times[0].tv_usec = times[1].tv_usec = 155897be3a4Schristos (isc_int32_t)(isc_time_nanoseconds(itime) / 1000); 156897be3a4Schristos 157897be3a4Schristos if (utimes(file, times) < 0) 158897be3a4Schristos return (isc__errno2result(errno)); 159897be3a4Schristos 160897be3a4Schristos return (ISC_R_SUCCESS); 161897be3a4Schristos } 162897be3a4Schristos 163897be3a4Schristos #undef TEMPLATE 164897be3a4Schristos #define TEMPLATE "tmp-XXXXXXXXXX" /*%< 14 characters. */ 165897be3a4Schristos 166897be3a4Schristos isc_result_t 167897be3a4Schristos isc_file_mktemplate(const char *path, char *buf, size_t buflen) { 168897be3a4Schristos return (isc_file_template(path, TEMPLATE, buf, buflen)); 169897be3a4Schristos } 170897be3a4Schristos 171897be3a4Schristos isc_result_t 172897be3a4Schristos isc_file_template(const char *path, const char *templet, char *buf, 173897be3a4Schristos size_t buflen) { 174897be3a4Schristos char *s; 175897be3a4Schristos 176897be3a4Schristos REQUIRE(path != NULL); 177897be3a4Schristos REQUIRE(templet != NULL); 178897be3a4Schristos REQUIRE(buf != NULL); 179897be3a4Schristos 180897be3a4Schristos s = strrchr(templet, '/'); 181897be3a4Schristos if (s != NULL) 182897be3a4Schristos templet = s + 1; 183897be3a4Schristos 184897be3a4Schristos s = strrchr(path, '/'); 185897be3a4Schristos 186897be3a4Schristos if (s != NULL) { 187897be3a4Schristos if ((s - path + 1 + strlen(templet) + 1) > buflen) 188897be3a4Schristos return (ISC_R_NOSPACE); 189897be3a4Schristos 190897be3a4Schristos strlcpy(buf, path, buflen); 191897be3a4Schristos buf[s - path + 1] = '\0'; 192897be3a4Schristos strlcat(buf, templet, buflen); 193897be3a4Schristos } else { 194897be3a4Schristos if ((strlen(templet) + 1) > buflen) 195897be3a4Schristos return (ISC_R_NOSPACE); 196897be3a4Schristos 197897be3a4Schristos strlcpy(buf, templet, buflen); 198897be3a4Schristos } 199897be3a4Schristos 200897be3a4Schristos return (ISC_R_SUCCESS); 201897be3a4Schristos } 202897be3a4Schristos 203897be3a4Schristos static char alphnum[] = 204897be3a4Schristos "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; 205897be3a4Schristos 206897be3a4Schristos isc_result_t 207897be3a4Schristos isc_file_renameunique(const char *file, char *templet) { 208897be3a4Schristos char *x; 209897be3a4Schristos char *cp; 210897be3a4Schristos isc_uint32_t which; 211897be3a4Schristos 212897be3a4Schristos REQUIRE(file != NULL); 213897be3a4Schristos REQUIRE(templet != NULL); 214897be3a4Schristos 215897be3a4Schristos cp = templet; 216897be3a4Schristos while (*cp != '\0') 217897be3a4Schristos cp++; 218897be3a4Schristos if (cp == templet) 219897be3a4Schristos return (ISC_R_FAILURE); 220897be3a4Schristos 221897be3a4Schristos x = cp--; 222897be3a4Schristos while (cp >= templet && *cp == 'X') { 223897be3a4Schristos isc_random_get(&which); 224897be3a4Schristos *cp = alphnum[which % (sizeof(alphnum) - 1)]; 225897be3a4Schristos x = cp--; 226897be3a4Schristos } 227897be3a4Schristos while (link(file, templet) == -1) { 228897be3a4Schristos if (errno != EEXIST) 229897be3a4Schristos return (isc__errno2result(errno)); 230897be3a4Schristos for (cp = x;;) { 231897be3a4Schristos char *t; 232897be3a4Schristos if (*cp == '\0') 233897be3a4Schristos return (ISC_R_FAILURE); 234897be3a4Schristos t = strchr(alphnum, *cp); 235897be3a4Schristos if (t == NULL || *++t == '\0') 236897be3a4Schristos *cp++ = alphnum[0]; 237897be3a4Schristos else { 238897be3a4Schristos *cp = *t; 239897be3a4Schristos break; 240897be3a4Schristos } 241897be3a4Schristos } 242897be3a4Schristos } 243897be3a4Schristos if (unlink(file) < 0) 244897be3a4Schristos if (errno != ENOENT) 245897be3a4Schristos return (isc__errno2result(errno)); 246897be3a4Schristos return (ISC_R_SUCCESS); 247897be3a4Schristos } 248897be3a4Schristos 249897be3a4Schristos isc_result_t 250897be3a4Schristos isc_file_openunique(char *templet, FILE **fp) { 251897be3a4Schristos int mode = S_IWUSR|S_IRUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH; 252897be3a4Schristos return (isc_file_openuniquemode(templet, mode, fp)); 253897be3a4Schristos } 254897be3a4Schristos 255897be3a4Schristos isc_result_t 256897be3a4Schristos isc_file_openuniqueprivate(char *templet, FILE **fp) { 257897be3a4Schristos int mode = S_IWUSR|S_IRUSR; 258897be3a4Schristos return (isc_file_openuniquemode(templet, mode, fp)); 259897be3a4Schristos } 260897be3a4Schristos 261897be3a4Schristos isc_result_t 262897be3a4Schristos isc_file_openuniquemode(char *templet, int mode, FILE **fp) { 263897be3a4Schristos int fd; 264897be3a4Schristos FILE *f; 265897be3a4Schristos isc_result_t result = ISC_R_SUCCESS; 266897be3a4Schristos char *x; 267897be3a4Schristos char *cp; 268897be3a4Schristos isc_uint32_t which; 269897be3a4Schristos 270897be3a4Schristos REQUIRE(templet != NULL); 271897be3a4Schristos REQUIRE(fp != NULL && *fp == NULL); 272897be3a4Schristos 273897be3a4Schristos cp = templet; 274897be3a4Schristos while (*cp != '\0') 275897be3a4Schristos cp++; 276897be3a4Schristos if (cp == templet) 277897be3a4Schristos return (ISC_R_FAILURE); 278897be3a4Schristos 279897be3a4Schristos x = cp--; 280897be3a4Schristos while (cp >= templet && *cp == 'X') { 281897be3a4Schristos isc_random_get(&which); 282897be3a4Schristos *cp = alphnum[which % (sizeof(alphnum) - 1)]; 283897be3a4Schristos x = cp--; 284897be3a4Schristos } 285897be3a4Schristos 286897be3a4Schristos 287897be3a4Schristos while ((fd = open(templet, O_RDWR|O_CREAT|O_EXCL, mode)) == -1) { 288897be3a4Schristos if (errno != EEXIST) 289897be3a4Schristos return (isc__errno2result(errno)); 290897be3a4Schristos for (cp = x;;) { 291897be3a4Schristos char *t; 292897be3a4Schristos if (*cp == '\0') 293897be3a4Schristos return (ISC_R_FAILURE); 294897be3a4Schristos t = strchr(alphnum, *cp); 295897be3a4Schristos if (t == NULL || *++t == '\0') 296897be3a4Schristos *cp++ = alphnum[0]; 297897be3a4Schristos else { 298897be3a4Schristos *cp = *t; 299897be3a4Schristos break; 300897be3a4Schristos } 301897be3a4Schristos } 302897be3a4Schristos } 303897be3a4Schristos f = fdopen(fd, "w+"); 304897be3a4Schristos if (f == NULL) { 305897be3a4Schristos result = isc__errno2result(errno); 306897be3a4Schristos if (remove(templet) < 0) { 307897be3a4Schristos isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, 308897be3a4Schristos ISC_LOGMODULE_FILE, ISC_LOG_ERROR, 309897be3a4Schristos "remove '%s': failed", templet); 310897be3a4Schristos } 311897be3a4Schristos (void)close(fd); 312897be3a4Schristos } else 313897be3a4Schristos *fp = f; 314897be3a4Schristos 315897be3a4Schristos return (result); 316897be3a4Schristos } 317897be3a4Schristos 318897be3a4Schristos isc_result_t 319897be3a4Schristos isc_file_remove(const char *filename) { 320897be3a4Schristos int r; 321897be3a4Schristos 322897be3a4Schristos REQUIRE(filename != NULL); 323897be3a4Schristos 324897be3a4Schristos r = unlink(filename); 325897be3a4Schristos if (r == 0) 326897be3a4Schristos return (ISC_R_SUCCESS); 327897be3a4Schristos else 328897be3a4Schristos return (isc__errno2result(errno)); 329897be3a4Schristos } 330897be3a4Schristos 331897be3a4Schristos isc_result_t 332897be3a4Schristos isc_file_rename(const char *oldname, const char *newname) { 333897be3a4Schristos int r; 334897be3a4Schristos 335897be3a4Schristos REQUIRE(oldname != NULL); 336897be3a4Schristos REQUIRE(newname != NULL); 337897be3a4Schristos 338897be3a4Schristos r = rename(oldname, newname); 339897be3a4Schristos if (r == 0) 340897be3a4Schristos return (ISC_R_SUCCESS); 341897be3a4Schristos else 342897be3a4Schristos return (isc__errno2result(errno)); 343897be3a4Schristos } 344897be3a4Schristos 345897be3a4Schristos isc_boolean_t 346897be3a4Schristos isc_file_exists(const char *pathname) { 347897be3a4Schristos struct stat stats; 348897be3a4Schristos 349897be3a4Schristos REQUIRE(pathname != NULL); 350897be3a4Schristos 351897be3a4Schristos return (ISC_TF(file_stats(pathname, &stats) == ISC_R_SUCCESS)); 352897be3a4Schristos } 353897be3a4Schristos 354897be3a4Schristos isc_result_t 355897be3a4Schristos isc_file_isplainfile(const char *filename) { 356897be3a4Schristos /* 357897be3a4Schristos * This function returns success if filename is a plain file. 358897be3a4Schristos */ 359897be3a4Schristos struct stat filestat; 360897be3a4Schristos memset(&filestat,0,sizeof(struct stat)); 361897be3a4Schristos 362897be3a4Schristos if ((stat(filename, &filestat)) == -1) 363897be3a4Schristos return(isc__errno2result(errno)); 364897be3a4Schristos 365897be3a4Schristos if(! S_ISREG(filestat.st_mode)) 366897be3a4Schristos return(ISC_R_INVALIDFILE); 367897be3a4Schristos 368897be3a4Schristos return(ISC_R_SUCCESS); 369897be3a4Schristos } 370897be3a4Schristos 371897be3a4Schristos isc_boolean_t 372897be3a4Schristos isc_file_isabsolute(const char *filename) { 373897be3a4Schristos REQUIRE(filename != NULL); 374897be3a4Schristos return (ISC_TF(filename[0] == '/')); 375897be3a4Schristos } 376897be3a4Schristos 377897be3a4Schristos isc_boolean_t 378897be3a4Schristos isc_file_iscurrentdir(const char *filename) { 379897be3a4Schristos REQUIRE(filename != NULL); 380897be3a4Schristos return (ISC_TF(filename[0] == '.' && filename[1] == '\0')); 381897be3a4Schristos } 382897be3a4Schristos 383897be3a4Schristos isc_boolean_t 384897be3a4Schristos isc_file_ischdiridempotent(const char *filename) { 385897be3a4Schristos REQUIRE(filename != NULL); 386897be3a4Schristos if (isc_file_isabsolute(filename)) 387897be3a4Schristos return (ISC_TRUE); 388897be3a4Schristos if (isc_file_iscurrentdir(filename)) 389897be3a4Schristos return (ISC_TRUE); 390897be3a4Schristos return (ISC_FALSE); 391897be3a4Schristos } 392897be3a4Schristos 393897be3a4Schristos const char * 394897be3a4Schristos isc_file_basename(const char *filename) { 395897be3a4Schristos char *s; 396897be3a4Schristos 397897be3a4Schristos REQUIRE(filename != NULL); 398897be3a4Schristos 399897be3a4Schristos s = strrchr(filename, '/'); 400897be3a4Schristos if (s == NULL) 401897be3a4Schristos return (filename); 402897be3a4Schristos 403897be3a4Schristos return (s + 1); 404897be3a4Schristos } 405897be3a4Schristos 406897be3a4Schristos isc_result_t 407897be3a4Schristos isc_file_progname(const char *filename, char *buf, size_t buflen) { 408897be3a4Schristos const char *base; 409897be3a4Schristos size_t len; 410897be3a4Schristos 411897be3a4Schristos REQUIRE(filename != NULL); 412897be3a4Schristos REQUIRE(buf != NULL); 413897be3a4Schristos 414897be3a4Schristos base = isc_file_basename(filename); 415897be3a4Schristos len = strlen(base) + 1; 416897be3a4Schristos 417897be3a4Schristos if (len > buflen) 418897be3a4Schristos return (ISC_R_NOSPACE); 419897be3a4Schristos memcpy(buf, base, len); 420897be3a4Schristos 421897be3a4Schristos return (ISC_R_SUCCESS); 422897be3a4Schristos } 423897be3a4Schristos 424897be3a4Schristos /* 425897be3a4Schristos * Put the absolute name of the current directory into 'dirname', which is 426897be3a4Schristos * a buffer of at least 'length' characters. End the string with the 427897be3a4Schristos * appropriate path separator, such that the final product could be 428897be3a4Schristos * concatenated with a relative pathname to make a valid pathname string. 429897be3a4Schristos */ 430897be3a4Schristos static isc_result_t 431897be3a4Schristos dir_current(char *dirname, size_t length) { 432897be3a4Schristos char *cwd; 433897be3a4Schristos isc_result_t result = ISC_R_SUCCESS; 434897be3a4Schristos 435897be3a4Schristos REQUIRE(dirname != NULL); 436897be3a4Schristos REQUIRE(length > 0U); 437897be3a4Schristos 438897be3a4Schristos cwd = getcwd(dirname, length); 439897be3a4Schristos 440897be3a4Schristos if (cwd == NULL) { 441897be3a4Schristos if (errno == ERANGE) 442897be3a4Schristos result = ISC_R_NOSPACE; 443897be3a4Schristos else 444897be3a4Schristos result = isc__errno2result(errno); 445897be3a4Schristos } else { 446897be3a4Schristos if (strlen(dirname) + 1 == length) 447897be3a4Schristos result = ISC_R_NOSPACE; 448897be3a4Schristos else if (dirname[1] != '\0') 449897be3a4Schristos strlcat(dirname, "/", length); 450897be3a4Schristos } 451897be3a4Schristos 452897be3a4Schristos return (result); 453897be3a4Schristos } 454897be3a4Schristos 455897be3a4Schristos isc_result_t 456897be3a4Schristos isc_file_absolutepath(const char *filename, char *path, size_t pathlen) { 457897be3a4Schristos isc_result_t result; 458897be3a4Schristos result = dir_current(path, pathlen); 459897be3a4Schristos if (result != ISC_R_SUCCESS) 460897be3a4Schristos return (result); 461897be3a4Schristos if (strlen(path) + strlen(filename) + 1 > pathlen) 462897be3a4Schristos return (ISC_R_NOSPACE); 463897be3a4Schristos strlcat(path, filename, pathlen); 464897be3a4Schristos return (ISC_R_SUCCESS); 465897be3a4Schristos } 466897be3a4Schristos 467897be3a4Schristos isc_result_t 468897be3a4Schristos isc_file_truncate(const char *filename, isc_offset_t size) { 469897be3a4Schristos isc_result_t result = ISC_R_SUCCESS; 470897be3a4Schristos 471897be3a4Schristos if (truncate(filename, size) < 0) 472897be3a4Schristos result = isc__errno2result(errno); 473897be3a4Schristos return (result); 474897be3a4Schristos } 475897be3a4Schristos 476897be3a4Schristos isc_result_t 477897be3a4Schristos isc_file_safecreate(const char *filename, FILE **fp) { 478897be3a4Schristos isc_result_t result; 479897be3a4Schristos int flags; 480897be3a4Schristos struct stat sb; 481897be3a4Schristos FILE *f; 482897be3a4Schristos int fd; 483897be3a4Schristos 484897be3a4Schristos REQUIRE(filename != NULL); 485897be3a4Schristos REQUIRE(fp != NULL && *fp == NULL); 486897be3a4Schristos 487897be3a4Schristos result = file_stats(filename, &sb); 488897be3a4Schristos if (result == ISC_R_SUCCESS) { 489897be3a4Schristos if ((sb.st_mode & S_IFREG) == 0) 490897be3a4Schristos return (ISC_R_INVALIDFILE); 491897be3a4Schristos flags = O_WRONLY | O_TRUNC; 492897be3a4Schristos } else if (result == ISC_R_FILENOTFOUND) { 493897be3a4Schristos flags = O_WRONLY | O_CREAT | O_EXCL; 494897be3a4Schristos } else 495897be3a4Schristos return (result); 496897be3a4Schristos 497897be3a4Schristos fd = open(filename, flags, S_IRUSR | S_IWUSR); 498897be3a4Schristos if (fd == -1) 499897be3a4Schristos return (isc__errno2result(errno)); 500897be3a4Schristos 501897be3a4Schristos f = fdopen(fd, "w"); 502897be3a4Schristos if (f == NULL) { 503897be3a4Schristos result = isc__errno2result(errno); 504897be3a4Schristos close(fd); 505897be3a4Schristos return (result); 506897be3a4Schristos } 507897be3a4Schristos 508897be3a4Schristos *fp = f; 509897be3a4Schristos return (ISC_R_SUCCESS); 510897be3a4Schristos } 511897be3a4Schristos 512897be3a4Schristos isc_result_t 513897be3a4Schristos isc_file_splitpath(isc_mem_t *mctx, char *path, char **dirnam, char **basenam) 514897be3a4Schristos { 515897be3a4Schristos char *dir, *file, *slash; 516897be3a4Schristos 517897be3a4Schristos REQUIRE(path != NULL); 518897be3a4Schristos 519897be3a4Schristos slash = strrchr(path, '/'); 520897be3a4Schristos 521897be3a4Schristos if (slash == path) { 522897be3a4Schristos file = ++slash; 523897be3a4Schristos dir = isc_mem_strdup(mctx, "/"); 524897be3a4Schristos } else if (slash != NULL) { 525897be3a4Schristos file = ++slash; 526897be3a4Schristos dir = isc_mem_allocate(mctx, slash - path); 527897be3a4Schristos if (dir != NULL) 528897be3a4Schristos strlcpy(dir, path, slash - path); 529897be3a4Schristos } else { 530897be3a4Schristos file = path; 531897be3a4Schristos dir = isc_mem_strdup(mctx, "."); 532897be3a4Schristos } 533897be3a4Schristos 534897be3a4Schristos if (dir == NULL) 535897be3a4Schristos return (ISC_R_NOMEMORY); 536897be3a4Schristos 537897be3a4Schristos if (*file == '\0') { 538897be3a4Schristos isc_mem_free(mctx, dir); 539897be3a4Schristos return (ISC_R_INVALIDFILE); 540897be3a4Schristos } 541897be3a4Schristos 542897be3a4Schristos *dirnam = dir; 543897be3a4Schristos *basenam = file; 544897be3a4Schristos 545897be3a4Schristos return (ISC_R_SUCCESS); 546897be3a4Schristos } 547