/src/ntp-dev/lib/isc/unix/dir.c
Line | Count | Source (jump to first uncovered line) |
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 | | #include "ntp_stdlib.h" /* NTP change for strlcpy, strlcat */ |
39 | | |
40 | 0 | #define ISC_DIR_MAGIC ISC_MAGIC('D', 'I', 'R', '*') |
41 | | #define VALID_DIR(dir) ISC_MAGIC_VALID(dir, ISC_DIR_MAGIC) |
42 | | |
43 | | void |
44 | 0 | isc_dir_init(isc_dir_t *dir) { |
45 | 0 | REQUIRE(dir != NULL); |
46 | | |
47 | 0 | dir->entry.name[0] = '\0'; |
48 | 0 | dir->entry.length = 0; |
49 | |
|
50 | 0 | dir->handle = NULL; |
51 | |
|
52 | 0 | dir->magic = ISC_DIR_MAGIC; |
53 | 0 | } |
54 | | |
55 | | /*! |
56 | | * \brief Allocate workspace and open directory stream. If either one fails, |
57 | | * NULL will be returned. |
58 | | */ |
59 | | isc_result_t |
60 | 0 | isc_dir_open(isc_dir_t *dir, const char *dirname) { |
61 | 0 | char *p; |
62 | 0 | size_t octets; |
63 | 0 | isc_result_t result = ISC_R_SUCCESS; |
64 | |
|
65 | 0 | REQUIRE(VALID_DIR(dir)); |
66 | 0 | REQUIRE(dirname != NULL); |
67 | | |
68 | | /* |
69 | | * Copy directory name. Need to have enough space for the name, |
70 | | * a possible path separator, the wildcard, and the final NUL. |
71 | | */ |
72 | 0 | octets = strlen(dirname) + 1; |
73 | 0 | if (octets + 2 > sizeof(dir->dirname)) |
74 | | /* XXXDCL ? */ |
75 | 0 | return (ISC_R_NOSPACE); |
76 | 0 | strlcpy(dir->dirname, dirname, octets); |
77 | | |
78 | | /* |
79 | | * Append path separator, if needed, and "*". |
80 | | */ |
81 | 0 | p = dir->dirname + strlen(dir->dirname); |
82 | 0 | if (dir->dirname < p && *(p - 1) != '/') |
83 | 0 | *p++ = '/'; |
84 | 0 | *p++ = '*'; |
85 | 0 | *p = '\0'; |
86 | | |
87 | | /* |
88 | | * Open stream. |
89 | | */ |
90 | 0 | dir->handle = opendir(dirname); |
91 | |
|
92 | 0 | if (dir->handle == NULL) |
93 | 0 | return isc__errno2result(errno); |
94 | | |
95 | 0 | return (result); |
96 | 0 | } |
97 | | |
98 | | /*! |
99 | | * \brief Return previously retrieved file or get next one. |
100 | | |
101 | | * 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. |
104 | | */ |
105 | | isc_result_t |
106 | 0 | isc_dir_read(isc_dir_t *dir) { |
107 | 0 | struct dirent *entry; |
108 | 0 | size_t octets; |
109 | |
|
110 | 0 | REQUIRE(VALID_DIR(dir) && dir->handle != NULL); |
111 | | |
112 | | /* |
113 | | * Fetch next file in directory. |
114 | | */ |
115 | 0 | entry = readdir(dir->handle); |
116 | |
|
117 | 0 | if (entry == NULL) |
118 | 0 | return (ISC_R_NOMORE); |
119 | | |
120 | | /* |
121 | | * Make sure that the space for the name is long enough. |
122 | | */ |
123 | 0 | octets = strlen(entry->d_name) + 1; |
124 | 0 | if (sizeof(dir->entry.name) < octets) |
125 | 0 | return (ISC_R_UNEXPECTED); |
126 | | |
127 | 0 | strlcpy(dir->entry.name, entry->d_name, octets); |
128 | | |
129 | | /* |
130 | | * Some dirents have d_namlen, but it is not portable. |
131 | | */ |
132 | 0 | dir->entry.length = strlen(entry->d_name); |
133 | |
|
134 | 0 | return (ISC_R_SUCCESS); |
135 | 0 | } |
136 | | |
137 | | /*! |
138 | | * \brief Close directory stream. |
139 | | */ |
140 | | void |
141 | 0 | isc_dir_close(isc_dir_t *dir) { |
142 | 0 | REQUIRE(VALID_DIR(dir) && dir->handle != NULL); |
143 | | |
144 | 0 | (void)closedir(dir->handle); |
145 | 0 | dir->handle = NULL; |
146 | 0 | } |
147 | | |
148 | | /*! |
149 | | * \brief Reposition directory stream at start. |
150 | | */ |
151 | | isc_result_t |
152 | 0 | isc_dir_reset(isc_dir_t *dir) { |
153 | 0 | REQUIRE(VALID_DIR(dir) && dir->handle != NULL); |
154 | | |
155 | 0 | rewinddir(dir->handle); |
156 | |
|
157 | 0 | return (ISC_R_SUCCESS); |
158 | 0 | } |
159 | | |
160 | | isc_result_t |
161 | 0 | isc_dir_chdir(const char *dirname) { |
162 | | /*! |
163 | | * \brief Change the current directory to 'dirname'. |
164 | | */ |
165 | |
|
166 | 0 | REQUIRE(dirname != NULL); |
167 | | |
168 | 0 | if (chdir(dirname) < 0) |
169 | 0 | return (isc__errno2result(errno)); |
170 | | |
171 | 0 | return (ISC_R_SUCCESS); |
172 | 0 | } |
173 | | |
174 | | isc_result_t |
175 | 0 | isc_dir_chroot(const char *dirname) { |
176 | |
|
177 | 0 | REQUIRE(dirname != NULL); |
178 | | |
179 | | #ifdef HAVE_CHROOT |
180 | | if (chroot(dirname) < 0 || chdir("/") < 0) |
181 | | return (isc__errno2result(errno)); |
182 | | |
183 | | return (ISC_R_SUCCESS); |
184 | | #else |
185 | 0 | return (ISC_R_NOTIMPLEMENTED); |
186 | 0 | #endif |
187 | 0 | } |
188 | | |
189 | | isc_result_t |
190 | 0 | isc_dir_createunique(char *templet) { |
191 | 0 | isc_result_t result; |
192 | 0 | char *x; |
193 | 0 | char *p; |
194 | 0 | int i; |
195 | 0 | int pid; |
196 | |
|
197 | 0 | REQUIRE(templet != NULL); |
198 | | |
199 | | /*! |
200 | | * \brief mkdtemp is not portable, so this emulates it. |
201 | | */ |
202 | | |
203 | 0 | pid = getpid(); |
204 | | |
205 | | /* |
206 | | * Replace trailing Xs with the process-id, zero-filled. |
207 | | */ |
208 | 0 | for (x = templet + strlen(templet) - 1; *x == 'X' && x >= templet; |
209 | 0 | x--, pid /= 10) |
210 | 0 | *x = pid % 10 + '0'; |
211 | |
|
212 | 0 | x++; /* Set x to start of ex-Xs. */ |
213 | |
|
214 | 0 | do { |
215 | 0 | i = mkdir(templet, 0700); |
216 | 0 | if (i == 0 || errno != EEXIST) |
217 | 0 | break; |
218 | | |
219 | | /* |
220 | | * The BSD algorithm. |
221 | | */ |
222 | 0 | p = x; |
223 | 0 | while (*p != '\0') { |
224 | 0 | if (isdigit(*p & 0xff)) |
225 | 0 | *p = 'a'; |
226 | 0 | else if (*p != 'z') |
227 | 0 | ++*p; |
228 | 0 | else { |
229 | | /* |
230 | | * Reset character and move to next. |
231 | | */ |
232 | 0 | *p++ = 'a'; |
233 | 0 | continue; |
234 | 0 | } |
235 | | |
236 | 0 | break; |
237 | 0 | } |
238 | |
|
239 | 0 | if (*p == '\0') { |
240 | | /* |
241 | | * Tried all combinations. errno should already |
242 | | * be EEXIST, but ensure it is anyway for |
243 | | * isc__errno2result(). |
244 | | */ |
245 | 0 | errno = EEXIST; |
246 | 0 | break; |
247 | 0 | } |
248 | 0 | } while (1); |
249 | | |
250 | 0 | if (i == -1) |
251 | 0 | result = isc__errno2result(errno); |
252 | 0 | else |
253 | 0 | result = ISC_R_SUCCESS; |
254 | |
|
255 | 0 | return (result); |
256 | 0 | } |