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