1*eabc0478Schristos /* $NetBSD: dir.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) 1999-2001 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 /* Id */ 21897be3a4Schristos 22897be3a4Schristos /*! \file 23897be3a4Schristos * \author Principal Authors: DCL */ 24897be3a4Schristos 25897be3a4Schristos #include <config.h> 26897be3a4Schristos 27897be3a4Schristos #include <sys/types.h> 28897be3a4Schristos #include <sys/stat.h> 29897be3a4Schristos 30897be3a4Schristos #include <ctype.h> 31897be3a4Schristos #include <errno.h> 32897be3a4Schristos #include <unistd.h> 33897be3a4Schristos 34897be3a4Schristos #include <isc/dir.h> 35897be3a4Schristos #include <isc/magic.h> 36897be3a4Schristos #include <isc/string.h> 37897be3a4Schristos #include <isc/util.h> 38897be3a4Schristos 39897be3a4Schristos #include "errno2result.h" 40897be3a4Schristos #include "ntp_stdlib.h" /* NTP change for strlcpy, strlcat */ 41897be3a4Schristos 42897be3a4Schristos #define ISC_DIR_MAGIC ISC_MAGIC('D', 'I', 'R', '*') 43897be3a4Schristos #define VALID_DIR(dir) ISC_MAGIC_VALID(dir, ISC_DIR_MAGIC) 44897be3a4Schristos 45897be3a4Schristos void 46897be3a4Schristos isc_dir_init(isc_dir_t *dir) { 47897be3a4Schristos REQUIRE(dir != NULL); 48897be3a4Schristos 49897be3a4Schristos dir->entry.name[0] = '\0'; 50897be3a4Schristos dir->entry.length = 0; 51897be3a4Schristos 52897be3a4Schristos dir->handle = NULL; 53897be3a4Schristos 54897be3a4Schristos dir->magic = ISC_DIR_MAGIC; 55897be3a4Schristos } 56897be3a4Schristos 57897be3a4Schristos /*! 58897be3a4Schristos * \brief Allocate workspace and open directory stream. If either one fails, 59897be3a4Schristos * NULL will be returned. 60897be3a4Schristos */ 61897be3a4Schristos isc_result_t 62897be3a4Schristos isc_dir_open(isc_dir_t *dir, const char *dirname) { 63897be3a4Schristos char *p; 64897be3a4Schristos size_t octets; 65897be3a4Schristos isc_result_t result = ISC_R_SUCCESS; 66897be3a4Schristos 67897be3a4Schristos REQUIRE(VALID_DIR(dir)); 68897be3a4Schristos REQUIRE(dirname != NULL); 69897be3a4Schristos 70897be3a4Schristos /* 71897be3a4Schristos * Copy directory name. Need to have enough space for the name, 72897be3a4Schristos * a possible path separator, the wildcard, and the final NUL. 73897be3a4Schristos */ 74897be3a4Schristos octets = strlen(dirname) + 1; 75897be3a4Schristos if (octets + 2 > sizeof(dir->dirname)) 76897be3a4Schristos /* XXXDCL ? */ 77897be3a4Schristos return (ISC_R_NOSPACE); 78897be3a4Schristos strlcpy(dir->dirname, dirname, octets); 79897be3a4Schristos 80897be3a4Schristos /* 81897be3a4Schristos * Append path separator, if needed, and "*". 82897be3a4Schristos */ 83897be3a4Schristos p = dir->dirname + strlen(dir->dirname); 84897be3a4Schristos if (dir->dirname < p && *(p - 1) != '/') 85897be3a4Schristos *p++ = '/'; 86897be3a4Schristos *p++ = '*'; 87897be3a4Schristos *p = '\0'; 88897be3a4Schristos 89897be3a4Schristos /* 90897be3a4Schristos * Open stream. 91897be3a4Schristos */ 92897be3a4Schristos dir->handle = opendir(dirname); 93897be3a4Schristos 94897be3a4Schristos if (dir->handle == NULL) 95897be3a4Schristos return isc__errno2result(errno); 96897be3a4Schristos 97897be3a4Schristos return (result); 98897be3a4Schristos } 99897be3a4Schristos 100897be3a4Schristos /*! 101897be3a4Schristos * \brief Return previously retrieved file or get next one. 102897be3a4Schristos 103897be3a4Schristos * Unix's dirent has 104897be3a4Schristos * separate open and read functions, but the Win32 and DOS interfaces open 105897be3a4Schristos * the dir stream and reads the first file in one operation. 106897be3a4Schristos */ 107897be3a4Schristos isc_result_t 108897be3a4Schristos isc_dir_read(isc_dir_t *dir) { 109897be3a4Schristos struct dirent *entry; 110897be3a4Schristos size_t octets; 111897be3a4Schristos 112897be3a4Schristos REQUIRE(VALID_DIR(dir) && dir->handle != NULL); 113897be3a4Schristos 114897be3a4Schristos /* 115897be3a4Schristos * Fetch next file in directory. 116897be3a4Schristos */ 117897be3a4Schristos entry = readdir(dir->handle); 118897be3a4Schristos 119897be3a4Schristos if (entry == NULL) 120897be3a4Schristos return (ISC_R_NOMORE); 121897be3a4Schristos 122897be3a4Schristos /* 123897be3a4Schristos * Make sure that the space for the name is long enough. 124897be3a4Schristos */ 125897be3a4Schristos octets = strlen(entry->d_name) + 1; 126897be3a4Schristos if (sizeof(dir->entry.name) < octets) 127897be3a4Schristos return (ISC_R_UNEXPECTED); 128897be3a4Schristos 129897be3a4Schristos strlcpy(dir->entry.name, entry->d_name, octets); 130897be3a4Schristos 131897be3a4Schristos /* 132897be3a4Schristos * Some dirents have d_namlen, but it is not portable. 133897be3a4Schristos */ 134897be3a4Schristos dir->entry.length = strlen(entry->d_name); 135897be3a4Schristos 136897be3a4Schristos return (ISC_R_SUCCESS); 137897be3a4Schristos } 138897be3a4Schristos 139897be3a4Schristos /*! 140897be3a4Schristos * \brief Close directory stream. 141897be3a4Schristos */ 142897be3a4Schristos void 143897be3a4Schristos isc_dir_close(isc_dir_t *dir) { 144897be3a4Schristos REQUIRE(VALID_DIR(dir) && dir->handle != NULL); 145897be3a4Schristos 146897be3a4Schristos (void)closedir(dir->handle); 147897be3a4Schristos dir->handle = NULL; 148897be3a4Schristos } 149897be3a4Schristos 150897be3a4Schristos /*! 151897be3a4Schristos * \brief Reposition directory stream at start. 152897be3a4Schristos */ 153897be3a4Schristos isc_result_t 154897be3a4Schristos isc_dir_reset(isc_dir_t *dir) { 155897be3a4Schristos REQUIRE(VALID_DIR(dir) && dir->handle != NULL); 156897be3a4Schristos 157897be3a4Schristos rewinddir(dir->handle); 158897be3a4Schristos 159897be3a4Schristos return (ISC_R_SUCCESS); 160897be3a4Schristos } 161897be3a4Schristos 162897be3a4Schristos isc_result_t 163897be3a4Schristos isc_dir_chdir(const char *dirname) { 164897be3a4Schristos /*! 165897be3a4Schristos * \brief Change the current directory to 'dirname'. 166897be3a4Schristos */ 167897be3a4Schristos 168897be3a4Schristos REQUIRE(dirname != NULL); 169897be3a4Schristos 170897be3a4Schristos if (chdir(dirname) < 0) 171897be3a4Schristos return (isc__errno2result(errno)); 172897be3a4Schristos 173897be3a4Schristos return (ISC_R_SUCCESS); 174897be3a4Schristos } 175897be3a4Schristos 176897be3a4Schristos isc_result_t 177897be3a4Schristos isc_dir_chroot(const char *dirname) { 178897be3a4Schristos 179897be3a4Schristos REQUIRE(dirname != NULL); 180897be3a4Schristos 181897be3a4Schristos #ifdef HAVE_CHROOT 182897be3a4Schristos if (chroot(dirname) < 0 || chdir("/") < 0) 183897be3a4Schristos return (isc__errno2result(errno)); 184897be3a4Schristos 185897be3a4Schristos return (ISC_R_SUCCESS); 186897be3a4Schristos #else 187897be3a4Schristos return (ISC_R_NOTIMPLEMENTED); 188897be3a4Schristos #endif 189897be3a4Schristos } 190897be3a4Schristos 191897be3a4Schristos isc_result_t 192897be3a4Schristos isc_dir_createunique(char *templet) { 193897be3a4Schristos isc_result_t result; 194897be3a4Schristos char *x; 195897be3a4Schristos char *p; 196897be3a4Schristos int i; 197897be3a4Schristos int pid; 198897be3a4Schristos 199897be3a4Schristos REQUIRE(templet != NULL); 200897be3a4Schristos 201897be3a4Schristos /*! 202897be3a4Schristos * \brief mkdtemp is not portable, so this emulates it. 203897be3a4Schristos */ 204897be3a4Schristos 205897be3a4Schristos pid = getpid(); 206897be3a4Schristos 207897be3a4Schristos /* 208897be3a4Schristos * Replace trailing Xs with the process-id, zero-filled. 209897be3a4Schristos */ 210897be3a4Schristos for (x = templet + strlen(templet) - 1; *x == 'X' && x >= templet; 211897be3a4Schristos x--, pid /= 10) 212897be3a4Schristos *x = pid % 10 + '0'; 213897be3a4Schristos 214897be3a4Schristos x++; /* Set x to start of ex-Xs. */ 215897be3a4Schristos 216897be3a4Schristos do { 217897be3a4Schristos i = mkdir(templet, 0700); 218897be3a4Schristos if (i == 0 || errno != EEXIST) 219897be3a4Schristos break; 220897be3a4Schristos 221897be3a4Schristos /* 222897be3a4Schristos * The BSD algorithm. 223897be3a4Schristos */ 224897be3a4Schristos p = x; 225897be3a4Schristos while (*p != '\0') { 226897be3a4Schristos if (isdigit(*p & 0xff)) 227897be3a4Schristos *p = 'a'; 228897be3a4Schristos else if (*p != 'z') 229897be3a4Schristos ++*p; 230897be3a4Schristos else { 231897be3a4Schristos /* 232897be3a4Schristos * Reset character and move to next. 233897be3a4Schristos */ 234897be3a4Schristos *p++ = 'a'; 235897be3a4Schristos continue; 236897be3a4Schristos } 237897be3a4Schristos 238897be3a4Schristos break; 239897be3a4Schristos } 240897be3a4Schristos 241897be3a4Schristos if (*p == '\0') { 242897be3a4Schristos /* 243897be3a4Schristos * Tried all combinations. errno should already 244897be3a4Schristos * be EEXIST, but ensure it is anyway for 245897be3a4Schristos * isc__errno2result(). 246897be3a4Schristos */ 247897be3a4Schristos errno = EEXIST; 248897be3a4Schristos break; 249897be3a4Schristos } 250897be3a4Schristos } while (1); 251897be3a4Schristos 252897be3a4Schristos if (i == -1) 253897be3a4Schristos result = isc__errno2result(errno); 254897be3a4Schristos else 255897be3a4Schristos result = ISC_R_SUCCESS; 256897be3a4Schristos 257897be3a4Schristos return (result); 258897be3a4Schristos } 259