1258945Sroberto/* 2280849Scy * Copyright (C) 2004, 2005, 2007-2009, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") 3258945Sroberto * Copyright (C) 1999-2001 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/*! \file 21258945Sroberto * \author Principal Authors: DCL */ 22258945Sroberto 23258945Sroberto#include <config.h> 24258945Sroberto 25258945Sroberto#include <sys/types.h> 26258945Sroberto#include <sys/stat.h> 27258945Sroberto 28258945Sroberto#include <ctype.h> 29258945Sroberto#include <errno.h> 30258945Sroberto#include <unistd.h> 31258945Sroberto 32258945Sroberto#include <isc/dir.h> 33258945Sroberto#include <isc/magic.h> 34258945Sroberto#include <isc/string.h> 35258945Sroberto#include <isc/util.h> 36258945Sroberto 37258945Sroberto#include "errno2result.h" 38280849Scy#include "ntp_stdlib.h" /* NTP change for strlcpy, strlcat */ 39258945Sroberto 40258945Sroberto#define ISC_DIR_MAGIC ISC_MAGIC('D', 'I', 'R', '*') 41258945Sroberto#define VALID_DIR(dir) ISC_MAGIC_VALID(dir, ISC_DIR_MAGIC) 42258945Sroberto 43258945Srobertovoid 44258945Srobertoisc_dir_init(isc_dir_t *dir) { 45258945Sroberto REQUIRE(dir != NULL); 46258945Sroberto 47258945Sroberto dir->entry.name[0] = '\0'; 48258945Sroberto dir->entry.length = 0; 49258945Sroberto 50258945Sroberto dir->handle = NULL; 51258945Sroberto 52258945Sroberto dir->magic = ISC_DIR_MAGIC; 53258945Sroberto} 54258945Sroberto 55258945Sroberto/*! 56258945Sroberto * \brief Allocate workspace and open directory stream. If either one fails, 57258945Sroberto * NULL will be returned. 58258945Sroberto */ 59258945Srobertoisc_result_t 60258945Srobertoisc_dir_open(isc_dir_t *dir, const char *dirname) { 61258945Sroberto char *p; 62280849Scy size_t octets; 63258945Sroberto isc_result_t result = ISC_R_SUCCESS; 64258945Sroberto 65258945Sroberto REQUIRE(VALID_DIR(dir)); 66258945Sroberto REQUIRE(dirname != NULL); 67258945Sroberto 68258945Sroberto /* 69258945Sroberto * Copy directory name. Need to have enough space for the name, 70258945Sroberto * a possible path separator, the wildcard, and the final NUL. 71258945Sroberto */ 72280849Scy octets = strlen(dirname) + 1; 73280849Scy if (octets + 2 > sizeof(dir->dirname)) 74258945Sroberto /* XXXDCL ? */ 75258945Sroberto return (ISC_R_NOSPACE); 76280849Scy strlcpy(dir->dirname, dirname, octets); 77258945Sroberto 78258945Sroberto /* 79258945Sroberto * Append path separator, if needed, and "*". 80258945Sroberto */ 81258945Sroberto p = dir->dirname + strlen(dir->dirname); 82258945Sroberto if (dir->dirname < p && *(p - 1) != '/') 83258945Sroberto *p++ = '/'; 84258945Sroberto *p++ = '*'; 85280849Scy *p = '\0'; 86258945Sroberto 87258945Sroberto /* 88258945Sroberto * Open stream. 89258945Sroberto */ 90258945Sroberto dir->handle = opendir(dirname); 91258945Sroberto 92258945Sroberto if (dir->handle == NULL) 93258945Sroberto return isc__errno2result(errno); 94258945Sroberto 95258945Sroberto return (result); 96258945Sroberto} 97258945Sroberto 98258945Sroberto/*! 99258945Sroberto * \brief Return previously retrieved file or get next one. 100258945Sroberto 101258945Sroberto * Unix's dirent has 102258945Sroberto * separate open and read functions, but the Win32 and DOS interfaces open 103258945Sroberto * the dir stream and reads the first file in one operation. 104258945Sroberto */ 105258945Srobertoisc_result_t 106258945Srobertoisc_dir_read(isc_dir_t *dir) { 107258945Sroberto struct dirent *entry; 108280849Scy size_t octets; 109258945Sroberto 110258945Sroberto REQUIRE(VALID_DIR(dir) && dir->handle != NULL); 111258945Sroberto 112258945Sroberto /* 113258945Sroberto * Fetch next file in directory. 114258945Sroberto */ 115258945Sroberto entry = readdir(dir->handle); 116258945Sroberto 117258945Sroberto if (entry == NULL) 118258945Sroberto return (ISC_R_NOMORE); 119258945Sroberto 120258945Sroberto /* 121258945Sroberto * Make sure that the space for the name is long enough. 122258945Sroberto */ 123280849Scy octets = strlen(entry->d_name) + 1; 124280849Scy if (sizeof(dir->entry.name) < octets) 125280849Scy return (ISC_R_UNEXPECTED); 126258945Sroberto 127280849Scy strlcpy(dir->entry.name, entry->d_name, octets); 128258945Sroberto 129258945Sroberto /* 130258945Sroberto * Some dirents have d_namlen, but it is not portable. 131258945Sroberto */ 132258945Sroberto dir->entry.length = strlen(entry->d_name); 133258945Sroberto 134258945Sroberto return (ISC_R_SUCCESS); 135258945Sroberto} 136258945Sroberto 137258945Sroberto/*! 138258945Sroberto * \brief Close directory stream. 139258945Sroberto */ 140258945Srobertovoid 141258945Srobertoisc_dir_close(isc_dir_t *dir) { 142258945Sroberto REQUIRE(VALID_DIR(dir) && dir->handle != NULL); 143258945Sroberto 144258945Sroberto (void)closedir(dir->handle); 145258945Sroberto dir->handle = NULL; 146258945Sroberto} 147258945Sroberto 148258945Sroberto/*! 149258945Sroberto * \brief Reposition directory stream at start. 150258945Sroberto */ 151258945Srobertoisc_result_t 152258945Srobertoisc_dir_reset(isc_dir_t *dir) { 153258945Sroberto REQUIRE(VALID_DIR(dir) && dir->handle != NULL); 154258945Sroberto 155258945Sroberto rewinddir(dir->handle); 156258945Sroberto 157258945Sroberto return (ISC_R_SUCCESS); 158258945Sroberto} 159258945Sroberto 160258945Srobertoisc_result_t 161258945Srobertoisc_dir_chdir(const char *dirname) { 162258945Sroberto /*! 163258945Sroberto * \brief Change the current directory to 'dirname'. 164258945Sroberto */ 165258945Sroberto 166258945Sroberto REQUIRE(dirname != NULL); 167258945Sroberto 168258945Sroberto if (chdir(dirname) < 0) 169258945Sroberto return (isc__errno2result(errno)); 170258945Sroberto 171258945Sroberto return (ISC_R_SUCCESS); 172258945Sroberto} 173258945Sroberto 174258945Srobertoisc_result_t 175258945Srobertoisc_dir_chroot(const char *dirname) { 176258945Sroberto 177258945Sroberto REQUIRE(dirname != NULL); 178258945Sroberto 179258945Sroberto#ifdef HAVE_CHROOT 180258945Sroberto if (chroot(dirname) < 0 || chdir("/") < 0) 181258945Sroberto return (isc__errno2result(errno)); 182258945Sroberto 183258945Sroberto return (ISC_R_SUCCESS); 184258945Sroberto#else 185258945Sroberto return (ISC_R_NOTIMPLEMENTED); 186258945Sroberto#endif 187258945Sroberto} 188258945Sroberto 189258945Srobertoisc_result_t 190258945Srobertoisc_dir_createunique(char *templet) { 191258945Sroberto isc_result_t result; 192258945Sroberto char *x; 193258945Sroberto char *p; 194258945Sroberto int i; 195258945Sroberto int pid; 196258945Sroberto 197258945Sroberto REQUIRE(templet != NULL); 198258945Sroberto 199258945Sroberto /*! 200258945Sroberto * \brief mkdtemp is not portable, so this emulates it. 201258945Sroberto */ 202258945Sroberto 203258945Sroberto pid = getpid(); 204258945Sroberto 205258945Sroberto /* 206258945Sroberto * Replace trailing Xs with the process-id, zero-filled. 207258945Sroberto */ 208258945Sroberto for (x = templet + strlen(templet) - 1; *x == 'X' && x >= templet; 209258945Sroberto x--, pid /= 10) 210258945Sroberto *x = pid % 10 + '0'; 211258945Sroberto 212258945Sroberto x++; /* Set x to start of ex-Xs. */ 213258945Sroberto 214258945Sroberto do { 215258945Sroberto i = mkdir(templet, 0700); 216258945Sroberto if (i == 0 || errno != EEXIST) 217258945Sroberto break; 218258945Sroberto 219258945Sroberto /* 220258945Sroberto * The BSD algorithm. 221258945Sroberto */ 222258945Sroberto p = x; 223258945Sroberto while (*p != '\0') { 224258945Sroberto if (isdigit(*p & 0xff)) 225258945Sroberto *p = 'a'; 226258945Sroberto else if (*p != 'z') 227258945Sroberto ++*p; 228258945Sroberto else { 229258945Sroberto /* 230258945Sroberto * Reset character and move to next. 231258945Sroberto */ 232258945Sroberto *p++ = 'a'; 233258945Sroberto continue; 234258945Sroberto } 235258945Sroberto 236258945Sroberto break; 237258945Sroberto } 238258945Sroberto 239258945Sroberto if (*p == '\0') { 240258945Sroberto /* 241258945Sroberto * Tried all combinations. errno should already 242258945Sroberto * be EEXIST, but ensure it is anyway for 243258945Sroberto * isc__errno2result(). 244258945Sroberto */ 245258945Sroberto errno = EEXIST; 246258945Sroberto break; 247258945Sroberto } 248258945Sroberto } while (1); 249258945Sroberto 250258945Sroberto if (i == -1) 251258945Sroberto result = isc__errno2result(errno); 252258945Sroberto else 253258945Sroberto result = ISC_R_SUCCESS; 254258945Sroberto 255258945Sroberto return (result); 256258945Sroberto} 257