/src/httpd/srclib/apr/file_io/unix/filestat.c
Line | Count | Source (jump to first uncovered line) |
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 | 1.26k | { |
29 | 1.26k | apr_filetype_e type; |
30 | | |
31 | 1.26k | switch (mode & S_IFMT) { |
32 | 1.26k | case S_IFREG: |
33 | 1.26k | type = APR_REG; break; |
34 | 0 | case S_IFDIR: |
35 | 0 | type = APR_DIR; break; |
36 | 0 | case S_IFLNK: |
37 | 0 | type = APR_LNK; break; |
38 | 0 | case S_IFCHR: |
39 | 0 | type = APR_CHR; break; |
40 | 0 | case S_IFBLK: |
41 | 0 | type = APR_BLK; break; |
42 | | #if defined(S_IFFIFO) |
43 | | case S_IFFIFO: |
44 | | type = APR_PIPE; break; |
45 | | #endif |
46 | 0 | #if !defined(BEOS) && defined(S_IFSOCK) |
47 | 0 | case S_IFSOCK: |
48 | 0 | type = APR_SOCK; break; |
49 | 0 | #endif |
50 | | |
51 | 0 | default: |
52 | | /* Work around missing S_IFxxx values above |
53 | | * for Linux et al. |
54 | | */ |
55 | 0 | #if !defined(S_IFFIFO) && defined(S_ISFIFO) |
56 | 0 | if (S_ISFIFO(mode)) { |
57 | 0 | type = APR_PIPE; |
58 | 0 | } else |
59 | 0 | #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 | 0 | type = APR_UNKFILE; |
66 | 1.26k | } |
67 | 1.26k | return type; |
68 | 1.26k | } |
69 | | |
70 | | static void fill_out_finfo(apr_finfo_t *finfo, struct_stat *info, |
71 | | apr_int32_t wanted) |
72 | 1.26k | { |
73 | 1.26k | finfo->valid = APR_FINFO_MIN | APR_FINFO_IDENT | APR_FINFO_NLINK |
74 | 1.26k | | APR_FINFO_OWNER | APR_FINFO_PROT; |
75 | 1.26k | finfo->protection = apr_unix_mode2perms(info->st_mode); |
76 | 1.26k | finfo->filetype = filetype_from_mode(info->st_mode); |
77 | 1.26k | finfo->user = info->st_uid; |
78 | 1.26k | finfo->group = info->st_gid; |
79 | 1.26k | finfo->size = info->st_size; |
80 | 1.26k | finfo->device = info->st_dev; |
81 | 1.26k | 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 | 1.26k | if (sizeof(apr_ino_t) >= sizeof(info->st_ino) |
86 | 1.26k | || (apr_ino_t)info->st_ino == info->st_ino) { |
87 | 1.26k | finfo->inode = info->st_ino; |
88 | 1.26k | } else { |
89 | 0 | finfo->valid &= ~APR_FINFO_INODE; |
90 | 0 | } |
91 | | |
92 | 1.26k | apr_time_ansi_put(&finfo->atime, info->st_atime); |
93 | 1.26k | #ifdef HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC |
94 | 1.26k | 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 | 1.26k | apr_time_ansi_put(&finfo->mtime, info->st_mtime); |
102 | 1.26k | #ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC |
103 | 1.26k | 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 | 1.26k | apr_time_ansi_put(&finfo->ctime, info->st_ctime); |
111 | 1.26k | #ifdef HAVE_STRUCT_STAT_ST_CTIM_TV_NSEC |
112 | 1.26k | 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 | 1.26k | #ifdef HAVE_STRUCT_STAT_ST_BLOCKS |
120 | 1.26k | #ifdef DEV_BSIZE |
121 | 1.26k | 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 | 1.26k | finfo->valid |= APR_FINFO_CSIZE; |
126 | 1.26k | #endif |
127 | 1.26k | } |
128 | | |
129 | | apr_status_t apr_file_info_get_locked(apr_finfo_t *finfo, apr_int32_t wanted, |
130 | | apr_file_t *thefile) |
131 | 0 | { |
132 | 0 | struct_stat info; |
133 | |
|
134 | 0 | if (thefile->buffered) { |
135 | 0 | apr_status_t rv = apr_file_flush_locked(thefile); |
136 | 0 | if (rv != APR_SUCCESS) |
137 | 0 | return rv; |
138 | 0 | } |
139 | | |
140 | 0 | if (fstat(thefile->filedes, &info) == 0) { |
141 | 0 | finfo->pool = thefile->pool; |
142 | 0 | finfo->fname = thefile->fname; |
143 | 0 | fill_out_finfo(finfo, &info, wanted); |
144 | 0 | return (wanted & ~finfo->valid) ? APR_INCOMPLETE : APR_SUCCESS; |
145 | 0 | } |
146 | 0 | else { |
147 | 0 | return errno; |
148 | 0 | } |
149 | 0 | } |
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 | 1.26k | { |
155 | 1.26k | struct_stat info; |
156 | | |
157 | 1.26k | if (thefile->buffered) { |
158 | 1.26k | apr_status_t rv = apr_file_flush(thefile); |
159 | 1.26k | if (rv != APR_SUCCESS) |
160 | 0 | return rv; |
161 | 1.26k | } |
162 | | |
163 | 1.26k | if (fstat(thefile->filedes, &info) == 0) { |
164 | 1.26k | finfo->pool = thefile->pool; |
165 | 1.26k | finfo->fname = thefile->fname; |
166 | 1.26k | fill_out_finfo(finfo, &info, wanted); |
167 | 1.26k | return (wanted & ~finfo->valid) ? APR_INCOMPLETE : APR_SUCCESS; |
168 | 1.26k | } |
169 | 0 | else { |
170 | 0 | return errno; |
171 | 0 | } |
172 | 1.26k | } |
173 | | |
174 | | APR_DECLARE(apr_status_t) apr_file_perms_set(const char *fname, |
175 | | apr_fileperms_t perms) |
176 | 0 | { |
177 | 0 | mode_t mode = apr_unix_perms2mode(perms); |
178 | |
|
179 | 0 | if (chmod(fname, mode) == -1) |
180 | 0 | return errno; |
181 | 0 | return APR_SUCCESS; |
182 | 0 | } |
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 | 0 | { |
189 | 0 | apr_status_t status; |
190 | 0 | apr_finfo_t finfo; |
191 | | |
192 | | /* Don't do anything if we can't handle the requested attributes */ |
193 | 0 | if (!(attr_mask & (APR_FILE_ATTR_READONLY |
194 | 0 | | APR_FILE_ATTR_EXECUTABLE))) |
195 | 0 | return APR_SUCCESS; |
196 | | |
197 | 0 | status = apr_stat(&finfo, fname, APR_FINFO_PROT, pool); |
198 | 0 | if (status) |
199 | 0 | return status; |
200 | | |
201 | | /* ### TODO: should added bits be umask'd? */ |
202 | 0 | if (attr_mask & APR_FILE_ATTR_READONLY) |
203 | 0 | { |
204 | 0 | if (attributes & APR_FILE_ATTR_READONLY) |
205 | 0 | { |
206 | 0 | finfo.protection &= ~APR_FPROT_UWRITE; |
207 | 0 | finfo.protection &= ~APR_FPROT_GWRITE; |
208 | 0 | finfo.protection &= ~APR_FPROT_WWRITE; |
209 | 0 | } |
210 | 0 | else |
211 | 0 | { |
212 | | /* ### umask this! */ |
213 | 0 | finfo.protection |= APR_FPROT_UWRITE; |
214 | 0 | finfo.protection |= APR_FPROT_GWRITE; |
215 | 0 | finfo.protection |= APR_FPROT_WWRITE; |
216 | 0 | } |
217 | 0 | } |
218 | |
|
219 | 0 | if (attr_mask & APR_FILE_ATTR_EXECUTABLE) |
220 | 0 | { |
221 | 0 | if (attributes & APR_FILE_ATTR_EXECUTABLE) |
222 | 0 | { |
223 | | /* ### umask this! */ |
224 | 0 | finfo.protection |= APR_FPROT_UEXECUTE; |
225 | 0 | finfo.protection |= APR_FPROT_GEXECUTE; |
226 | 0 | finfo.protection |= APR_FPROT_WEXECUTE; |
227 | 0 | } |
228 | 0 | else |
229 | 0 | { |
230 | 0 | finfo.protection &= ~APR_FPROT_UEXECUTE; |
231 | 0 | finfo.protection &= ~APR_FPROT_GEXECUTE; |
232 | 0 | finfo.protection &= ~APR_FPROT_WEXECUTE; |
233 | 0 | } |
234 | 0 | } |
235 | |
|
236 | 0 | return apr_file_perms_set(fname, finfo.protection); |
237 | 0 | } |
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 | 0 | { |
244 | 0 | apr_status_t status; |
245 | 0 | apr_finfo_t finfo; |
246 | |
|
247 | 0 | status = apr_stat(&finfo, fname, APR_FINFO_ATIME, pool); |
248 | 0 | if (status) { |
249 | 0 | return status; |
250 | 0 | } |
251 | | |
252 | 0 | #ifdef HAVE_UTIMES |
253 | 0 | { |
254 | 0 | struct timeval tvp[2]; |
255 | |
|
256 | 0 | tvp[0].tv_sec = apr_time_sec(finfo.atime); |
257 | 0 | tvp[0].tv_usec = apr_time_usec(finfo.atime); |
258 | 0 | tvp[1].tv_sec = apr_time_sec(mtime); |
259 | 0 | tvp[1].tv_usec = apr_time_usec(mtime); |
260 | |
|
261 | 0 | if (utimes(fname, tvp) == -1) { |
262 | 0 | return errno; |
263 | 0 | } |
264 | 0 | } |
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 | 0 | return APR_SUCCESS; |
281 | 0 | } |
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 | 0 | { |
288 | 0 | struct_stat info; |
289 | 0 | int srv; |
290 | |
|
291 | 0 | if (wanted & APR_FINFO_LINK) |
292 | 0 | srv = lstat(fname, &info); |
293 | 0 | else |
294 | 0 | srv = stat(fname, &info); |
295 | |
|
296 | 0 | if (srv == 0) { |
297 | 0 | finfo->pool = pool; |
298 | 0 | finfo->fname = fname; |
299 | 0 | fill_out_finfo(finfo, &info, wanted); |
300 | 0 | if (wanted & APR_FINFO_LINK) |
301 | 0 | wanted &= ~APR_FINFO_LINK; |
302 | 0 | return (wanted & ~finfo->valid) ? APR_INCOMPLETE : APR_SUCCESS; |
303 | 0 | } |
304 | 0 | 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 | 0 | return errno; |
335 | 0 | #endif |
336 | 0 | } |
337 | 0 | } |
338 | | |
339 | | |