1258945Sroberto/* 2280849Scy * Copyright (C) 2004, 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 18280849Scy/* $Id$ */ 19258945Sroberto 20258945Sroberto#include <config.h> 21258945Sroberto 22258945Sroberto#undef rename 23258945Sroberto#include <errno.h> 24258945Sroberto#include <limits.h> 25258945Sroberto#include <stdlib.h> 26258945Sroberto#include <io.h> 27258945Sroberto#include <process.h> 28258945Sroberto 29258945Sroberto#include <sys/stat.h> 30258945Sroberto#include <fcntl.h> 31258945Sroberto#include <sys/utime.h> 32258945Sroberto 33258945Sroberto#include <isc/file.h> 34280849Scy#include <isc/mem.h> 35258945Sroberto#include <isc/result.h> 36258945Sroberto#include <isc/time.h> 37258945Sroberto#include <isc/util.h> 38258945Sroberto#include <isc/stat.h> 39280849Scy#include <isc/string.h> 40258945Sroberto 41258945Sroberto#include "errno2result.h" 42258945Sroberto 43258945Sroberto/* 44258945Sroberto * Emulate UNIX mkstemp, which returns an open FD to the new file 45258945Sroberto * 46258945Sroberto */ 47258945Srobertostatic int 48258945Srobertogettemp(char *path, int *doopen) { 49258945Sroberto char *start, *trv; 50258945Sroberto struct stat sbuf; 51258945Sroberto int pid; 52258945Sroberto 53258945Sroberto trv = strrchr(path, 'X'); 54258945Sroberto trv++; 55258945Sroberto pid = getpid(); 56258945Sroberto /* extra X's get set to 0's */ 57258945Sroberto while (*--trv == 'X') { 58258945Sroberto *trv = (pid % 10) + '0'; 59258945Sroberto pid /= 10; 60258945Sroberto } 61258945Sroberto /* 62258945Sroberto * check the target directory; if you have six X's and it 63258945Sroberto * doesn't exist this runs for a *very* long time. 64258945Sroberto */ 65258945Sroberto for (start = trv + 1;; --trv) { 66258945Sroberto if (trv <= path) 67258945Sroberto break; 68258945Sroberto if (*trv == '\\') { 69258945Sroberto *trv = '\0'; 70258945Sroberto if (stat(path, &sbuf)) 71258945Sroberto return (0); 72258945Sroberto if (!S_ISDIR(sbuf.st_mode)) { 73258945Sroberto errno = ENOTDIR; 74258945Sroberto return (0); 75258945Sroberto } 76258945Sroberto *trv = '\\'; 77258945Sroberto break; 78258945Sroberto } 79258945Sroberto } 80258945Sroberto 81258945Sroberto for (;;) { 82258945Sroberto if (doopen) { 83258945Sroberto if ((*doopen = 84258945Sroberto open(path, O_CREAT|O_EXCL|O_RDWR, 85258945Sroberto _S_IREAD | _S_IWRITE)) >= 0) 86258945Sroberto return (1); 87258945Sroberto if (errno != EEXIST) 88258945Sroberto return (0); 89258945Sroberto } else if (stat(path, &sbuf)) 90258945Sroberto return (errno == ENOENT ? 1 : 0); 91258945Sroberto 92258945Sroberto /* tricky little algorithm for backward compatibility */ 93258945Sroberto for (trv = start;;) { 94258945Sroberto if (!*trv) 95258945Sroberto return (0); 96258945Sroberto if (*trv == 'z') 97258945Sroberto *trv++ = 'a'; 98258945Sroberto else { 99258945Sroberto if (isdigit(*trv)) 100258945Sroberto *trv = 'a'; 101258945Sroberto else 102258945Sroberto ++*trv; 103258945Sroberto break; 104258945Sroberto } 105258945Sroberto } 106258945Sroberto } 107258945Sroberto /*NOTREACHED*/ 108258945Sroberto} 109258945Sroberto 110258945Srobertostatic int 111258945Srobertomkstemp(char *path) { 112258945Sroberto int fd; 113258945Sroberto 114258945Sroberto return (gettemp(path, &fd) ? fd : -1); 115258945Sroberto} 116258945Sroberto 117258945Sroberto/* 118258945Sroberto * XXXDCL As the API for accessing file statistics undoubtedly gets expanded, 119258945Sroberto * it might be good to provide a mechanism that allows for the results 120258945Sroberto * of a previous stat() to be used again without having to do another stat, 121258945Sroberto * such as perl's mechanism of using "_" in place of a file name to indicate 122258945Sroberto * that the results of the last stat should be used. But then you get into 123258945Sroberto * annoying MP issues. BTW, Win32 has stat(). 124258945Sroberto */ 125258945Srobertostatic isc_result_t 126258945Srobertofile_stats(const char *file, struct stat *stats) { 127258945Sroberto isc_result_t result = ISC_R_SUCCESS; 128258945Sroberto 129258945Sroberto REQUIRE(file != NULL); 130258945Sroberto REQUIRE(stats != NULL); 131258945Sroberto 132258945Sroberto if (stat(file, stats) != 0) 133258945Sroberto result = isc__errno2result(errno); 134258945Sroberto 135258945Sroberto return (result); 136258945Sroberto} 137258945Sroberto 138258945Sroberto/* 139258945Sroberto * isc_file_safemovefile is needed to be defined here to ensure that 140258945Sroberto * any file with the new name is renamed to a backup name and then the 141258945Sroberto * rename is done. If all goes well then the backup can be deleted, 142258945Sroberto * otherwise it gets renamed back. 143258945Sroberto */ 144258945Sroberto 145258945Srobertoint 146258945Srobertoisc_file_safemovefile(const char *oldname, const char *newname) { 147258945Sroberto BOOL filestatus; 148258945Sroberto char buf[512]; 149258945Sroberto struct stat sbuf; 150258945Sroberto BOOL exists = FALSE; 151258945Sroberto int tmpfd; 152258945Sroberto 153258945Sroberto /* 154258945Sroberto * Make sure we have something to do 155258945Sroberto */ 156258945Sroberto if (stat(oldname, &sbuf) != 0) { 157258945Sroberto errno = ENOENT; 158258945Sroberto return (-1); 159258945Sroberto } 160258945Sroberto 161258945Sroberto /* 162258945Sroberto * Rename to a backup the new file if it still exists 163258945Sroberto */ 164258945Sroberto if (stat(newname, &sbuf) == 0) { 165258945Sroberto exists = TRUE; 166258945Sroberto strcpy(buf, newname); 167258945Sroberto strcat(buf, ".XXXXX"); 168258945Sroberto tmpfd = mkstemp(buf); 169258945Sroberto if (tmpfd > 0) 170258945Sroberto _close(tmpfd); 171258945Sroberto DeleteFile(buf); 172258945Sroberto _chmod(newname, _S_IREAD | _S_IWRITE); 173258945Sroberto 174258945Sroberto filestatus = MoveFile(newname, buf); 175258945Sroberto } 176258945Sroberto /* Now rename the file to the new name 177258945Sroberto */ 178258945Sroberto _chmod(oldname, _S_IREAD | _S_IWRITE); 179258945Sroberto 180258945Sroberto filestatus = MoveFile(oldname, newname); 181258945Sroberto if (filestatus == 0) { 182258945Sroberto /* 183258945Sroberto * Try to rename the backup back to the original name 184258945Sroberto * if the backup got created 185258945Sroberto */ 186258945Sroberto if (exists == TRUE) { 187258945Sroberto filestatus = MoveFile(buf, newname); 188258945Sroberto if (filestatus == 0) 189258945Sroberto errno = EACCES; 190258945Sroberto } 191258945Sroberto return (-1); 192258945Sroberto } 193258945Sroberto 194258945Sroberto /* 195258945Sroberto * Delete the backup file if it got created 196258945Sroberto */ 197258945Sroberto if (exists == TRUE) 198258945Sroberto filestatus = DeleteFile(buf); 199258945Sroberto return (0); 200258945Sroberto} 201258945Sroberto 202258945Srobertoisc_result_t 203258945Srobertoisc_file_getmodtime(const char *file, isc_time_t *time) { 204258945Sroberto int fh; 205258945Sroberto 206258945Sroberto REQUIRE(file != NULL); 207258945Sroberto REQUIRE(time != NULL); 208258945Sroberto 209258945Sroberto if ((fh = open(file, _O_RDONLY | _O_BINARY)) < 0) 210258945Sroberto return (isc__errno2result(errno)); 211258945Sroberto 212258945Sroberto if (!GetFileTime((HANDLE) _get_osfhandle(fh), 213258945Sroberto NULL, 214258945Sroberto NULL, 215258945Sroberto &time->absolute)) 216258945Sroberto { 217258945Sroberto close(fh); 218280849Scy errno = EINVAL; 219280849Scy return (isc__errno2result(errno)); 220280849Scy } 221258945Sroberto close(fh); 222258945Sroberto return (ISC_R_SUCCESS); 223258945Sroberto} 224258945Sroberto 225258945Srobertoisc_result_t 226258945Srobertoisc_file_settime(const char *file, isc_time_t *time) { 227258945Sroberto int fh; 228258945Sroberto 229258945Sroberto REQUIRE(file != NULL && time != NULL); 230258945Sroberto 231258945Sroberto if ((fh = open(file, _O_RDWR | _O_BINARY)) < 0) 232258945Sroberto return (isc__errno2result(errno)); 233258945Sroberto 234280849Scy /* 235258945Sroberto * Set the date via the filedate system call and return. Failing 236280849Scy * this call implies the new file times are not supported by the 237280849Scy * underlying file system. 238280849Scy */ 239258945Sroberto if (!SetFileTime((HANDLE) _get_osfhandle(fh), 240258945Sroberto NULL, 241258945Sroberto &time->absolute, 242258945Sroberto &time->absolute)) 243258945Sroberto { 244258945Sroberto close(fh); 245280849Scy errno = EINVAL; 246280849Scy return (isc__errno2result(errno)); 247280849Scy } 248258945Sroberto 249258945Sroberto close(fh); 250280849Scy return (ISC_R_SUCCESS); 251258945Sroberto 252258945Sroberto} 253258945Sroberto 254258945Sroberto#undef TEMPLATE 255258945Sroberto#define TEMPLATE "XXXXXXXXXX.tmp" /* 14 characters. */ 256258945Sroberto 257258945Srobertoisc_result_t 258258945Srobertoisc_file_mktemplate(const char *path, char *buf, size_t buflen) { 259258945Sroberto return (isc_file_template(path, TEMPLATE, buf, buflen)); 260258945Sroberto} 261258945Sroberto 262258945Srobertoisc_result_t 263258945Srobertoisc_file_template(const char *path, const char *templet, char *buf, 264258945Sroberto size_t buflen) { 265258945Sroberto char *s; 266258945Sroberto 267258945Sroberto REQUIRE(path != NULL); 268258945Sroberto REQUIRE(templet != NULL); 269258945Sroberto REQUIRE(buf != NULL); 270258945Sroberto 271258945Sroberto s = strrchr(templet, '\\'); 272258945Sroberto if (s != NULL) 273258945Sroberto templet = s + 1; 274258945Sroberto 275258945Sroberto s = strrchr(path, '\\'); 276258945Sroberto 277258945Sroberto if (s != NULL) { 278258945Sroberto if ((s - path + 1 + strlen(templet) + 1) > buflen) 279258945Sroberto return (ISC_R_NOSPACE); 280258945Sroberto 281258945Sroberto strncpy(buf, path, s - path + 1); 282258945Sroberto buf[s - path + 1] = '\0'; 283258945Sroberto strcat(buf, templet); 284258945Sroberto } else { 285258945Sroberto if ((strlen(templet) + 1) > buflen) 286258945Sroberto return (ISC_R_NOSPACE); 287258945Sroberto 288258945Sroberto strcpy(buf, templet); 289258945Sroberto } 290258945Sroberto 291258945Sroberto return (ISC_R_SUCCESS); 292258945Sroberto} 293258945Sroberto 294258945Srobertoisc_result_t 295258945Srobertoisc_file_renameunique(const char *file, char *templet) { 296258945Sroberto int fd = -1; 297258945Sroberto int res = 0; 298258945Sroberto isc_result_t result = ISC_R_SUCCESS; 299258945Sroberto 300258945Sroberto REQUIRE(file != NULL); 301258945Sroberto REQUIRE(templet != NULL); 302258945Sroberto 303258945Sroberto fd = mkstemp(templet); 304258945Sroberto if (fd == -1) 305258945Sroberto result = isc__errno2result(errno); 306258945Sroberto else 307258945Sroberto close(fd); 308258945Sroberto 309258945Sroberto if (result == ISC_R_SUCCESS) { 310258945Sroberto res = isc_file_safemovefile(file, templet); 311258945Sroberto if (res != 0) { 312258945Sroberto result = isc__errno2result(errno); 313258945Sroberto (void)unlink(templet); 314258945Sroberto } 315258945Sroberto } 316258945Sroberto return (result); 317258945Sroberto} 318258945Sroberto 319258945Srobertoisc_result_t 320280849Scyisc_file_openuniqueprivate(char *templet, FILE **fp) { 321280849Scy int mode = _S_IREAD | _S_IWRITE; 322280849Scy return (isc_file_openuniquemode(templet, mode, fp)); 323280849Scy} 324280849Scy 325280849Scyisc_result_t 326258945Srobertoisc_file_openunique(char *templet, FILE **fp) { 327280849Scy int mode = _S_IREAD | _S_IWRITE; 328280849Scy return (isc_file_openuniquemode(templet, mode, fp)); 329280849Scy} 330280849Scy 331280849Scyisc_result_t 332280849Scyisc_file_openuniquemode(char *templet, int mode, FILE **fp) { 333258945Sroberto int fd; 334258945Sroberto FILE *f; 335258945Sroberto isc_result_t result = ISC_R_SUCCESS; 336258945Sroberto 337258945Sroberto REQUIRE(templet != NULL); 338258945Sroberto REQUIRE(fp != NULL && *fp == NULL); 339258945Sroberto 340258945Sroberto /* 341258945Sroberto * Win32 does not have mkstemp. Using emulation above. 342258945Sroberto */ 343258945Sroberto fd = mkstemp(templet); 344258945Sroberto 345258945Sroberto if (fd == -1) 346258945Sroberto result = isc__errno2result(errno); 347258945Sroberto if (result == ISC_R_SUCCESS) { 348280849Scy#if 1 349280849Scy UNUSED(mode); 350280849Scy#else 351280849Scy (void)fchmod(fd, mode); 352280849Scy#endif 353258945Sroberto f = fdopen(fd, "w+"); 354258945Sroberto if (f == NULL) { 355258945Sroberto result = isc__errno2result(errno); 356258945Sroberto (void)remove(templet); 357258945Sroberto (void)close(fd); 358258945Sroberto } else 359258945Sroberto *fp = f; 360258945Sroberto } 361258945Sroberto 362258945Sroberto return (result); 363258945Sroberto} 364258945Sroberto 365258945Srobertoisc_result_t 366258945Srobertoisc_file_remove(const char *filename) { 367258945Sroberto int r; 368258945Sroberto 369258945Sroberto REQUIRE(filename != NULL); 370258945Sroberto 371258945Sroberto r = unlink(filename); 372258945Sroberto if (r == 0) 373258945Sroberto return (ISC_R_SUCCESS); 374258945Sroberto else 375258945Sroberto return (isc__errno2result(errno)); 376258945Sroberto} 377258945Sroberto 378258945Srobertoisc_result_t 379258945Srobertoisc_file_rename(const char *oldname, const char *newname) { 380258945Sroberto int r; 381258945Sroberto 382258945Sroberto REQUIRE(oldname != NULL); 383258945Sroberto REQUIRE(newname != NULL); 384258945Sroberto 385258945Sroberto r = isc_file_safemovefile(oldname, newname); 386258945Sroberto if (r == 0) 387258945Sroberto return (ISC_R_SUCCESS); 388258945Sroberto else 389258945Sroberto return (isc__errno2result(errno)); 390258945Sroberto} 391258945Sroberto 392258945Srobertoisc_boolean_t 393258945Srobertoisc_file_exists(const char *pathname) { 394258945Sroberto struct stat stats; 395258945Sroberto 396258945Sroberto REQUIRE(pathname != NULL); 397258945Sroberto 398258945Sroberto return (ISC_TF(file_stats(pathname, &stats) == ISC_R_SUCCESS)); 399258945Sroberto} 400258945Sroberto 401280849Scyisc_result_t 402280849Scyisc_file_isplainfile(const char *filename) { 403280849Scy /* 404280849Scy * This function returns success if filename is a plain file. 405280849Scy */ 406280849Scy struct stat filestat; 407280849Scy memset(&filestat,0,sizeof(struct stat)); 408280849Scy 409280849Scy if ((stat(filename, &filestat)) == -1) 410280849Scy return(isc__errno2result(errno)); 411280849Scy 412280849Scy if(! S_ISREG(filestat.st_mode)) 413280849Scy return(ISC_R_INVALIDFILE); 414280849Scy 415280849Scy return(ISC_R_SUCCESS); 416280849Scy} 417280849Scy 418258945Srobertoisc_boolean_t 419258945Srobertoisc_file_isabsolute(const char *filename) { 420258945Sroberto REQUIRE(filename != NULL); 421258945Sroberto /* 422258945Sroberto * Look for c:\path\... style, c:/path/... or \\computer\shar\path... 423258945Sroberto * the UNC style file specs 424258945Sroberto */ 425258945Sroberto if ((filename[0] == '\\') && (filename[1] == '\\')) 426258945Sroberto return (ISC_TRUE); 427258945Sroberto if (isalpha(filename[0]) && filename[1] == ':' && filename[2] == '\\') 428258945Sroberto return (ISC_TRUE); 429258945Sroberto if (isalpha(filename[0]) && filename[1] == ':' && filename[2] == '/') 430258945Sroberto return (ISC_TRUE); 431258945Sroberto return (ISC_FALSE); 432258945Sroberto} 433258945Sroberto 434258945Srobertoisc_boolean_t 435258945Srobertoisc_file_iscurrentdir(const char *filename) { 436258945Sroberto REQUIRE(filename != NULL); 437258945Sroberto return (ISC_TF(filename[0] == '.' && filename[1] == '\0')); 438258945Sroberto} 439258945Sroberto 440258945Srobertoisc_boolean_t 441258945Srobertoisc_file_ischdiridempotent(const char *filename) { 442258945Sroberto REQUIRE(filename != NULL); 443258945Sroberto 444258945Sroberto if (isc_file_isabsolute(filename)) 445258945Sroberto return (ISC_TRUE); 446258945Sroberto if (filename[0] == '\\') 447258945Sroberto return (ISC_TRUE); 448258945Sroberto if (filename[0] == '/') 449258945Sroberto return (ISC_TRUE); 450258945Sroberto if (isc_file_iscurrentdir(filename)) 451258945Sroberto return (ISC_TRUE); 452258945Sroberto return (ISC_FALSE); 453258945Sroberto} 454258945Sroberto 455258945Srobertoconst char * 456258945Srobertoisc_file_basename(const char *filename) { 457258945Sroberto char *s; 458258945Sroberto 459258945Sroberto REQUIRE(filename != NULL); 460258945Sroberto 461258945Sroberto s = strrchr(filename, '\\'); 462258945Sroberto if (s == NULL) 463258945Sroberto return (filename); 464258945Sroberto return (s + 1); 465258945Sroberto} 466258945Sroberto 467258945Srobertoisc_result_t 468258945Srobertoisc_file_progname(const char *filename, char *progname, size_t namelen) { 469258945Sroberto const char *s; 470258945Sroberto char *p; 471258945Sroberto size_t len; 472258945Sroberto 473258945Sroberto REQUIRE(filename != NULL); 474258945Sroberto REQUIRE(progname != NULL); 475258945Sroberto 476258945Sroberto /* 477258945Sroberto * Strip the path from the name 478258945Sroberto */ 479258945Sroberto s = isc_file_basename(filename); 480258945Sroberto if (s == NULL) { 481258945Sroberto return (ISC_R_NOSPACE); 482258945Sroberto } 483258945Sroberto 484258945Sroberto /* 485258945Sroberto * Strip any and all suffixes 486258945Sroberto */ 487258945Sroberto p = strchr(s, '.'); 488258945Sroberto if (p == NULL) { 489258945Sroberto if (namelen <= strlen(s)) 490258945Sroberto return (ISC_R_NOSPACE); 491258945Sroberto 492258945Sroberto strcpy(progname, s); 493258945Sroberto return (ISC_R_SUCCESS); 494258945Sroberto } 495258945Sroberto 496280849Scy /* 497258945Sroberto * Copy the result to the buffer 498258945Sroberto */ 499258945Sroberto len = p - s; 500258945Sroberto if (len >= namelen) 501258945Sroberto return (ISC_R_NOSPACE); 502258945Sroberto 503258945Sroberto strncpy(progname, s, len); 504258945Sroberto progname[len] = '\0'; 505258945Sroberto return (ISC_R_SUCCESS); 506258945Sroberto} 507258945Sroberto 508258945Srobertoisc_result_t 509258945Srobertoisc_file_absolutepath(const char *filename, char *path, size_t pathlen) { 510258945Sroberto char *ptrname; 511258945Sroberto DWORD retval; 512258945Sroberto 513258945Sroberto REQUIRE(filename != NULL); 514258945Sroberto REQUIRE(path != NULL); 515258945Sroberto 516258945Sroberto retval = GetFullPathName(filename, pathlen, path, &ptrname); 517258945Sroberto 518258945Sroberto /* Something went wrong in getting the path */ 519258945Sroberto if (retval == 0) 520258945Sroberto return (ISC_R_NOTFOUND); 521258945Sroberto /* Caller needs to provide a larger buffer to contain the string */ 522258945Sroberto if (retval >= pathlen) 523258945Sroberto return (ISC_R_NOSPACE); 524258945Sroberto return (ISC_R_SUCCESS); 525258945Sroberto} 526258945Sroberto 527258945Srobertoisc_result_t 528258945Srobertoisc_file_truncate(const char *filename, isc_offset_t size) { 529258945Sroberto int fh; 530258945Sroberto 531258945Sroberto REQUIRE(filename != NULL && size >= 0); 532258945Sroberto 533258945Sroberto if ((fh = open(filename, _O_RDWR | _O_BINARY)) < 0) 534258945Sroberto return (isc__errno2result(errno)); 535258945Sroberto 536258945Sroberto if(_chsize(fh, size) != 0) { 537258945Sroberto close(fh); 538258945Sroberto return (isc__errno2result(errno)); 539258945Sroberto } 540258945Sroberto close(fh); 541258945Sroberto 542258945Sroberto return (ISC_R_SUCCESS); 543258945Sroberto} 544280849Scy 545280849Scyisc_result_t 546280849Scyisc_file_safecreate(const char *filename, FILE **fp) { 547280849Scy isc_result_t result; 548280849Scy int flags; 549280849Scy struct stat sb; 550280849Scy FILE *f; 551280849Scy int fd; 552280849Scy 553280849Scy REQUIRE(filename != NULL); 554280849Scy REQUIRE(fp != NULL && *fp == NULL); 555280849Scy 556280849Scy result = file_stats(filename, &sb); 557280849Scy if (result == ISC_R_SUCCESS) { 558280849Scy if ((sb.st_mode & S_IFREG) == 0) 559280849Scy return (ISC_R_INVALIDFILE); 560280849Scy flags = O_WRONLY | O_TRUNC; 561280849Scy } else if (result == ISC_R_FILENOTFOUND) { 562280849Scy flags = O_WRONLY | O_CREAT | O_EXCL; 563280849Scy } else 564280849Scy return (result); 565280849Scy 566280849Scy fd = open(filename, flags, S_IRUSR | S_IWUSR); 567280849Scy if (fd == -1) 568280849Scy return (isc__errno2result(errno)); 569280849Scy 570280849Scy f = fdopen(fd, "w"); 571280849Scy if (f == NULL) { 572280849Scy result = isc__errno2result(errno); 573280849Scy close(fd); 574280849Scy return (result); 575280849Scy } 576280849Scy 577280849Scy *fp = f; 578280849Scy return (ISC_R_SUCCESS); 579280849Scy} 580280849Scy 581280849Scyisc_result_t 582280849Scyisc_file_splitpath(isc_mem_t *mctx, char *path, char **dirname, char **basename) 583280849Scy{ 584280849Scy char *dir, *file, *slash; 585280849Scy char *backslash; 586280849Scy 587280849Scy slash = strrchr(path, '/'); 588280849Scy 589280849Scy backslash = strrchr(path, '\\'); 590280849Scy if ((slash != NULL && backslash != NULL && backslash > slash) || 591280849Scy (slash == NULL && backslash != NULL)) 592280849Scy slash = backslash; 593280849Scy 594280849Scy if (slash == path) { 595280849Scy file = ++slash; 596280849Scy dir = isc_mem_strdup(mctx, "/"); 597280849Scy } else if (slash != NULL) { 598280849Scy file = ++slash; 599280849Scy dir = isc_mem_allocate(mctx, slash - path); 600280849Scy if (dir != NULL) 601280849Scy strlcpy(dir, path, slash - path); 602280849Scy } else { 603280849Scy file = path; 604280849Scy dir = isc_mem_strdup(mctx, "."); 605280849Scy } 606280849Scy 607280849Scy if (dir == NULL) 608280849Scy return (ISC_R_NOMEMORY); 609280849Scy 610280849Scy if (*file == '\0') { 611280849Scy isc_mem_free(mctx, dir); 612280849Scy return (ISC_R_INVALIDFILE); 613280849Scy } 614280849Scy 615280849Scy *dirname = dir; 616280849Scy *basename = file; 617280849Scy 618280849Scy return (ISC_R_SUCCESS); 619280849Scy} 620