1258945Sroberto/* 2280849Scy * Copyright (C) 2004, 2005, 2007, 2009, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") 3258945Sroberto * Copyright (C) 2000-2002 Internet Software Consortium. 4258945Sroberto * 5258945Sroberto * Permission to use, copy, modify, and/or distribute this software for any 6258945Sroberto * purpose with or without fee is hereby granted, provided that the above 7258945Sroberto * copyright notice and this permission notice appear in all copies. 8258945Sroberto * 9258945Sroberto * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10258945Sroberto * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11258945Sroberto * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12258945Sroberto * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13258945Sroberto * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14258945Sroberto * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15258945Sroberto * PERFORMANCE OF THIS SOFTWARE. 16258945Sroberto */ 17258945Sroberto 18258945Sroberto/* 19258945Sroberto * Portions Copyright (c) 1987, 1993 20258945Sroberto * The Regents of the University of California. All rights reserved. 21258945Sroberto * 22258945Sroberto * Redistribution and use in source and binary forms, with or without 23258945Sroberto * modification, are permitted provided that the following conditions 24258945Sroberto * are met: 25258945Sroberto * 1. Redistributions of source code must retain the above copyright 26258945Sroberto * notice, this list of conditions and the following disclaimer. 27258945Sroberto * 2. Redistributions in binary form must reproduce the above copyright 28258945Sroberto * notice, this list of conditions and the following disclaimer in the 29258945Sroberto * documentation and/or other materials provided with the distribution. 30258945Sroberto * 3. All advertising materials mentioning features or use of this software 31258945Sroberto * must display the following acknowledgement: 32258945Sroberto * This product includes software developed by the University of 33258945Sroberto * California, Berkeley and its contributors. 34258945Sroberto * 4. Neither the name of the University nor the names of its contributors 35258945Sroberto * may be used to endorse or promote products derived from this software 36258945Sroberto * without specific prior written permission. 37258945Sroberto * 38258945Sroberto * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 39258945Sroberto * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 40258945Sroberto * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 41258945Sroberto * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 42258945Sroberto * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 43258945Sroberto * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 44258945Sroberto * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 45258945Sroberto * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 46258945Sroberto * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 47258945Sroberto * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 48258945Sroberto * SUCH DAMAGE. 49258945Sroberto */ 50258945Sroberto 51280849Scy/* $Id$ */ 52258945Sroberto 53258945Sroberto/*! \file */ 54258945Sroberto 55258945Sroberto#include <config.h> 56258945Sroberto 57258945Sroberto#include <errno.h> 58258945Sroberto#include <fcntl.h> 59258945Sroberto#include <limits.h> 60258945Sroberto#include <stdlib.h> 61258945Sroberto#include <time.h> /* Required for utimes on some platforms. */ 62258945Sroberto#include <unistd.h> /* Required for mkstemp on NetBSD. */ 63258945Sroberto 64258945Sroberto 65258945Sroberto#include <sys/stat.h> 66258945Sroberto#include <sys/time.h> 67258945Sroberto 68258945Sroberto#include <isc/dir.h> 69258945Sroberto#include <isc/file.h> 70258945Sroberto#include <isc/log.h> 71280849Scy#include <isc/mem.h> 72258945Sroberto#include <isc/random.h> 73258945Sroberto#include <isc/string.h> 74258945Sroberto#include <isc/time.h> 75258945Sroberto#include <isc/util.h> 76258945Sroberto 77258945Sroberto#include "errno2result.h" 78280849Scy#include "ntp_stdlib.h" /* NTP change for strlcpy, strlcat */ 79258945Sroberto 80258945Sroberto/* 81258945Sroberto * XXXDCL As the API for accessing file statistics undoubtedly gets expanded, 82258945Sroberto * it might be good to provide a mechanism that allows for the results 83258945Sroberto * of a previous stat() to be used again without having to do another stat, 84258945Sroberto * such as perl's mechanism of using "_" in place of a file name to indicate 85258945Sroberto * that the results of the last stat should be used. But then you get into 86258945Sroberto * annoying MP issues. BTW, Win32 has stat(). 87258945Sroberto */ 88258945Srobertostatic isc_result_t 89258945Srobertofile_stats(const char *file, struct stat *stats) { 90258945Sroberto isc_result_t result = ISC_R_SUCCESS; 91258945Sroberto 92258945Sroberto REQUIRE(file != NULL); 93258945Sroberto REQUIRE(stats != NULL); 94258945Sroberto 95258945Sroberto if (stat(file, stats) != 0) 96258945Sroberto result = isc__errno2result(errno); 97258945Sroberto 98258945Sroberto return (result); 99258945Sroberto} 100258945Sroberto 101258945Srobertoisc_result_t 102280849Scyisc_file_getmodtime(const char *file, isc_time_t *itime) { 103258945Sroberto isc_result_t result; 104258945Sroberto struct stat stats; 105258945Sroberto 106258945Sroberto REQUIRE(file != NULL); 107280849Scy REQUIRE(itime != NULL); 108258945Sroberto 109258945Sroberto result = file_stats(file, &stats); 110258945Sroberto 111258945Sroberto if (result == ISC_R_SUCCESS) 112258945Sroberto /* 113258945Sroberto * XXXDCL some operating systems provide nanoseconds, too, 114258945Sroberto * such as BSD/OS via st_mtimespec. 115258945Sroberto */ 116280849Scy isc_time_set(itime, stats.st_mtime, 0); 117258945Sroberto 118258945Sroberto return (result); 119258945Sroberto} 120258945Sroberto 121258945Srobertoisc_result_t 122280849Scyisc_file_settime(const char *file, isc_time_t *itime) { 123258945Sroberto struct timeval times[2]; 124258945Sroberto 125280849Scy REQUIRE(file != NULL && itime != NULL); 126258945Sroberto 127258945Sroberto /* 128258945Sroberto * tv_sec is at least a 32 bit quantity on all platforms we're 129258945Sroberto * dealing with, but it is signed on most (all?) of them, 130258945Sroberto * so we need to make sure the high bit isn't set. This unfortunately 131258945Sroberto * loses when either: 132258945Sroberto * * tv_sec becomes a signed 64 bit integer but long is 32 bits 133258945Sroberto * and isc_time_seconds > LONG_MAX, or 134258945Sroberto * * isc_time_seconds is changed to be > 32 bits but long is 32 bits 135258945Sroberto * and isc_time_seconds has at least 33 significant bits. 136258945Sroberto */ 137280849Scy times[0].tv_sec = times[1].tv_sec = (long)isc_time_seconds(itime); 138258945Sroberto 139258945Sroberto /* 140258945Sroberto * Here is the real check for the high bit being set. 141258945Sroberto */ 142258945Sroberto if ((times[0].tv_sec & 143258945Sroberto (1ULL << (sizeof(times[0].tv_sec) * CHAR_BIT - 1))) != 0) 144258945Sroberto return (ISC_R_RANGE); 145258945Sroberto 146258945Sroberto /* 147258945Sroberto * isc_time_nanoseconds guarantees a value that divided by 1000 will 148258945Sroberto * fit into the minimum possible size tv_usec field. Unfortunately, 149258945Sroberto * we don't know what that type is so can't cast directly ... but 150258945Sroberto * we can at least cast to signed so the IRIX compiler shuts up. 151258945Sroberto */ 152258945Sroberto times[0].tv_usec = times[1].tv_usec = 153280849Scy (isc_int32_t)(isc_time_nanoseconds(itime) / 1000); 154258945Sroberto 155258945Sroberto if (utimes(file, times) < 0) 156258945Sroberto return (isc__errno2result(errno)); 157258945Sroberto 158258945Sroberto return (ISC_R_SUCCESS); 159258945Sroberto} 160258945Sroberto 161258945Sroberto#undef TEMPLATE 162258945Sroberto#define TEMPLATE "tmp-XXXXXXXXXX" /*%< 14 characters. */ 163258945Sroberto 164258945Srobertoisc_result_t 165258945Srobertoisc_file_mktemplate(const char *path, char *buf, size_t buflen) { 166258945Sroberto return (isc_file_template(path, TEMPLATE, buf, buflen)); 167258945Sroberto} 168258945Sroberto 169258945Srobertoisc_result_t 170258945Srobertoisc_file_template(const char *path, const char *templet, char *buf, 171258945Sroberto size_t buflen) { 172258945Sroberto char *s; 173258945Sroberto 174258945Sroberto REQUIRE(path != NULL); 175258945Sroberto REQUIRE(templet != NULL); 176258945Sroberto REQUIRE(buf != NULL); 177258945Sroberto 178258945Sroberto s = strrchr(templet, '/'); 179258945Sroberto if (s != NULL) 180258945Sroberto templet = s + 1; 181258945Sroberto 182258945Sroberto s = strrchr(path, '/'); 183258945Sroberto 184258945Sroberto if (s != NULL) { 185258945Sroberto if ((s - path + 1 + strlen(templet) + 1) > buflen) 186258945Sroberto return (ISC_R_NOSPACE); 187258945Sroberto 188280849Scy strlcpy(buf, path, buflen); 189258945Sroberto buf[s - path + 1] = '\0'; 190280849Scy strlcat(buf, templet, buflen); 191258945Sroberto } else { 192258945Sroberto if ((strlen(templet) + 1) > buflen) 193258945Sroberto return (ISC_R_NOSPACE); 194258945Sroberto 195280849Scy strlcpy(buf, templet, buflen); 196258945Sroberto } 197258945Sroberto 198258945Sroberto return (ISC_R_SUCCESS); 199258945Sroberto} 200258945Sroberto 201258945Srobertostatic char alphnum[] = 202258945Sroberto "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; 203258945Sroberto 204258945Srobertoisc_result_t 205258945Srobertoisc_file_renameunique(const char *file, char *templet) { 206258945Sroberto char *x; 207258945Sroberto char *cp; 208258945Sroberto isc_uint32_t which; 209258945Sroberto 210258945Sroberto REQUIRE(file != NULL); 211258945Sroberto REQUIRE(templet != NULL); 212258945Sroberto 213258945Sroberto cp = templet; 214258945Sroberto while (*cp != '\0') 215258945Sroberto cp++; 216258945Sroberto if (cp == templet) 217258945Sroberto return (ISC_R_FAILURE); 218258945Sroberto 219258945Sroberto x = cp--; 220258945Sroberto while (cp >= templet && *cp == 'X') { 221258945Sroberto isc_random_get(&which); 222258945Sroberto *cp = alphnum[which % (sizeof(alphnum) - 1)]; 223258945Sroberto x = cp--; 224258945Sroberto } 225258945Sroberto while (link(file, templet) == -1) { 226258945Sroberto if (errno != EEXIST) 227258945Sroberto return (isc__errno2result(errno)); 228258945Sroberto for (cp = x;;) { 229258945Sroberto char *t; 230258945Sroberto if (*cp == '\0') 231258945Sroberto return (ISC_R_FAILURE); 232258945Sroberto t = strchr(alphnum, *cp); 233258945Sroberto if (t == NULL || *++t == '\0') 234258945Sroberto *cp++ = alphnum[0]; 235258945Sroberto else { 236258945Sroberto *cp = *t; 237258945Sroberto break; 238258945Sroberto } 239258945Sroberto } 240258945Sroberto } 241258945Sroberto if (unlink(file) < 0) 242258945Sroberto if (errno != ENOENT) 243258945Sroberto return (isc__errno2result(errno)); 244258945Sroberto return (ISC_R_SUCCESS); 245258945Sroberto} 246258945Sroberto 247280849Scyisc_result_t 248280849Scyisc_file_openunique(char *templet, FILE **fp) { 249280849Scy int mode = S_IWUSR|S_IRUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH; 250280849Scy return (isc_file_openuniquemode(templet, mode, fp)); 251280849Scy} 252258945Sroberto 253258945Srobertoisc_result_t 254280849Scyisc_file_openuniqueprivate(char *templet, FILE **fp) { 255280849Scy int mode = S_IWUSR|S_IRUSR; 256280849Scy return (isc_file_openuniquemode(templet, mode, fp)); 257280849Scy} 258280849Scy 259280849Scyisc_result_t 260280849Scyisc_file_openuniquemode(char *templet, int mode, FILE **fp) { 261258945Sroberto int fd; 262258945Sroberto FILE *f; 263258945Sroberto isc_result_t result = ISC_R_SUCCESS; 264258945Sroberto char *x; 265258945Sroberto char *cp; 266258945Sroberto isc_uint32_t which; 267258945Sroberto 268258945Sroberto REQUIRE(templet != NULL); 269258945Sroberto REQUIRE(fp != NULL && *fp == NULL); 270258945Sroberto 271258945Sroberto cp = templet; 272258945Sroberto while (*cp != '\0') 273258945Sroberto cp++; 274258945Sroberto if (cp == templet) 275258945Sroberto return (ISC_R_FAILURE); 276258945Sroberto 277258945Sroberto x = cp--; 278258945Sroberto while (cp >= templet && *cp == 'X') { 279258945Sroberto isc_random_get(&which); 280258945Sroberto *cp = alphnum[which % (sizeof(alphnum) - 1)]; 281258945Sroberto x = cp--; 282258945Sroberto } 283258945Sroberto 284258945Sroberto 285258945Sroberto while ((fd = open(templet, O_RDWR|O_CREAT|O_EXCL, mode)) == -1) { 286258945Sroberto if (errno != EEXIST) 287258945Sroberto return (isc__errno2result(errno)); 288258945Sroberto for (cp = x;;) { 289258945Sroberto char *t; 290258945Sroberto if (*cp == '\0') 291258945Sroberto return (ISC_R_FAILURE); 292258945Sroberto t = strchr(alphnum, *cp); 293258945Sroberto if (t == NULL || *++t == '\0') 294258945Sroberto *cp++ = alphnum[0]; 295258945Sroberto else { 296258945Sroberto *cp = *t; 297258945Sroberto break; 298258945Sroberto } 299258945Sroberto } 300258945Sroberto } 301258945Sroberto f = fdopen(fd, "w+"); 302258945Sroberto if (f == NULL) { 303258945Sroberto result = isc__errno2result(errno); 304258945Sroberto if (remove(templet) < 0) { 305258945Sroberto isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, 306258945Sroberto ISC_LOGMODULE_FILE, ISC_LOG_ERROR, 307258945Sroberto "remove '%s': failed", templet); 308258945Sroberto } 309258945Sroberto (void)close(fd); 310258945Sroberto } else 311258945Sroberto *fp = f; 312258945Sroberto 313258945Sroberto return (result); 314258945Sroberto} 315258945Sroberto 316258945Srobertoisc_result_t 317258945Srobertoisc_file_remove(const char *filename) { 318258945Sroberto int r; 319258945Sroberto 320258945Sroberto REQUIRE(filename != NULL); 321258945Sroberto 322258945Sroberto r = unlink(filename); 323258945Sroberto if (r == 0) 324258945Sroberto return (ISC_R_SUCCESS); 325258945Sroberto else 326258945Sroberto return (isc__errno2result(errno)); 327258945Sroberto} 328258945Sroberto 329258945Srobertoisc_result_t 330258945Srobertoisc_file_rename(const char *oldname, const char *newname) { 331258945Sroberto int r; 332258945Sroberto 333258945Sroberto REQUIRE(oldname != NULL); 334258945Sroberto REQUIRE(newname != NULL); 335258945Sroberto 336258945Sroberto r = rename(oldname, newname); 337258945Sroberto if (r == 0) 338258945Sroberto return (ISC_R_SUCCESS); 339258945Sroberto else 340258945Sroberto return (isc__errno2result(errno)); 341258945Sroberto} 342258945Sroberto 343258945Srobertoisc_boolean_t 344258945Srobertoisc_file_exists(const char *pathname) { 345258945Sroberto struct stat stats; 346258945Sroberto 347258945Sroberto REQUIRE(pathname != NULL); 348258945Sroberto 349258945Sroberto return (ISC_TF(file_stats(pathname, &stats) == ISC_R_SUCCESS)); 350258945Sroberto} 351258945Sroberto 352280849Scyisc_result_t 353280849Scyisc_file_isplainfile(const char *filename) { 354280849Scy /* 355280849Scy * This function returns success if filename is a plain file. 356280849Scy */ 357280849Scy struct stat filestat; 358280849Scy memset(&filestat,0,sizeof(struct stat)); 359280849Scy 360280849Scy if ((stat(filename, &filestat)) == -1) 361280849Scy return(isc__errno2result(errno)); 362280849Scy 363280849Scy if(! S_ISREG(filestat.st_mode)) 364280849Scy return(ISC_R_INVALIDFILE); 365280849Scy 366280849Scy return(ISC_R_SUCCESS); 367280849Scy} 368280849Scy 369258945Srobertoisc_boolean_t 370258945Srobertoisc_file_isabsolute(const char *filename) { 371258945Sroberto REQUIRE(filename != NULL); 372258945Sroberto return (ISC_TF(filename[0] == '/')); 373258945Sroberto} 374258945Sroberto 375258945Srobertoisc_boolean_t 376258945Srobertoisc_file_iscurrentdir(const char *filename) { 377258945Sroberto REQUIRE(filename != NULL); 378258945Sroberto return (ISC_TF(filename[0] == '.' && filename[1] == '\0')); 379258945Sroberto} 380258945Sroberto 381258945Srobertoisc_boolean_t 382258945Srobertoisc_file_ischdiridempotent(const char *filename) { 383258945Sroberto REQUIRE(filename != NULL); 384258945Sroberto if (isc_file_isabsolute(filename)) 385258945Sroberto return (ISC_TRUE); 386258945Sroberto if (isc_file_iscurrentdir(filename)) 387258945Sroberto return (ISC_TRUE); 388258945Sroberto return (ISC_FALSE); 389258945Sroberto} 390258945Sroberto 391258945Srobertoconst char * 392258945Srobertoisc_file_basename(const char *filename) { 393258945Sroberto char *s; 394258945Sroberto 395258945Sroberto REQUIRE(filename != NULL); 396258945Sroberto 397258945Sroberto s = strrchr(filename, '/'); 398258945Sroberto if (s == NULL) 399258945Sroberto return (filename); 400258945Sroberto 401258945Sroberto return (s + 1); 402258945Sroberto} 403258945Sroberto 404258945Srobertoisc_result_t 405258945Srobertoisc_file_progname(const char *filename, char *buf, size_t buflen) { 406258945Sroberto const char *base; 407258945Sroberto size_t len; 408258945Sroberto 409258945Sroberto REQUIRE(filename != NULL); 410258945Sroberto REQUIRE(buf != NULL); 411258945Sroberto 412258945Sroberto base = isc_file_basename(filename); 413258945Sroberto len = strlen(base) + 1; 414258945Sroberto 415258945Sroberto if (len > buflen) 416258945Sroberto return (ISC_R_NOSPACE); 417258945Sroberto memcpy(buf, base, len); 418258945Sroberto 419258945Sroberto return (ISC_R_SUCCESS); 420258945Sroberto} 421258945Sroberto 422258945Sroberto/* 423258945Sroberto * Put the absolute name of the current directory into 'dirname', which is 424258945Sroberto * a buffer of at least 'length' characters. End the string with the 425258945Sroberto * appropriate path separator, such that the final product could be 426258945Sroberto * concatenated with a relative pathname to make a valid pathname string. 427258945Sroberto */ 428258945Srobertostatic isc_result_t 429258945Srobertodir_current(char *dirname, size_t length) { 430258945Sroberto char *cwd; 431258945Sroberto isc_result_t result = ISC_R_SUCCESS; 432258945Sroberto 433258945Sroberto REQUIRE(dirname != NULL); 434258945Sroberto REQUIRE(length > 0U); 435258945Sroberto 436258945Sroberto cwd = getcwd(dirname, length); 437258945Sroberto 438258945Sroberto if (cwd == NULL) { 439258945Sroberto if (errno == ERANGE) 440258945Sroberto result = ISC_R_NOSPACE; 441258945Sroberto else 442258945Sroberto result = isc__errno2result(errno); 443258945Sroberto } else { 444258945Sroberto if (strlen(dirname) + 1 == length) 445258945Sroberto result = ISC_R_NOSPACE; 446258945Sroberto else if (dirname[1] != '\0') 447280849Scy strlcat(dirname, "/", length); 448258945Sroberto } 449258945Sroberto 450258945Sroberto return (result); 451258945Sroberto} 452258945Sroberto 453258945Srobertoisc_result_t 454258945Srobertoisc_file_absolutepath(const char *filename, char *path, size_t pathlen) { 455258945Sroberto isc_result_t result; 456258945Sroberto result = dir_current(path, pathlen); 457258945Sroberto if (result != ISC_R_SUCCESS) 458258945Sroberto return (result); 459258945Sroberto if (strlen(path) + strlen(filename) + 1 > pathlen) 460258945Sroberto return (ISC_R_NOSPACE); 461280849Scy strlcat(path, filename, pathlen); 462258945Sroberto return (ISC_R_SUCCESS); 463258945Sroberto} 464258945Sroberto 465258945Srobertoisc_result_t 466258945Srobertoisc_file_truncate(const char *filename, isc_offset_t size) { 467258945Sroberto isc_result_t result = ISC_R_SUCCESS; 468258945Sroberto 469258945Sroberto if (truncate(filename, size) < 0) 470258945Sroberto result = isc__errno2result(errno); 471258945Sroberto return (result); 472258945Sroberto} 473280849Scy 474280849Scyisc_result_t 475280849Scyisc_file_safecreate(const char *filename, FILE **fp) { 476280849Scy isc_result_t result; 477280849Scy int flags; 478280849Scy struct stat sb; 479280849Scy FILE *f; 480280849Scy int fd; 481280849Scy 482280849Scy REQUIRE(filename != NULL); 483280849Scy REQUIRE(fp != NULL && *fp == NULL); 484280849Scy 485280849Scy result = file_stats(filename, &sb); 486280849Scy if (result == ISC_R_SUCCESS) { 487280849Scy if ((sb.st_mode & S_IFREG) == 0) 488280849Scy return (ISC_R_INVALIDFILE); 489280849Scy flags = O_WRONLY | O_TRUNC; 490280849Scy } else if (result == ISC_R_FILENOTFOUND) { 491280849Scy flags = O_WRONLY | O_CREAT | O_EXCL; 492280849Scy } else 493280849Scy return (result); 494280849Scy 495280849Scy fd = open(filename, flags, S_IRUSR | S_IWUSR); 496280849Scy if (fd == -1) 497280849Scy return (isc__errno2result(errno)); 498280849Scy 499280849Scy f = fdopen(fd, "w"); 500280849Scy if (f == NULL) { 501280849Scy result = isc__errno2result(errno); 502280849Scy close(fd); 503280849Scy return (result); 504280849Scy } 505280849Scy 506280849Scy *fp = f; 507280849Scy return (ISC_R_SUCCESS); 508280849Scy} 509280849Scy 510280849Scyisc_result_t 511285612Sdelphijisc_file_splitpath(isc_mem_t *mctx, char *path, char **dirnam, char **basenam) 512280849Scy{ 513280849Scy char *dir, *file, *slash; 514280849Scy 515280849Scy REQUIRE(path != NULL); 516280849Scy 517280849Scy slash = strrchr(path, '/'); 518280849Scy 519280849Scy if (slash == path) { 520280849Scy file = ++slash; 521280849Scy dir = isc_mem_strdup(mctx, "/"); 522280849Scy } else if (slash != NULL) { 523280849Scy file = ++slash; 524280849Scy dir = isc_mem_allocate(mctx, slash - path); 525280849Scy if (dir != NULL) 526280849Scy strlcpy(dir, path, slash - path); 527280849Scy } else { 528280849Scy file = path; 529280849Scy dir = isc_mem_strdup(mctx, "."); 530280849Scy } 531280849Scy 532280849Scy if (dir == NULL) 533280849Scy return (ISC_R_NOMEMORY); 534280849Scy 535280849Scy if (*file == '\0') { 536280849Scy isc_mem_free(mctx, dir); 537280849Scy return (ISC_R_INVALIDFILE); 538280849Scy } 539280849Scy 540285612Sdelphij *dirnam = dir; 541285612Sdelphij *basenam = file; 542280849Scy 543280849Scy return (ISC_R_SUCCESS); 544280849Scy} 545