]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/apr/file_io/unix/filestat.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / contrib / apr / file_io / unix / filestat.c
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_arch_file_io.h"
18 #include "apr_file_io.h"
19 #include "apr_general.h"
20 #include "apr_strings.h"
21 #include "apr_errno.h"
22
23 #ifdef HAVE_UTIME
24 #include <utime.h>
25 #endif
26
27 static apr_filetype_e filetype_from_mode(mode_t mode)
28 {
29     apr_filetype_e type;
30
31     switch (mode & S_IFMT) {
32     case S_IFREG:
33         type = APR_REG;  break;
34     case S_IFDIR:
35         type = APR_DIR;  break;
36     case S_IFLNK:
37         type = APR_LNK;  break;
38     case S_IFCHR:
39         type = APR_CHR;  break;
40     case S_IFBLK:
41         type = APR_BLK;  break;
42 #if defined(S_IFFIFO)
43     case S_IFFIFO:
44         type = APR_PIPE; break;
45 #endif
46 #if !defined(BEOS) && defined(S_IFSOCK)
47     case S_IFSOCK:
48         type = APR_SOCK; break;
49 #endif
50
51     default:
52         /* Work around missing S_IFxxx values above
53          * for Linux et al.
54          */
55 #if !defined(S_IFFIFO) && defined(S_ISFIFO)
56         if (S_ISFIFO(mode)) {
57             type = APR_PIPE;
58         } else
59 #endif
60 #if !defined(BEOS) && !defined(S_IFSOCK) && defined(S_ISSOCK)
61         if (S_ISSOCK(mode)) {
62             type = APR_SOCK;
63         } else
64 #endif
65         type = APR_UNKFILE;
66     }
67     return type;
68 }
69
70 static void fill_out_finfo(apr_finfo_t *finfo, struct_stat *info,
71                            apr_int32_t wanted)
72
73     finfo->valid = APR_FINFO_MIN | APR_FINFO_IDENT | APR_FINFO_NLINK
74                  | APR_FINFO_OWNER | APR_FINFO_PROT;
75     finfo->protection = apr_unix_mode2perms(info->st_mode);
76     finfo->filetype = filetype_from_mode(info->st_mode);
77     finfo->user = info->st_uid;
78     finfo->group = info->st_gid;
79     finfo->size = info->st_size;
80     finfo->device = info->st_dev;
81     finfo->nlink = info->st_nlink;
82
83     /* Check for overflow if storing a 64-bit st_ino in a 32-bit
84      * apr_ino_t for LFS builds: */
85     if (sizeof(apr_ino_t) >= sizeof(info->st_ino)
86         || (apr_ino_t)info->st_ino == info->st_ino) {
87         finfo->inode = info->st_ino;
88     } else {
89         finfo->valid &= ~APR_FINFO_INODE;
90     }
91
92     apr_time_ansi_put(&finfo->atime, info->st_atime);
93 #ifdef HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC
94     finfo->atime += info->st_atim.tv_nsec / APR_TIME_C(1000);
95 #elif defined(HAVE_STRUCT_STAT_ST_ATIMENSEC)
96     finfo->atime += info->st_atimensec / APR_TIME_C(1000);
97 #elif defined(HAVE_STRUCT_STAT_ST_ATIME_N)
98     finfo->atime += info->st_atime_n / APR_TIME_C(1000);
99 #endif
100
101     apr_time_ansi_put(&finfo->mtime, info->st_mtime);
102 #ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
103     finfo->mtime += info->st_mtim.tv_nsec / APR_TIME_C(1000);
104 #elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC)
105     finfo->mtime += info->st_mtimensec / APR_TIME_C(1000);
106 #elif defined(HAVE_STRUCT_STAT_ST_MTIME_N)
107     finfo->mtime += info->st_mtime_n / APR_TIME_C(1000);
108 #endif
109
110     apr_time_ansi_put(&finfo->ctime, info->st_ctime);
111 #ifdef HAVE_STRUCT_STAT_ST_CTIM_TV_NSEC
112     finfo->ctime += info->st_ctim.tv_nsec / APR_TIME_C(1000);
113 #elif defined(HAVE_STRUCT_STAT_ST_CTIMENSEC)
114     finfo->ctime += info->st_ctimensec / APR_TIME_C(1000);
115 #elif defined(HAVE_STRUCT_STAT_ST_CTIME_N)
116     finfo->ctime += info->st_ctime_n / APR_TIME_C(1000);
117 #endif
118
119 #ifdef HAVE_STRUCT_STAT_ST_BLOCKS
120 #ifdef DEV_BSIZE
121     finfo->csize = (apr_off_t)info->st_blocks * (apr_off_t)DEV_BSIZE;
122 #else
123     finfo->csize = (apr_off_t)info->st_blocks * (apr_off_t)512;
124 #endif
125     finfo->valid |= APR_FINFO_CSIZE;
126 #endif
127 }
128
129 apr_status_t apr_file_info_get_locked(apr_finfo_t *finfo, apr_int32_t wanted,
130                                       apr_file_t *thefile)
131 {
132     struct_stat info;
133
134     if (thefile->buffered) {
135         apr_status_t rv = apr_file_flush_locked(thefile);
136         if (rv != APR_SUCCESS)
137             return rv;
138     }
139
140     if (fstat(thefile->filedes, &info) == 0) {
141         finfo->pool = thefile->pool;
142         finfo->fname = thefile->fname;
143         fill_out_finfo(finfo, &info, wanted);
144         return (wanted & ~finfo->valid) ? APR_INCOMPLETE : APR_SUCCESS;
145     }
146     else {
147         return errno;
148     }
149 }
150
151 APR_DECLARE(apr_status_t) apr_file_info_get(apr_finfo_t *finfo, 
152                                             apr_int32_t wanted,
153                                             apr_file_t *thefile)
154 {
155     struct_stat info;
156
157     if (thefile->buffered) {
158         apr_status_t rv = apr_file_flush(thefile);
159         if (rv != APR_SUCCESS)
160             return rv;
161     }
162
163     if (fstat(thefile->filedes, &info) == 0) {
164         finfo->pool = thefile->pool;
165         finfo->fname = thefile->fname;
166         fill_out_finfo(finfo, &info, wanted);
167         return (wanted & ~finfo->valid) ? APR_INCOMPLETE : APR_SUCCESS;
168     }
169     else {
170         return errno;
171     }
172 }
173
174 APR_DECLARE(apr_status_t) apr_file_perms_set(const char *fname, 
175                                              apr_fileperms_t perms)
176 {
177     mode_t mode = apr_unix_perms2mode(perms);
178
179     if (chmod(fname, mode) == -1)
180         return errno;
181     return APR_SUCCESS;
182 }
183
184 APR_DECLARE(apr_status_t) apr_file_attrs_set(const char *fname,
185                                              apr_fileattrs_t attributes,
186                                              apr_fileattrs_t attr_mask,
187                                              apr_pool_t *pool)
188 {
189     apr_status_t status;
190     apr_finfo_t finfo;
191
192     /* Don't do anything if we can't handle the requested attributes */
193     if (!(attr_mask & (APR_FILE_ATTR_READONLY
194                        | APR_FILE_ATTR_EXECUTABLE)))
195         return APR_SUCCESS;
196
197     status = apr_stat(&finfo, fname, APR_FINFO_PROT, pool);
198     if (status)
199         return status;
200
201     /* ### TODO: should added bits be umask'd? */
202     if (attr_mask & APR_FILE_ATTR_READONLY)
203     {
204         if (attributes & APR_FILE_ATTR_READONLY)
205         {
206             finfo.protection &= ~APR_UWRITE;
207             finfo.protection &= ~APR_GWRITE;
208             finfo.protection &= ~APR_WWRITE;
209         }
210         else
211         {
212             /* ### umask this! */
213             finfo.protection |= APR_UWRITE;
214             finfo.protection |= APR_GWRITE;
215             finfo.protection |= APR_WWRITE;
216         }
217     }
218
219     if (attr_mask & APR_FILE_ATTR_EXECUTABLE)
220     {
221         if (attributes & APR_FILE_ATTR_EXECUTABLE)
222         {
223             /* ### umask this! */
224             finfo.protection |= APR_UEXECUTE;
225             finfo.protection |= APR_GEXECUTE;
226             finfo.protection |= APR_WEXECUTE;
227         }
228         else
229         {
230             finfo.protection &= ~APR_UEXECUTE;
231             finfo.protection &= ~APR_GEXECUTE;
232             finfo.protection &= ~APR_WEXECUTE;
233         }
234     }
235
236     return apr_file_perms_set(fname, finfo.protection);
237 }
238
239
240 APR_DECLARE(apr_status_t) apr_file_mtime_set(const char *fname,
241                                               apr_time_t mtime,
242                                               apr_pool_t *pool)
243 {
244     apr_status_t status;
245     apr_finfo_t finfo;
246
247     status = apr_stat(&finfo, fname, APR_FINFO_ATIME, pool);
248     if (status) {
249         return status;
250     }
251
252 #ifdef HAVE_UTIMES
253     {
254       struct timeval tvp[2];
255     
256       tvp[0].tv_sec = apr_time_sec(finfo.atime);
257       tvp[0].tv_usec = apr_time_usec(finfo.atime);
258       tvp[1].tv_sec = apr_time_sec(mtime);
259       tvp[1].tv_usec = apr_time_usec(mtime);
260       
261       if (utimes(fname, tvp) == -1) {
262         return errno;
263       }
264     }
265 #elif defined(HAVE_UTIME)
266     {
267       struct utimbuf buf;
268       
269       buf.actime = (time_t) (finfo.atime / APR_USEC_PER_SEC);
270       buf.modtime = (time_t) (mtime / APR_USEC_PER_SEC);
271       
272       if (utime(fname, &buf) == -1) {
273         return errno;
274       }
275     }
276 #else
277     return APR_ENOTIMPL;
278 #endif
279
280     return APR_SUCCESS;
281 }
282
283
284 APR_DECLARE(apr_status_t) apr_stat(apr_finfo_t *finfo, 
285                                    const char *fname, 
286                                    apr_int32_t wanted, apr_pool_t *pool)
287 {
288     struct_stat info;
289     int srv;
290
291     if (wanted & APR_FINFO_LINK)
292         srv = lstat(fname, &info);
293     else
294         srv = stat(fname, &info);
295
296     if (srv == 0) {
297         finfo->pool = pool;
298         finfo->fname = fname;
299         fill_out_finfo(finfo, &info, wanted);
300         if (wanted & APR_FINFO_LINK)
301             wanted &= ~APR_FINFO_LINK;
302         return (wanted & ~finfo->valid) ? APR_INCOMPLETE : APR_SUCCESS;
303     }
304     else {
305 #if !defined(ENOENT) || !defined(ENOTDIR)
306 #error ENOENT || ENOTDIR not defined; please see the
307 #error comments at this line in the source for a workaround.
308         /*
309          * If ENOENT || ENOTDIR is not defined in one of the your OS's
310          * include files, APR cannot report a good reason why the stat()
311          * of the file failed; there are cases where it can fail even though
312          * the file exists.  This opens holes in Apache, for example, because
313          * it becomes possible for someone to get a directory listing of a 
314          * directory even though there is an index (eg. index.html) file in 
315          * it.  If you do not have a problem with this, delete the above 
316          * #error lines and start the compile again.  If you need to do this,
317          * please submit a bug report to http://www.apache.org/bug_report.html
318          * letting us know that you needed to do this.  Please be sure to 
319          * include the operating system you are using.
320          */
321         /* WARNING: All errors will be handled as not found
322          */
323 #if !defined(ENOENT) 
324         return APR_ENOENT;
325 #else
326         /* WARNING: All errors but not found will be handled as not directory
327          */
328         if (errno != ENOENT)
329             return APR_ENOENT;
330         else
331             return errno;
332 #endif
333 #else /* All was defined well, report the usual: */
334         return errno;
335 #endif
336     }
337 }
338
339