1251875Speter/* Licensed to the Apache Software Foundation (ASF) under one or more
2251875Speter * contributor license agreements.  See the NOTICE file distributed with
3251875Speter * this work for additional information regarding copyright ownership.
4251875Speter * The ASF licenses this file to You under the Apache License, Version 2.0
5251875Speter * (the "License"); you may not use this file except in compliance with
6251875Speter * the License.  You may obtain a copy of the License at
7251875Speter *
8251875Speter *     http://www.apache.org/licenses/LICENSE-2.0
9251875Speter *
10251875Speter * Unless required by applicable law or agreed to in writing, software
11251875Speter * distributed under the License is distributed on an "AS IS" BASIS,
12251875Speter * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13251875Speter * See the License for the specific language governing permissions and
14251875Speter * limitations under the License.
15251875Speter */
16251875Speter
17251875Speter#include "apr_arch_file_io.h"
18251875Speter#include "apr_file_io.h"
19251875Speter#include "apr_general.h"
20251875Speter#include "apr_strings.h"
21251875Speter#include "apr_errno.h"
22251875Speter
23251875Speter#ifdef HAVE_UTIME
24251875Speter#include <utime.h>
25251875Speter#endif
26251875Speter
27251875Speterstatic apr_filetype_e filetype_from_mode(mode_t mode)
28251875Speter{
29251875Speter    apr_filetype_e type;
30251875Speter
31251875Speter    switch (mode & S_IFMT) {
32251875Speter    case S_IFREG:
33251875Speter        type = APR_REG;  break;
34251875Speter    case S_IFDIR:
35251875Speter        type = APR_DIR;  break;
36251875Speter    case S_IFLNK:
37251875Speter        type = APR_LNK;  break;
38251875Speter    case S_IFCHR:
39251875Speter        type = APR_CHR;  break;
40251875Speter    case S_IFBLK:
41251875Speter        type = APR_BLK;  break;
42251875Speter#if defined(S_IFFIFO)
43251875Speter    case S_IFFIFO:
44251875Speter        type = APR_PIPE; break;
45251875Speter#endif
46251875Speter#if !defined(BEOS) && defined(S_IFSOCK)
47251875Speter    case S_IFSOCK:
48251875Speter        type = APR_SOCK; break;
49251875Speter#endif
50251875Speter
51251875Speter    default:
52251875Speter	/* Work around missing S_IFxxx values above
53251875Speter         * for Linux et al.
54251875Speter         */
55251875Speter#if !defined(S_IFFIFO) && defined(S_ISFIFO)
56251875Speter    	if (S_ISFIFO(mode)) {
57251875Speter            type = APR_PIPE;
58251875Speter	} else
59251875Speter#endif
60251875Speter#if !defined(BEOS) && !defined(S_IFSOCK) && defined(S_ISSOCK)
61251875Speter    	if (S_ISSOCK(mode)) {
62251875Speter            type = APR_SOCK;
63251875Speter	} else
64251875Speter#endif
65251875Speter        type = APR_UNKFILE;
66251875Speter    }
67251875Speter    return type;
68251875Speter}
69251875Speter
70251875Speterstatic void fill_out_finfo(apr_finfo_t *finfo, struct_stat *info,
71251875Speter                           apr_int32_t wanted)
72251875Speter{
73251875Speter    finfo->valid = APR_FINFO_MIN | APR_FINFO_IDENT | APR_FINFO_NLINK
74251875Speter                 | APR_FINFO_OWNER | APR_FINFO_PROT;
75251875Speter    finfo->protection = apr_unix_mode2perms(info->st_mode);
76251875Speter    finfo->filetype = filetype_from_mode(info->st_mode);
77251875Speter    finfo->user = info->st_uid;
78251875Speter    finfo->group = info->st_gid;
79251875Speter    finfo->size = info->st_size;
80251875Speter    finfo->device = info->st_dev;
81251875Speter    finfo->nlink = info->st_nlink;
82251875Speter
83251875Speter    /* Check for overflow if storing a 64-bit st_ino in a 32-bit
84251875Speter     * apr_ino_t for LFS builds: */
85251875Speter    if (sizeof(apr_ino_t) >= sizeof(info->st_ino)
86251875Speter        || (apr_ino_t)info->st_ino == info->st_ino) {
87251875Speter        finfo->inode = info->st_ino;
88251875Speter    } else {
89251875Speter        finfo->valid &= ~APR_FINFO_INODE;
90251875Speter    }
91251875Speter
92251875Speter    apr_time_ansi_put(&finfo->atime, info->st_atime);
93251875Speter#ifdef HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC
94251875Speter    finfo->atime += info->st_atim.tv_nsec / APR_TIME_C(1000);
95251875Speter#elif defined(HAVE_STRUCT_STAT_ST_ATIMENSEC)
96251875Speter    finfo->atime += info->st_atimensec / APR_TIME_C(1000);
97251875Speter#elif defined(HAVE_STRUCT_STAT_ST_ATIME_N)
98269847Speter    finfo->atime += info->st_atime_n / APR_TIME_C(1000);
99251875Speter#endif
100251875Speter
101251875Speter    apr_time_ansi_put(&finfo->mtime, info->st_mtime);
102251875Speter#ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
103251875Speter    finfo->mtime += info->st_mtim.tv_nsec / APR_TIME_C(1000);
104251875Speter#elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC)
105251875Speter    finfo->mtime += info->st_mtimensec / APR_TIME_C(1000);
106251875Speter#elif defined(HAVE_STRUCT_STAT_ST_MTIME_N)
107269847Speter    finfo->mtime += info->st_mtime_n / APR_TIME_C(1000);
108251875Speter#endif
109251875Speter
110251875Speter    apr_time_ansi_put(&finfo->ctime, info->st_ctime);
111251875Speter#ifdef HAVE_STRUCT_STAT_ST_CTIM_TV_NSEC
112251875Speter    finfo->ctime += info->st_ctim.tv_nsec / APR_TIME_C(1000);
113251875Speter#elif defined(HAVE_STRUCT_STAT_ST_CTIMENSEC)
114251875Speter    finfo->ctime += info->st_ctimensec / APR_TIME_C(1000);
115251875Speter#elif defined(HAVE_STRUCT_STAT_ST_CTIME_N)
116251875Speter    finfo->ctime += info->st_ctime_n / APR_TIME_C(1000);
117251875Speter#endif
118251875Speter
119251875Speter#ifdef HAVE_STRUCT_STAT_ST_BLOCKS
120251875Speter#ifdef DEV_BSIZE
121251875Speter    finfo->csize = (apr_off_t)info->st_blocks * (apr_off_t)DEV_BSIZE;
122251875Speter#else
123251875Speter    finfo->csize = (apr_off_t)info->st_blocks * (apr_off_t)512;
124251875Speter#endif
125251875Speter    finfo->valid |= APR_FINFO_CSIZE;
126251875Speter#endif
127251875Speter}
128251875Speter
129251875Speterapr_status_t apr_file_info_get_locked(apr_finfo_t *finfo, apr_int32_t wanted,
130251875Speter                                      apr_file_t *thefile)
131251875Speter{
132251875Speter    struct_stat info;
133251875Speter
134251875Speter    if (thefile->buffered) {
135251875Speter        apr_status_t rv = apr_file_flush_locked(thefile);
136251875Speter        if (rv != APR_SUCCESS)
137251875Speter            return rv;
138251875Speter    }
139251875Speter
140251875Speter    if (fstat(thefile->filedes, &info) == 0) {
141251875Speter        finfo->pool = thefile->pool;
142251875Speter        finfo->fname = thefile->fname;
143251875Speter        fill_out_finfo(finfo, &info, wanted);
144251875Speter        return (wanted & ~finfo->valid) ? APR_INCOMPLETE : APR_SUCCESS;
145251875Speter    }
146251875Speter    else {
147251875Speter        return errno;
148251875Speter    }
149251875Speter}
150251875Speter
151251875SpeterAPR_DECLARE(apr_status_t) apr_file_info_get(apr_finfo_t *finfo,
152251875Speter                                            apr_int32_t wanted,
153251875Speter                                            apr_file_t *thefile)
154251875Speter{
155251875Speter    struct_stat info;
156251875Speter
157251875Speter    if (thefile->buffered) {
158251875Speter        apr_status_t rv = apr_file_flush(thefile);
159251875Speter        if (rv != APR_SUCCESS)
160251875Speter            return rv;
161251875Speter    }
162251875Speter
163251875Speter    if (fstat(thefile->filedes, &info) == 0) {
164251875Speter        finfo->pool = thefile->pool;
165251875Speter        finfo->fname = thefile->fname;
166251875Speter        fill_out_finfo(finfo, &info, wanted);
167251875Speter        return (wanted & ~finfo->valid) ? APR_INCOMPLETE : APR_SUCCESS;
168251875Speter    }
169251875Speter    else {
170251875Speter        return errno;
171251875Speter    }
172251875Speter}
173251875Speter
174251875SpeterAPR_DECLARE(apr_status_t) apr_file_perms_set(const char *fname,
175251875Speter                                             apr_fileperms_t perms)
176251875Speter{
177251875Speter    mode_t mode = apr_unix_perms2mode(perms);
178251875Speter
179251875Speter    if (chmod(fname, mode) == -1)
180251875Speter        return errno;
181251875Speter    return APR_SUCCESS;
182251875Speter}
183251875Speter
184251875SpeterAPR_DECLARE(apr_status_t) apr_file_attrs_set(const char *fname,
185251875Speter                                             apr_fileattrs_t attributes,
186251875Speter                                             apr_fileattrs_t attr_mask,
187251875Speter                                             apr_pool_t *pool)
188251875Speter{
189251875Speter    apr_status_t status;
190251875Speter    apr_finfo_t finfo;
191251875Speter
192251875Speter    /* Don't do anything if we can't handle the requested attributes */
193251875Speter    if (!(attr_mask & (APR_FILE_ATTR_READONLY
194251875Speter                       | APR_FILE_ATTR_EXECUTABLE)))
195251875Speter        return APR_SUCCESS;
196251875Speter
197251875Speter    status = apr_stat(&finfo, fname, APR_FINFO_PROT, pool);
198251875Speter    if (status)
199251875Speter        return status;
200251875Speter
201251875Speter    /* ### TODO: should added bits be umask'd? */
202251875Speter    if (attr_mask & APR_FILE_ATTR_READONLY)
203251875Speter    {
204251875Speter        if (attributes & APR_FILE_ATTR_READONLY)
205251875Speter        {
206251875Speter            finfo.protection &= ~APR_UWRITE;
207251875Speter            finfo.protection &= ~APR_GWRITE;
208251875Speter            finfo.protection &= ~APR_WWRITE;
209251875Speter        }
210251875Speter        else
211251875Speter        {
212251875Speter            /* ### umask this! */
213251875Speter            finfo.protection |= APR_UWRITE;
214251875Speter            finfo.protection |= APR_GWRITE;
215251875Speter            finfo.protection |= APR_WWRITE;
216251875Speter        }
217251875Speter    }
218251875Speter
219251875Speter    if (attr_mask & APR_FILE_ATTR_EXECUTABLE)
220251875Speter    {
221251875Speter        if (attributes & APR_FILE_ATTR_EXECUTABLE)
222251875Speter        {
223251875Speter            /* ### umask this! */
224251875Speter            finfo.protection |= APR_UEXECUTE;
225251875Speter            finfo.protection |= APR_GEXECUTE;
226251875Speter            finfo.protection |= APR_WEXECUTE;
227251875Speter        }
228251875Speter        else
229251875Speter        {
230251875Speter            finfo.protection &= ~APR_UEXECUTE;
231251875Speter            finfo.protection &= ~APR_GEXECUTE;
232251875Speter            finfo.protection &= ~APR_WEXECUTE;
233251875Speter        }
234251875Speter    }
235251875Speter
236251875Speter    return apr_file_perms_set(fname, finfo.protection);
237251875Speter}
238251875Speter
239251875Speter
240251875SpeterAPR_DECLARE(apr_status_t) apr_file_mtime_set(const char *fname,
241251875Speter                                              apr_time_t mtime,
242251875Speter                                              apr_pool_t *pool)
243251875Speter{
244251875Speter    apr_status_t status;
245251875Speter    apr_finfo_t finfo;
246251875Speter
247251875Speter    status = apr_stat(&finfo, fname, APR_FINFO_ATIME, pool);
248251875Speter    if (status) {
249251875Speter        return status;
250251875Speter    }
251251875Speter
252251875Speter#ifdef HAVE_UTIMES
253251875Speter    {
254251875Speter      struct timeval tvp[2];
255251875Speter
256251875Speter      tvp[0].tv_sec = apr_time_sec(finfo.atime);
257251875Speter      tvp[0].tv_usec = apr_time_usec(finfo.atime);
258251875Speter      tvp[1].tv_sec = apr_time_sec(mtime);
259251875Speter      tvp[1].tv_usec = apr_time_usec(mtime);
260251875Speter
261251875Speter      if (utimes(fname, tvp) == -1) {
262251875Speter        return errno;
263251875Speter      }
264251875Speter    }
265251875Speter#elif defined(HAVE_UTIME)
266251875Speter    {
267251875Speter      struct utimbuf buf;
268251875Speter
269251875Speter      buf.actime = (time_t) (finfo.atime / APR_USEC_PER_SEC);
270251875Speter      buf.modtime = (time_t) (mtime / APR_USEC_PER_SEC);
271251875Speter
272251875Speter      if (utime(fname, &buf) == -1) {
273251875Speter        return errno;
274251875Speter      }
275251875Speter    }
276251875Speter#else
277251875Speter    return APR_ENOTIMPL;
278251875Speter#endif
279251875Speter
280251875Speter    return APR_SUCCESS;
281251875Speter}
282251875Speter
283251875Speter
284251875SpeterAPR_DECLARE(apr_status_t) apr_stat(apr_finfo_t *finfo,
285251875Speter                                   const char *fname,
286251875Speter                                   apr_int32_t wanted, apr_pool_t *pool)
287251875Speter{
288251875Speter    struct_stat info;
289251875Speter    int srv;
290251875Speter
291251875Speter    if (wanted & APR_FINFO_LINK)
292251875Speter        srv = lstat(fname, &info);
293251875Speter    else
294251875Speter        srv = stat(fname, &info);
295251875Speter
296251875Speter    if (srv == 0) {
297251875Speter        finfo->pool = pool;
298251875Speter        finfo->fname = fname;
299251875Speter        fill_out_finfo(finfo, &info, wanted);
300251875Speter        if (wanted & APR_FINFO_LINK)
301251875Speter            wanted &= ~APR_FINFO_LINK;
302251875Speter        return (wanted & ~finfo->valid) ? APR_INCOMPLETE : APR_SUCCESS;
303251875Speter    }
304251875Speter    else {
305251875Speter#if !defined(ENOENT) || !defined(ENOTDIR)
306251875Speter#error ENOENT || ENOTDIR not defined; please see the
307251875Speter#error comments at this line in the source for a workaround.
308251875Speter        /*
309251875Speter         * If ENOENT || ENOTDIR is not defined in one of the your OS's
310251875Speter         * include files, APR cannot report a good reason why the stat()
311251875Speter         * of the file failed; there are cases where it can fail even though
312251875Speter         * the file exists.  This opens holes in Apache, for example, because
313251875Speter         * it becomes possible for someone to get a directory listing of a
314251875Speter         * directory even though there is an index (eg. index.html) file in
315251875Speter         * it.  If you do not have a problem with this, delete the above
316251875Speter         * #error lines and start the compile again.  If you need to do this,
317251875Speter         * please submit a bug report to http://www.apache.org/bug_report.html
318251875Speter         * letting us know that you needed to do this.  Please be sure to
319251875Speter         * include the operating system you are using.
320251875Speter         */
321251875Speter        /* WARNING: All errors will be handled as not found
322251875Speter         */
323251875Speter#if !defined(ENOENT)
324251875Speter        return APR_ENOENT;
325251875Speter#else
326251875Speter        /* WARNING: All errors but not found will be handled as not directory
327251875Speter         */
328251875Speter        if (errno != ENOENT)
329251875Speter            return APR_ENOENT;
330251875Speter        else
331251875Speter            return errno;
332251875Speter#endif
333251875Speter#else /* All was defined well, report the usual: */
334251875Speter        return errno;
335251875Speter#endif
336251875Speter    }
337251875Speter}
338251875Speter
339251875Speter
340