1
/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
* you may not use this file except in compliance with the License.
6
* You may obtain a copy of the License at
8
* http://www.apache.org/licenses/LICENSE-2.0
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.
17
#include "apr_arch_file_io.h"
19
#include "nks/dirio.h"
20
#include "apr_file_io.h"
21
#include "apr_general.h"
22
#include "apr_strings.h"
23
#include "apr_errno.h"
25
#include "apr_thread_rwlock.h"
33
static apr_filetype_e filetype_from_mode(mode_t mode)
35
apr_filetype_e type = APR_NOFILE;
39
else if (S_ISDIR(mode))
41
else if (S_ISCHR(mode))
43
else if (S_ISBLK(mode))
45
else if (S_ISFIFO(mode))
47
else if (S_ISLNK(mode))
49
else if (S_ISSOCK(mode))
56
static void fill_out_finfo(apr_finfo_t *finfo, struct stat *info,
59
finfo->valid = APR_FINFO_MIN | APR_FINFO_IDENT | APR_FINFO_NLINK
60
| APR_FINFO_OWNER | APR_FINFO_PROT;
61
finfo->protection = apr_unix_mode2perms(info->st_mode);
62
finfo->filetype = filetype_from_mode(info->st_mode);
63
finfo->user = info->st_uid;
64
finfo->group = info->st_gid;
65
finfo->size = info->st_size;
66
finfo->inode = info->st_ino;
67
finfo->device = info->st_dev;
68
finfo->nlink = info->st_nlink;
69
apr_time_ansi_put(&finfo->atime, info->st_atime.tv_sec);
70
apr_time_ansi_put(&finfo->mtime, info->st_mtime.tv_sec);
71
apr_time_ansi_put(&finfo->ctime, info->st_ctime.tv_sec);
72
/* ### needs to be revisited
73
* if (wanted & APR_FINFO_CSIZE) {
74
* finfo->csize = info->st_blocks * 512;
75
* finfo->valid |= APR_FINFO_CSIZE;
80
APR_DECLARE(apr_status_t) apr_file_info_get(apr_finfo_t *finfo,
86
if (thefile->buffered) {
87
apr_status_t rv = apr_file_flush(thefile);
88
if (rv != APR_SUCCESS)
92
if (fstat(thefile->filedes, &info) == 0) {
93
finfo->pool = thefile->pool;
94
finfo->fname = thefile->fname;
95
fill_out_finfo(finfo, &info, wanted);
96
return (wanted & ~finfo->valid) ? APR_INCOMPLETE : APR_SUCCESS;
103
APR_DECLARE(apr_status_t) apr_file_perms_set(const char *fname,
104
apr_fileperms_t perms)
106
mode_t mode = apr_unix_perms2mode(perms);
108
if (chmod(fname, mode) == -1)
113
APR_DECLARE(apr_status_t) apr_file_attrs_set(const char *fname,
114
apr_fileattrs_t attributes,
115
apr_fileattrs_t attr_mask,
121
/* Don't do anything if we can't handle the requested attributes */
122
if (!(attr_mask & (APR_FILE_ATTR_READONLY
123
| APR_FILE_ATTR_EXECUTABLE)))
126
status = apr_stat(&finfo, fname, APR_FINFO_PROT, pool);
130
/* ### TODO: should added bits be umask'd? */
131
if (attr_mask & APR_FILE_ATTR_READONLY)
133
if (attributes & APR_FILE_ATTR_READONLY)
135
finfo.protection &= ~APR_UWRITE;
136
finfo.protection &= ~APR_GWRITE;
137
finfo.protection &= ~APR_WWRITE;
141
/* ### umask this! */
142
finfo.protection |= APR_UWRITE;
143
finfo.protection |= APR_GWRITE;
144
finfo.protection |= APR_WWRITE;
148
if (attr_mask & APR_FILE_ATTR_EXECUTABLE)
150
if (attributes & APR_FILE_ATTR_EXECUTABLE)
152
/* ### umask this! */
153
finfo.protection |= APR_UEXECUTE;
154
finfo.protection |= APR_GEXECUTE;
155
finfo.protection |= APR_WEXECUTE;
159
finfo.protection &= ~APR_UEXECUTE;
160
finfo.protection &= ~APR_GEXECUTE;
161
finfo.protection &= ~APR_WEXECUTE;
165
return apr_file_perms_set(fname, finfo.protection);
169
static apr_status_t stat_cache_cleanup(void *data)
171
apr_pool_t *p = (apr_pool_t *)getGlobalPool();
172
apr_hash_index_t *hi;
173
apr_hash_t *statCache = (apr_hash_t*)data;
178
for (hi = apr_hash_first(p, statCache); hi; hi = apr_hash_next(hi)) {
179
apr_hash_this(hi, (const void**)&key, &keylen, (void**)&pathctx);
182
NXFreePathContext(pathctx);
189
int cstat (NXPathCtx_t ctx, char *path, struct stat *buf, unsigned long requestmap, apr_pool_t *p)
191
apr_pool_t *gPool = (apr_pool_t *)getGlobalPool();
192
apr_hash_t *statCache = NULL;
193
apr_thread_rwlock_t *rwlock = NULL;
195
NXPathCtx_t pathctx = 0;
196
char *ptr = NULL, *tr;
203
/* If there isn't a global pool then just stat the file
208
if (apr_pool_create(&gPool, NULL) != APR_SUCCESS) {
209
return getstat(ctx, path, buf, requestmap);
212
setGlobalPool(gPool);
213
apr_pool_tag(gPool, apr_pstrdup(gPool, "cstat_mem_pool"));
215
statCache = apr_hash_make(gPool);
216
apr_pool_userdata_set ((void*)statCache, "STAT_CACHE", stat_cache_cleanup, gPool);
218
apr_thread_rwlock_create(&rwlock, gPool);
219
apr_pool_userdata_set ((void*)rwlock, "STAT_CACHE_LOCK", apr_pool_cleanup_null, gPool);
222
apr_pool_userdata_get((void**)&statCache, "STAT_CACHE", gPool);
223
apr_pool_userdata_get((void**)&rwlock, "STAT_CACHE_LOCK", gPool);
226
if (!gPool || !statCache || !rwlock) {
227
return getstat(ctx, path, buf, requestmap);
230
for (x = 0,tr = path;*tr != '\0';tr++,x++) {
231
if (*tr == '\\' || *tr == '/') {
242
ppath = apr_pstrndup (p, path, len);
244
if (ptr[1] != '\0') {
247
/* If the path ended in a trailing slash then our result path
248
will be a single slash. To avoid stat'ing the root with a
249
slash, we need to make sure we stat the current directory
251
if (((*ptr == '/') || (*ptr == '\\')) && (*(ptr+1) == '\0')) {
252
pinfo = apr_pstrdup (p, ".");
255
pinfo = apr_pstrdup (p, ptr);
259
/* If we have a statCache then try to pull the information
260
from the cache. Otherwise just stat the file and return.*/
262
apr_thread_rwlock_rdlock(rwlock);
263
pathctx = (NXPathCtx_t) apr_hash_get(statCache, ppath, APR_HASH_KEY_STRING);
264
apr_thread_rwlock_unlock(rwlock);
266
return getstat(pathctx, pinfo, buf, requestmap);
271
err = NXCreatePathContext(0, ppath, 0, NULL, &pathctx);
273
apr_thread_rwlock_wrlock(rwlock);
274
apr_hash_set(statCache, apr_pstrdup(gPool,ppath) , APR_HASH_KEY_STRING, (void*)pathctx);
275
apr_thread_rwlock_unlock(rwlock);
276
return getstat(pathctx, pinfo, buf, requestmap);
281
return getstat(ctx, path, buf, requestmap);
285
APR_DECLARE(apr_status_t) apr_stat(apr_finfo_t *finfo,
287
apr_int32_t wanted, apr_pool_t *pool)
291
NXPathCtx_t pathCtx = 0;
293
getcwdpath(NULL, &pathCtx, CTX_ACTUAL_CWD);
295
srv = getstat(pathCtx, (char*)fname, &info, ST_STAT_BITS|ST_NAME_BIT);
297
srv = cstat(pathCtx, (char*)fname, &info, ST_STAT_BITS|ST_NAME_BIT, pool);
303
finfo->fname = fname;
304
fill_out_finfo(finfo, &info, wanted);
305
if (wanted & APR_FINFO_LINK)
306
wanted &= ~APR_FINFO_LINK;
307
if (wanted & APR_FINFO_NAME) {
308
finfo->name = apr_pstrdup(pool, info.st_name);
309
finfo->valid |= APR_FINFO_NAME;
311
return (wanted & ~finfo->valid) ? APR_INCOMPLETE : APR_SUCCESS;
314
#if !defined(ENOENT) || !defined(ENOTDIR)
315
#error ENOENT || ENOTDIR not defined; please see the
316
#error comments at this line in the source for a workaround.
318
* If ENOENT || ENOTDIR is not defined in one of the your OS's
319
* include files, APR cannot report a good reason why the stat()
320
* of the file failed; there are cases where it can fail even though
321
* the file exists. This opens holes in Apache, for example, because
322
* it becomes possible for someone to get a directory listing of a
323
* directory even though there is an index (eg. index.html) file in
324
* it. If you do not have a problem with this, delete the above
325
* #error lines and start the compile again. If you need to do this,
326
* please submit a bug report to http://www.apache.org/bug_report.html
327
* letting us know that you needed to do this. Please be sure to
328
* include the operating system you are using.
330
/* WARNING: All errors will be handled as not found
335
/* WARNING: All errors but not found will be handled as not directory
342
#else /* All was defined well, report the usual: */
348
APR_DECLARE(apr_status_t) apr_file_mtime_set(const char *fname,
355
status = apr_stat(&finfo, fname, APR_FINFO_ATIME, pool);
362
struct timeval tvp[2];
364
tvp[0].tv_sec = apr_time_sec(finfo.atime);
365
tvp[0].tv_usec = apr_time_usec(finfo.atime);
366
tvp[1].tv_sec = apr_time_sec(mtime);
367
tvp[1].tv_usec = apr_time_usec(mtime);
369
if (utimes(fname, tvp) == -1) {
373
#elif defined(HAVE_UTIME)
377
buf.actime = (time_t) (finfo.atime / APR_USEC_PER_SEC);
378
buf.modtime = (time_t) (mtime / APR_USEC_PER_SEC);
380
if (utime(fname, &buf) == -1) {