PageRenderTime 11ms CodeModel.GetById 1ms app.highlight 7ms RepoModel.GetById 1ms app.codeStats 0ms

/contrib/bind9/lib/isc/unix/dir.c

https://bitbucket.org/freebsd/freebsd-head/
C | 251 lines | 123 code | 52 blank | 76 comment | 42 complexity | 6e7ab7a4f3fbcc1d84c096ea04b9e0c2 MD5 | raw file
  1/*
  2 * Copyright (C) 2004, 2005, 2007-2009, 2011, 2012  Internet Systems Consortium, Inc. ("ISC")
  3 * Copyright (C) 1999-2001  Internet Software Consortium.
  4 *
  5 * Permission to use, copy, modify, and/or distribute this software for any
  6 * purpose with or without fee is hereby granted, provided that the above
  7 * copyright notice and this permission notice appear in all copies.
  8 *
  9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
 10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
 11 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
 12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
 13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
 14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 15 * PERFORMANCE OF THIS SOFTWARE.
 16 */
 17
 18/* $Id$ */
 19
 20/*! \file
 21 * \author  Principal Authors: DCL */
 22
 23#include <config.h>
 24
 25#include <sys/types.h>
 26#include <sys/stat.h>
 27
 28#include <ctype.h>
 29#include <errno.h>
 30#include <unistd.h>
 31
 32#include <isc/dir.h>
 33#include <isc/magic.h>
 34#include <isc/string.h>
 35#include <isc/util.h>
 36
 37#include "errno2result.h"
 38
 39#define ISC_DIR_MAGIC		ISC_MAGIC('D', 'I', 'R', '*')
 40#define VALID_DIR(dir)		ISC_MAGIC_VALID(dir, ISC_DIR_MAGIC)
 41
 42void
 43isc_dir_init(isc_dir_t *dir) {
 44	REQUIRE(dir != NULL);
 45
 46	dir->entry.name[0] = '\0';
 47	dir->entry.length = 0;
 48
 49	dir->handle = NULL;
 50
 51	dir->magic = ISC_DIR_MAGIC;
 52}
 53
 54/*!
 55 * \brief Allocate workspace and open directory stream. If either one fails,
 56 * NULL will be returned.
 57 */
 58isc_result_t
 59isc_dir_open(isc_dir_t *dir, const char *dirname) {
 60	char *p;
 61	isc_result_t result = ISC_R_SUCCESS;
 62
 63	REQUIRE(VALID_DIR(dir));
 64	REQUIRE(dirname != NULL);
 65
 66	/*
 67	 * Copy directory name.  Need to have enough space for the name,
 68	 * a possible path separator, the wildcard, and the final NUL.
 69	 */
 70	if (strlen(dirname) + 3 > sizeof(dir->dirname))
 71		/* XXXDCL ? */
 72		return (ISC_R_NOSPACE);
 73	strcpy(dir->dirname, dirname);
 74
 75	/*
 76	 * Append path separator, if needed, and "*".
 77	 */
 78	p = dir->dirname + strlen(dir->dirname);
 79	if (dir->dirname < p && *(p - 1) != '/')
 80		*p++ = '/';
 81	*p++ = '*';
 82	*p = '\0';
 83
 84	/*
 85	 * Open stream.
 86	 */
 87	dir->handle = opendir(dirname);
 88
 89	if (dir->handle == NULL)
 90		return isc__errno2result(errno);
 91
 92	return (result);
 93}
 94
 95/*!
 96 * \brief Return previously retrieved file or get next one.
 97
 98 * Unix's dirent has
 99 * separate open and read functions, but the Win32 and DOS interfaces open
100 * the dir stream and reads the first file in one operation.
101 */
102isc_result_t
103isc_dir_read(isc_dir_t *dir) {
104	struct dirent *entry;
105
106	REQUIRE(VALID_DIR(dir) && dir->handle != NULL);
107
108	/*
109	 * Fetch next file in directory.
110	 */
111	entry = readdir(dir->handle);
112
113	if (entry == NULL)
114		return (ISC_R_NOMORE);
115
116	/*
117	 * Make sure that the space for the name is long enough.
118	 */
119	if (sizeof(dir->entry.name) <= strlen(entry->d_name))
120	    return (ISC_R_UNEXPECTED);
121
122	strcpy(dir->entry.name, entry->d_name);
123
124	/*
125	 * Some dirents have d_namlen, but it is not portable.
126	 */
127	dir->entry.length = strlen(entry->d_name);
128
129	return (ISC_R_SUCCESS);
130}
131
132/*!
133 * \brief Close directory stream.
134 */
135void
136isc_dir_close(isc_dir_t *dir) {
137       REQUIRE(VALID_DIR(dir) && dir->handle != NULL);
138
139       (void)closedir(dir->handle);
140       dir->handle = NULL;
141}
142
143/*!
144 * \brief Reposition directory stream at start.
145 */
146isc_result_t
147isc_dir_reset(isc_dir_t *dir) {
148	REQUIRE(VALID_DIR(dir) && dir->handle != NULL);
149
150	rewinddir(dir->handle);
151
152	return (ISC_R_SUCCESS);
153}
154
155isc_result_t
156isc_dir_chdir(const char *dirname) {
157	/*!
158	 * \brief Change the current directory to 'dirname'.
159	 */
160
161	REQUIRE(dirname != NULL);
162
163	if (chdir(dirname) < 0)
164		return (isc__errno2result(errno));
165
166	return (ISC_R_SUCCESS);
167}
168
169isc_result_t
170isc_dir_chroot(const char *dirname) {
171
172	REQUIRE(dirname != NULL);
173
174#ifdef HAVE_CHROOT
175	if (chroot(dirname) < 0 || chdir("/") < 0)
176		return (isc__errno2result(errno));
177
178	return (ISC_R_SUCCESS);
179#else
180	return (ISC_R_NOTIMPLEMENTED);
181#endif
182}
183
184isc_result_t
185isc_dir_createunique(char *templet) {
186	isc_result_t result;
187	char *x;
188	char *p;
189	int i;
190	int pid;
191
192	REQUIRE(templet != NULL);
193
194	/*!
195	 * \brief mkdtemp is not portable, so this emulates it.
196	 */
197
198	pid = getpid();
199
200	/*
201	 * Replace trailing Xs with the process-id, zero-filled.
202	 */
203	for (x = templet + strlen(templet) - 1; *x == 'X' && x >= templet;
204	     x--, pid /= 10)
205		*x = pid % 10 + '0';
206
207	x++;			/* Set x to start of ex-Xs. */
208
209	do {
210		i = mkdir(templet, 0700);
211		if (i == 0 || errno != EEXIST)
212			break;
213
214		/*
215		 * The BSD algorithm.
216		 */
217		p = x;
218		while (*p != '\0') {
219			if (isdigit(*p & 0xff))
220				*p = 'a';
221			else if (*p != 'z')
222				++*p;
223			else {
224				/*
225				 * Reset character and move to next.
226				 */
227				*p++ = 'a';
228				continue;
229			}
230
231			break;
232		}
233
234		if (*p == '\0') {
235			/*
236			 * Tried all combinations.  errno should already
237			 * be EEXIST, but ensure it is anyway for
238			 * isc__errno2result().
239			 */
240			errno = EEXIST;
241			break;
242		}
243	} while (1);
244
245	if (i == -1)
246		result = isc__errno2result(errno);
247	else
248		result = ISC_R_SUCCESS;
249
250	return (result);
251}