Apache HTTPD
dir.c
Go to the documentation of this file.
1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "apr.h"
18#include "apr_arch_file_io.h"
19#include "apr_file_io.h"
20#include "apr_strings.h"
21#include "apr_portable.h"
22#include "apr_arch_atime.h"
23
24#if APR_HAVE_ERRNO_H
25#include <errno.h>
26#endif
27#if APR_HAVE_STRING_H
28#include <string.h>
29#endif
30#if APR_HAVE_DIRENT_H
31#include <dirent.h>
32#endif
33#ifdef HAVE_SYS_STAT_H
34#include <sys/stat.h>
35#endif
36
37
47
50{
51 apr_status_t rv;
52
53 apr_size_t len = strlen(dirname);
54 (*new) = apr_pcalloc(pool, sizeof(apr_dir_t));
55 /* Leave room here to add and pop the '*' wildcard for FindFirstFile
56 * and double-null terminate so we have one character to change.
57 */
58 (*new)->dirname = apr_palloc(pool, len + 3);
59 memcpy((*new)->dirname, dirname, len);
60 if (len && (*new)->dirname[len - 1] != '/') {
61 (*new)->dirname[len++] = '/';
62 }
63 (*new)->dirname[len++] = '\0';
64 (*new)->dirname[len] = '\0';
65
66#if APR_HAS_UNICODE_FS
68 {
69 /* Create a buffer for the longest file name we will ever see
70 */
71 (*new)->w.entry = apr_pcalloc(pool, sizeof(WIN32_FIND_DATAW));
72 (*new)->name = apr_pcalloc(pool, APR_FILE_MAX * 3 + 1);
73 }
74#endif
75#if APR_HAS_ANSI_FS
77 {
78 /* Note that we won't open a directory that is greater than MAX_PATH,
79 * counting the additional '/' '*' wildcard suffix. If a * won't fit
80 * then neither will any other file name within the directory.
81 * The length not including the trailing '*' is stored as rootlen, to
82 * skip over all paths which are too long.
83 */
84 if (len >= APR_PATH_MAX) {
85 (*new) = NULL;
86 return APR_ENAMETOOLONG;
87 }
88 (*new)->n.entry = apr_pcalloc(pool, sizeof(WIN32_FIND_DATAW));
89 }
90#endif
91 (*new)->rootlen = len - 1;
92 (*new)->pool = pool;
93 (*new)->dirhand = INVALID_HANDLE_VALUE;
94 apr_pool_cleanup_register((*new)->pool, (void *)(*new), dir_cleanup,
96
97 rv = apr_dir_read(NULL, 0, *new);
98 if (rv != APR_SUCCESS) {
99 dir_cleanup(*new);
100 *new = NULL;
101 }
102
103 return rv;
104}
105
107{
109 return dir_cleanup(dir);
110}
111
114{
115 apr_status_t rv;
116 char *fname;
117 /* The while loops below allow us to skip all invalid file names, so that
118 * we aren't reporting any files where their absolute paths are too long.
119 */
120#if APR_HAS_UNICODE_FS
124 {
125 /* This code path is always be invoked by apr_dir_open or
126 * apr_dir_rewind, so return without filling out the finfo.
127 */
129 {
130 apr_status_t rv;
132
133 if ((rv = utf8_to_unicode_path(wdirname, sizeof(wdirname)
134 / sizeof(apr_wchar_t),
135 thedir->dirname))) {
136 return rv;
137 }
138 eos = wcschr(wdirname, '\0');
139 eos[0] = '*';
140 eos[1] = '\0';
141
142 /* Do not request short file names on Windows 7 and later. */
143 if (apr_os_level >= APR_WIN_7) {
145 }
146 else {
148 }
149
151 thedir->w.entry,
153 0);
154 eos[0] = '\0';
156 return apr_get_os_error();
157 }
158 thedir->bof = 1;
159 return APR_SUCCESS;
160 }
161 else if (thedir->bof) {
162 /* Noop - we already called FindFirstFileW from
163 * either apr_dir_open or apr_dir_rewind ... use
164 * that first record.
165 */
166 thedir->bof = 0;
167 }
168 else if (!FindNextFileW(thedir->dirhand, thedir->w.entry)) {
169 return apr_get_os_error();
170 }
171
172 while (thedir->rootlen &&
173 thedir->rootlen + wcslen(thedir->w.entry->cFileName) >= APR_PATH_MAX)
174 {
176 return apr_get_os_error();
177 }
178 }
179 if ((rv = unicode_to_utf8_path(thedir->name, APR_FILE_MAX * 3 + 1,
180 thedir->w.entry->cFileName)))
181 return rv;
182 fname = thedir->name;
183 }
184#endif
185#if APR_HAS_ANSI_FS
187 {
188 /* This code path is always be invoked by apr_dir_open or
189 * apr_dir_rewind, so return without filling out the finfo.
190 */
192 /* '/' terminated, so add the '*' and pop it when we finish */
193 char *eop = strchr(thedir->dirname, '\0');
194 eop[0] = '*';
195 eop[1] = '\0';
197 thedir->n.entry);
198 eop[0] = '\0';
200 return apr_get_os_error();
201 }
202 thedir->bof = 1;
203 return APR_SUCCESS;
204 }
205 else if (thedir->bof) {
206 /* Noop - we already called FindFirstFileW from
207 * either apr_dir_open or apr_dir_rewind ... use
208 * that first record.
209 */
210 thedir->bof = 0;
211 }
212 else if (!FindNextFileA(thedir->dirhand, thedir->n.entry)) {
213 return apr_get_os_error();
214 }
215 while (thedir->rootlen &&
216 thedir->rootlen + strlen(thedir->n.entry->cFileName) >= MAX_PATH)
217 {
219 return apr_get_os_error();
220 }
221 }
222 fname = thedir->n.entry->cFileName;
223 }
224#endif
225
227 0, 1, fname, wanted);
228 finfo->pool = thedir->pool;
229
230 finfo->valid |= APR_FINFO_NAME;
231 finfo->name = fname;
232
233 if (wanted &= ~finfo->valid) {
234 /* Go back and get more_info if we can't answer the whole inquiry
235 */
236#if APR_HAS_UNICODE_FS
238 {
239 /* Almost all our work is done. Tack on the wide file name
240 * to the end of the wdirname (already / delimited)
241 */
242 if (!eos)
243 eos = wcschr(wdirname, '\0');
244 wcscpy(eos, thedir->w.entry->cFileName);
246 eos[0] = '\0';
247 return rv;
248 }
249#endif
250#if APR_HAS_ANSI_FS
252 {
253#if APR_HAS_UNICODE_FS
254 /* Don't waste stack space on a second buffer, the one we set
255 * aside for the wide directory name is twice what we need.
256 */
257 char *fspec = (char*)wdirname;
258#else
259 char fspec[APR_PATH_MAX];
260#endif
261 apr_size_t dirlen = strlen(thedir->dirname);
262 if (dirlen >= sizeof(fspec))
263 dirlen = sizeof(fspec) - 1;
265 apr_cpystrn(fspec + dirlen, fname, sizeof(fspec) - dirlen);
266 return more_finfo(finfo, fspec, wanted, MORE_OF_FSPEC);
267 }
268#endif
269 }
270
271 return APR_SUCCESS;
272}
273
275{
276 apr_status_t rv;
277
278 /* this will mark the handle as invalid and we'll open it
279 * again if apr_dir_read() is subsequently called
280 */
281 rv = dir_cleanup(dir);
282
283 if (rv == APR_SUCCESS)
284 rv = apr_dir_read(NULL, 0, dir);
285
286 return rv;
287}
288
291{
292#if APR_HAS_UNICODE_FS
294 {
296 apr_status_t rv;
297 if ((rv = utf8_to_unicode_path(wpath,
298 sizeof(wpath) / sizeof(apr_wchar_t),
299 path))) {
300 return rv;
301 }
302 if (!CreateDirectoryW(wpath, NULL)) {
303 return apr_get_os_error();
304 }
305 }
306#endif
307#if APR_HAS_ANSI_FS
309 if (!CreateDirectory(path, NULL)) {
310 return apr_get_os_error();
311 }
312#endif
313 return APR_SUCCESS;
314}
315
316
320{
321 apr_status_t rv;
322 char *ch = strrchr(path, '\\');
323 if (!ch) {
324 return APR_ENOENT;
325 }
326
327 *ch = '\0';
328 rv = apr_dir_make (path, perm, pool); /* Try to make straight off */
329
330 if (APR_STATUS_IS_ENOENT(rv)) { /* Missing an intermediate dir */
332
333 if (rv == APR_SUCCESS || APR_STATUS_IS_EEXIST(rv)) {
334 rv = apr_dir_make(path, perm, pool); /* And complete the path */
335 }
336 }
337
338 *ch = '\\'; /* Always replace the slash before returning */
339 return rv;
340}
341
345{
346 apr_status_t rv = 0;
347
348 rv = apr_dir_make (path, perm, pool); /* Try to make PATH right out */
349
350 if (APR_STATUS_IS_ENOENT(rv)) { /* Missing an intermediate dir */
351 char *dir;
352
354
355 if (rv != APR_SUCCESS)
356 return rv;
357
358 rv = dir_make_parent(dir, perm, pool); /* Make intermediate dirs */
359
360 if (rv == APR_SUCCESS || APR_STATUS_IS_EEXIST(rv)) {
361 rv = apr_dir_make (dir, perm, pool); /* And complete the path */
362
363 if (APR_STATUS_IS_EEXIST(rv)) {
364 rv = APR_SUCCESS; /* Timing issue; see comment below */
365 }
366 }
367 }
368 else if (APR_STATUS_IS_EEXIST(rv)) {
369 /*
370 * It's OK if PATH exists. Timing issues can lead to the
371 * second apr_dir_make being called on existing dir, therefore
372 * this check has to come last.
373 */
374 rv = APR_SUCCESS;
375 }
376
377 return rv;
378}
379
380
382{
383#if APR_HAS_UNICODE_FS
385 {
387 apr_status_t rv;
388 if ((rv = utf8_to_unicode_path(wpath,
389 sizeof(wpath) / sizeof(apr_wchar_t),
390 path))) {
391 return rv;
392 }
393 if (!RemoveDirectoryW(wpath)) {
394 return apr_get_os_error();
395 }
396 }
397#endif
398#if APR_HAS_ANSI_FS
400 if (!RemoveDirectory(path)) {
401 return apr_get_os_error();
402 }
403#endif
404 return APR_SUCCESS;
405}
406
408 apr_dir_t *dir)
409{
410 if (dir == NULL) {
411 return APR_ENODIR;
412 }
413 *thedir = dir->dirhand;
414 return APR_SUCCESS;
415}
416
420{
421 return APR_ENOTIMPL;
422}
const char apr_size_t len
Definition ap_regex.h:187
apr_uint16_t apr_wchar_t
APR File I/O Handling.
APR Portability Routines.
APR Strings library.
request_rec int int apr_table_t const char * path
#define APR_ENAMETOOLONG
Definition apr_errno.h:655
#define APR_ENOTIMPL
Definition apr_errno.h:476
#define APR_ENODIR
Definition apr_errno.h:301
#define APR_ENOENT
Definition apr_errno.h:662
#define APR_STATUS_IS_EEXIST(s)
Definition apr_errno.h:1233
#define APR_STATUS_IS_ENOENT(s)
Definition apr_errno.h:1246
const void apr_status_t(*) apr_status_t(* APR_DECLARE)(void) apr_pool_pre_cleanup_register(apr_pool_t *p
Definition apr_pools.h:646
apr_size_t size
const char int apr_pool_t * pool
Definition apr_cstr.h:84
const char * dirname
apr_int32_t apr_dir_t * thedir
#define APR_SUCCESS
Definition apr_errno.h:225
#define apr_get_os_error()
Definition apr_errno.h:1217
int apr_status_t
Definition apr_errno.h:44
apr_int32_t apr_fileperms_t
const char apr_int32_t apr_fileperms_t perm
const char apr_int32_t wanted
const char * fname
#define APR_FINFO_NAME
#define APR_FILEPATH_NATIVE
#define apr_pcalloc(p, size)
Definition apr_pools.h:465
DIR apr_os_dir_t
apr_dir_t * dir
return NULL
Definition mod_so.c:359
static apr_status_t dir_cleanup(void *thedir)
Definition dir.c:24
struct dirent * entry
apr_pool_t * pool
struct apr_dir_t::@60::@62 n
apr_size_t rootlen
const char * name
apr_pool_t * pool
apr_int32_t valid
apr_status_t apr_dir_read(apr_finfo_t *finfo, apr_int32_t wanted, apr_dir_t *thedir)
Definition dir.c:142
apr_status_t apr_dir_make(const char *path, apr_fileperms_t perm, apr_pool_t *pool)
Definition dir.c:297
apr_status_t apr_dir_remove(const char *path, apr_pool_t *pool)
Definition dir.c:343
apr_status_t apr_dir_close(apr_dir_t *thedir)
Definition dir.c:109
apr_status_t apr_dir_open(apr_dir_t **new, const char *dirname, apr_pool_t *pool)
Definition dir.c:75
apr_status_t apr_dir_make_recursive(const char *path, apr_fileperms_t perm, apr_pool_t *pool)
Definition dir.c:310
apr_status_t apr_os_dir_get(apr_os_dir_t **thedir, apr_dir_t *dir)
Definition dir.c:353
apr_status_t apr_dir_rewind(apr_dir_t *thedir)
Definition dir.c:291
apr_status_t apr_os_dir_put(apr_dir_t **dir, apr_os_dir_t *thedir, apr_pool_t *pool)
Definition dir.c:362
#define MORE_OF_FSPEC
#define MORE_OF_WFSPEC
#define APR_FILE_MAX
#define ELSE_WIN_OS_IS_ANSI
APR_DECLARE_DATA apr_oslevel_e apr_os_level
Definition misc.c:24
@ APR_WIN_7
#define IF_WIN_OS_IS_UNICODE
static apr_status_t dir_make_parent(char *path, apr_fileperms_t perm, apr_pool_t *pool)
Definition dir.c:317
apr_status_t more_finfo(apr_finfo_t *finfo, const void *ufile, apr_int32_t wanted, int whatfile)
Definition filestat.c:278
int fillin_fileinfo(apr_finfo_t *finfo, WIN32_FILE_ATTRIBUTE_DATA *wininfo, int byhandle, int finddata, const char *fname, apr_int32_t wanted)
Definition filestat.c:417