4 * Copyright (C) 2004, 2007-2009 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 1999-2001 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
20 /* Id: dir.c,v 1.16.22.2 2009/01/18 23:47:41 tbox Exp */
22 /* Principal Authors: DCL */
34 #include <isc/magic.h>
35 #include <isc/assertions.h>
38 #include "errno2result.h"
40 #define ISC_DIR_MAGIC ISC_MAGIC('D', 'I', 'R', '*')
41 #define VALID_DIR(dir) ISC_MAGIC_VALID(dir, ISC_DIR_MAGIC)
44 start_directory(isc_dir_t
*p
);
47 isc_dir_init(isc_dir_t
*dir
) {
50 dir
->dirname
[0] = '\0';
52 dir
->entry
.name
[0] = '\0';
53 dir
->entry
.length
= 0;
54 memset(&(dir
->entry
.find_data
), 0, sizeof(dir
->entry
.find_data
));
56 dir
->entry_filled
= ISC_FALSE
;
57 dir
->search_handle
= INVALID_HANDLE_VALUE
;
59 dir
->magic
= ISC_DIR_MAGIC
;
63 * Allocate workspace and open directory stream. If either one fails,
64 * NULL will be returned.
67 isc_dir_open(isc_dir_t
*dir
, const char *dirname
) {
71 REQUIRE(dirname
!= NULL
);
72 REQUIRE(VALID_DIR(dir
) && dir
->search_handle
== INVALID_HANDLE_VALUE
);
75 * Copy directory name. Need to have enough space for the name,
76 * a possible path separator, the wildcard, and the final NUL.
78 if (strlen(dirname
) + 3 > sizeof(dir
->dirname
))
80 return (ISC_R_NOSPACE
);
81 strcpy(dir
->dirname
, dirname
);
84 * Append path separator, if needed, and "*".
86 p
= dir
->dirname
+ strlen(dir
->dirname
);
87 if (dir
->dirname
< p
&& *(p
- 1) != '\\' && *(p
- 1) != ':')
95 result
= start_directory(dir
);
101 * Return previously retrieved file or get next one. Unix's dirent has
102 * separate open and read functions, but the Win32 and DOS interfaces open
103 * the dir stream and reads the first file in one operation.
106 isc_dir_read(isc_dir_t
*dir
) {
107 REQUIRE(VALID_DIR(dir
) && dir
->search_handle
!= INVALID_HANDLE_VALUE
);
109 if (dir
->entry_filled
)
111 * start_directory() already filled in the first entry.
113 dir
->entry_filled
= ISC_FALSE
;
117 * Fetch next file in directory.
119 if (FindNextFile(dir
->search_handle
,
120 &dir
->entry
.find_data
) == FALSE
)
122 * Either the last file has been processed or
123 * an error has occurred. The former is not
124 * really an error, but the latter is.
126 if (GetLastError() == ERROR_NO_MORE_FILES
)
127 return (ISC_R_NOMORE
);
129 return (ISC_R_UNEXPECTED
);
133 * Make sure that the space for the name is long enough.
135 strcpy(dir
->entry
.name
, dir
->entry
.find_data
.cFileName
);
136 dir
->entry
.length
= strlen(dir
->entry
.name
);
138 return (ISC_R_SUCCESS
);
142 * Close directory stream.
145 isc_dir_close(isc_dir_t
*dir
) {
146 REQUIRE(VALID_DIR(dir
) && dir
->search_handle
!= INVALID_HANDLE_VALUE
);
148 FindClose(dir
->search_handle
);
149 dir
->search_handle
= INVALID_HANDLE_VALUE
;
153 * Reposition directory stream at start.
156 isc_dir_reset(isc_dir_t
*dir
) {
159 REQUIRE(VALID_DIR(dir
) && dir
->search_handle
!= INVALID_HANDLE_VALUE
);
160 REQUIRE(dir
->dirname
!= NULL
);
163 * NT cannot reposition the seek pointer to the beginning of the
164 * the directory stream, but rather the directory needs to be
165 * closed and reopened. The latter might fail.
170 result
= start_directory(dir
);
176 * Initialize isc_dir_t structure with new directory. The function
177 * returns 0 on failure and nonzero on success.
180 * - Be sure to close previous stream before opening new one
183 start_directory(isc_dir_t
*dir
)
185 REQUIRE(VALID_DIR(dir
));
186 REQUIRE(dir
->search_handle
== INVALID_HANDLE_VALUE
);
188 dir
->entry_filled
= ISC_FALSE
;
191 * Open stream and retrieve first file.
193 dir
->search_handle
= FindFirstFile(dir
->dirname
,
194 &dir
->entry
.find_data
);
196 if (dir
->search_handle
== INVALID_HANDLE_VALUE
) {
198 * Something went wrong but we don't know what. GetLastError()
199 * could give us more information about the error, but the
200 * MSDN documentation is frustratingly thin about what
201 * possible errors could have resulted. (Score one for
202 * the Unix manual pages.) So there is just this lame error
203 * instead of being able to differentiate ISC_R_NOTFOUND
204 * from ISC_R_UNEXPECTED.
206 return (ISC_R_FAILURE
);
210 * Make sure that the space for the name is long enough.
212 INSIST(sizeof(dir
->entry
.name
) >
213 strlen(dir
->entry
.find_data
.cFileName
));
216 * Fill in the data for the first entry of the directory.
218 strcpy(dir
->entry
.name
, dir
->entry
.find_data
.cFileName
);
219 dir
->entry
.length
= strlen(dir
->entry
.name
);
221 dir
->entry_filled
= ISC_TRUE
;
223 return (ISC_R_SUCCESS
);
227 isc_dir_chdir(const char *dirname
) {
229 * Change the current directory to 'dirname'.
232 REQUIRE(dirname
!= NULL
);
234 if (chdir(dirname
) < 0)
235 return (isc__errno2result(errno
));
237 return (ISC_R_SUCCESS
);
241 isc_dir_chroot(const char *dirname
) {
242 return (ISC_R_NOTIMPLEMENTED
);
246 isc_dir_createunique(char *templet
) {
253 REQUIRE(templet
!= NULL
);
256 * mkdtemp is not portable, so this emulates it.
262 * Replace trailing Xs with the process-id, zero-filled.
264 for (x
= templet
+ strlen(templet
) - 1; *x
== 'X' && x
>= templet
;
268 x
++; /* Set x to start of ex-Xs. */
272 i
= chmod(templet
, 0700);
274 if (i
== 0 || errno
!= EEXIST
)
282 if (isdigit(*p
& 0xff))
288 * Reset character and move to next.
299 * Tried all combinations. errno should already
300 * be EEXIST, but ensure it is anyway for
301 * isc__errno2result().
309 result
= isc__errno2result(errno
);
311 result
= ISC_R_SUCCESS
;