filestat.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  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. #include "fspr_arch_file_io.h"
  17. #include "fsio.h"
  18. #include "nks/dirio.h"
  19. #include "fspr_file_io.h"
  20. #include "fspr_general.h"
  21. #include "fspr_strings.h"
  22. #include "fspr_errno.h"
  23. #include "fspr_hash.h"
  24. #include "fspr_thread_rwlock.h"
  25. #ifdef HAVE_UTIME_H
  26. #include <utime.h>
  27. #endif
  28. #define APR_HAS_PSA
  29. static fspr_filetype_e filetype_from_mode(mode_t mode)
  30. {
  31. fspr_filetype_e type = APR_NOFILE;
  32. if (S_ISREG(mode))
  33. type = APR_REG;
  34. else if (S_ISDIR(mode))
  35. type = APR_DIR;
  36. else if (S_ISCHR(mode))
  37. type = APR_CHR;
  38. else if (S_ISBLK(mode))
  39. type = APR_BLK;
  40. else if (S_ISFIFO(mode))
  41. type = APR_PIPE;
  42. else if (S_ISLNK(mode))
  43. type = APR_LNK;
  44. else if (S_ISSOCK(mode))
  45. type = APR_SOCK;
  46. else
  47. type = APR_UNKFILE;
  48. return type;
  49. }
  50. static void fill_out_finfo(fspr_finfo_t *finfo, struct stat *info,
  51. fspr_int32_t wanted)
  52. {
  53. finfo->valid = APR_FINFO_MIN | APR_FINFO_IDENT | APR_FINFO_NLINK
  54. | APR_FINFO_OWNER | APR_FINFO_PROT;
  55. finfo->protection = fspr_unix_mode2perms(info->st_mode);
  56. finfo->filetype = filetype_from_mode(info->st_mode);
  57. finfo->user = info->st_uid;
  58. finfo->group = info->st_gid;
  59. finfo->size = info->st_size;
  60. finfo->inode = info->st_ino;
  61. finfo->device = info->st_dev;
  62. finfo->nlink = info->st_nlink;
  63. fspr_time_ansi_put(&finfo->atime, info->st_atime.tv_sec);
  64. fspr_time_ansi_put(&finfo->mtime, info->st_mtime.tv_sec);
  65. fspr_time_ansi_put(&finfo->ctime, info->st_ctime.tv_sec);
  66. /* ### needs to be revisited
  67. * if (wanted & APR_FINFO_CSIZE) {
  68. * finfo->csize = info->st_blocks * 512;
  69. * finfo->valid |= APR_FINFO_CSIZE;
  70. * }
  71. */
  72. }
  73. APR_DECLARE(fspr_status_t) fspr_file_info_get(fspr_finfo_t *finfo,
  74. fspr_int32_t wanted,
  75. fspr_file_t *thefile)
  76. {
  77. struct stat info;
  78. if (thefile->buffered) {
  79. fspr_status_t rv = fspr_file_flush(thefile);
  80. if (rv != APR_SUCCESS)
  81. return rv;
  82. }
  83. if (fstat(thefile->filedes, &info) == 0) {
  84. finfo->pool = thefile->pool;
  85. finfo->fname = thefile->fname;
  86. fill_out_finfo(finfo, &info, wanted);
  87. return (wanted & ~finfo->valid) ? APR_INCOMPLETE : APR_SUCCESS;
  88. }
  89. else {
  90. return errno;
  91. }
  92. }
  93. APR_DECLARE(fspr_status_t) fspr_file_perms_set(const char *fname,
  94. fspr_fileperms_t perms)
  95. {
  96. mode_t mode = fspr_unix_perms2mode(perms);
  97. if (chmod(fname, mode) == -1)
  98. return errno;
  99. return APR_SUCCESS;
  100. }
  101. APR_DECLARE(fspr_status_t) fspr_file_attrs_set(const char *fname,
  102. fspr_fileattrs_t attributes,
  103. fspr_fileattrs_t attr_mask,
  104. fspr_pool_t *pool)
  105. {
  106. fspr_status_t status;
  107. fspr_finfo_t finfo;
  108. /* Don't do anything if we can't handle the requested attributes */
  109. if (!(attr_mask & (APR_FILE_ATTR_READONLY
  110. | APR_FILE_ATTR_EXECUTABLE)))
  111. return APR_SUCCESS;
  112. status = fspr_stat(&finfo, fname, APR_FINFO_PROT, pool);
  113. if (status)
  114. return status;
  115. /* ### TODO: should added bits be umask'd? */
  116. if (attr_mask & APR_FILE_ATTR_READONLY)
  117. {
  118. if (attributes & APR_FILE_ATTR_READONLY)
  119. {
  120. finfo.protection &= ~APR_UWRITE;
  121. finfo.protection &= ~APR_GWRITE;
  122. finfo.protection &= ~APR_WWRITE;
  123. }
  124. else
  125. {
  126. /* ### umask this! */
  127. finfo.protection |= APR_UWRITE;
  128. finfo.protection |= APR_GWRITE;
  129. finfo.protection |= APR_WWRITE;
  130. }
  131. }
  132. if (attr_mask & APR_FILE_ATTR_EXECUTABLE)
  133. {
  134. if (attributes & APR_FILE_ATTR_EXECUTABLE)
  135. {
  136. /* ### umask this! */
  137. finfo.protection |= APR_UEXECUTE;
  138. finfo.protection |= APR_GEXECUTE;
  139. finfo.protection |= APR_WEXECUTE;
  140. }
  141. else
  142. {
  143. finfo.protection &= ~APR_UEXECUTE;
  144. finfo.protection &= ~APR_GEXECUTE;
  145. finfo.protection &= ~APR_WEXECUTE;
  146. }
  147. }
  148. return fspr_file_perms_set(fname, finfo.protection);
  149. }
  150. #ifndef APR_HAS_PSA
  151. static fspr_status_t stat_cache_cleanup(void *data)
  152. {
  153. fspr_pool_t *p = (fspr_pool_t *)getGlobalPool();
  154. fspr_hash_index_t *hi;
  155. fspr_hash_t *statCache = (fspr_hash_t*)data;
  156. char *key;
  157. fspr_ssize_t keylen;
  158. NXPathCtx_t pathctx;
  159. for (hi = fspr_hash_first(p, statCache); hi; hi = fspr_hash_next(hi)) {
  160. fspr_hash_this(hi, (const void**)&key, &keylen, (void**)&pathctx);
  161. if (pathctx) {
  162. NXFreePathContext(pathctx);
  163. }
  164. }
  165. return APR_SUCCESS;
  166. }
  167. int cstat (NXPathCtx_t ctx, char *path, struct stat *buf, unsigned long requestmap, fspr_pool_t *p)
  168. {
  169. fspr_pool_t *gPool = (fspr_pool_t *)getGlobalPool();
  170. fspr_hash_t *statCache = NULL;
  171. fspr_thread_rwlock_t *rwlock = NULL;
  172. NXPathCtx_t pathctx = 0;
  173. char *ptr = NULL, *tr;
  174. int len = 0, x;
  175. char *ppath;
  176. char *pinfo;
  177. if (ctx == 1) {
  178. /* If there isn't a global pool then just stat the file
  179. and return */
  180. if (!gPool) {
  181. char poolname[50];
  182. if (fspr_pool_create(&gPool, NULL) != APR_SUCCESS) {
  183. return getstat(ctx, path, buf, requestmap);
  184. }
  185. setGlobalPool(gPool);
  186. fspr_pool_tag(gPool, fspr_pstrdup(gPool, "cstat_mem_pool"));
  187. statCache = fspr_hash_make(gPool);
  188. fspr_pool_userdata_set ((void*)statCache, "STAT_CACHE", stat_cache_cleanup, gPool);
  189. fspr_thread_rwlock_create(&rwlock, gPool);
  190. fspr_pool_userdata_set ((void*)rwlock, "STAT_CACHE_LOCK", fspr_pool_cleanup_null, gPool);
  191. }
  192. else {
  193. fspr_pool_userdata_get((void**)&statCache, "STAT_CACHE", gPool);
  194. fspr_pool_userdata_get((void**)&rwlock, "STAT_CACHE_LOCK", gPool);
  195. }
  196. if (!gPool || !statCache || !rwlock) {
  197. return getstat(ctx, path, buf, requestmap);
  198. }
  199. for (x = 0,tr = path;*tr != '\0';tr++,x++) {
  200. if (*tr == '\\' || *tr == '/') {
  201. ptr = tr;
  202. len = x;
  203. }
  204. if (*tr == ':') {
  205. ptr = "\\";
  206. len = x;
  207. }
  208. }
  209. if (ptr) {
  210. ppath = fspr_pstrndup (p, path, len);
  211. strlwr(ppath);
  212. if (ptr[1] != '\0') {
  213. ptr++;
  214. }
  215. /* If the path ended in a trailing slash then our result path
  216. will be a single slash. To avoid stat'ing the root with a
  217. slash, we need to make sure we stat the current directory
  218. with a dot */
  219. if (((*ptr == '/') || (*ptr == '\\')) && (*(ptr+1) == '\0')) {
  220. pinfo = fspr_pstrdup (p, ".");
  221. }
  222. else {
  223. pinfo = fspr_pstrdup (p, ptr);
  224. }
  225. }
  226. /* If we have a statCache then try to pull the information
  227. from the cache. Otherwise just stat the file and return.*/
  228. if (statCache) {
  229. fspr_thread_rwlock_rdlock(rwlock);
  230. pathctx = (NXPathCtx_t) fspr_hash_get(statCache, ppath, APR_HASH_KEY_STRING);
  231. fspr_thread_rwlock_unlock(rwlock);
  232. if (pathctx) {
  233. return getstat(pathctx, pinfo, buf, requestmap);
  234. }
  235. else {
  236. int err;
  237. err = NXCreatePathContext(0, ppath, 0, NULL, &pathctx);
  238. if (!err) {
  239. fspr_thread_rwlock_wrlock(rwlock);
  240. fspr_hash_set(statCache, fspr_pstrdup(gPool,ppath) , APR_HASH_KEY_STRING, (void*)pathctx);
  241. fspr_thread_rwlock_unlock(rwlock);
  242. return getstat(pathctx, pinfo, buf, requestmap);
  243. }
  244. }
  245. }
  246. }
  247. return getstat(ctx, path, buf, requestmap);
  248. }
  249. #endif
  250. APR_DECLARE(fspr_status_t) fspr_stat(fspr_finfo_t *finfo,
  251. const char *fname,
  252. fspr_int32_t wanted, fspr_pool_t *pool)
  253. {
  254. struct stat info;
  255. int srv;
  256. NXPathCtx_t pathCtx = 0;
  257. getcwdpath(NULL, &pathCtx, CTX_ACTUAL_CWD);
  258. #ifdef APR_HAS_PSA
  259. srv = getstat(pathCtx, (char*)fname, &info, ST_STAT_BITS|ST_NAME_BIT);
  260. #else
  261. srv = cstat(pathCtx, (char*)fname, &info, ST_STAT_BITS|ST_NAME_BIT, pool);
  262. #endif
  263. errno = srv;
  264. if (srv == 0) {
  265. finfo->pool = pool;
  266. finfo->fname = fname;
  267. fill_out_finfo(finfo, &info, wanted);
  268. if (wanted & APR_FINFO_LINK)
  269. wanted &= ~APR_FINFO_LINK;
  270. if (wanted & APR_FINFO_NAME) {
  271. finfo->name = fspr_pstrdup(pool, info.st_name);
  272. finfo->valid |= APR_FINFO_NAME;
  273. }
  274. return (wanted & ~finfo->valid) ? APR_INCOMPLETE : APR_SUCCESS;
  275. }
  276. else {
  277. #if !defined(ENOENT) || !defined(ENOTDIR)
  278. #error ENOENT || ENOTDIR not defined; please see the
  279. #error comments at this line in the source for a workaround.
  280. /*
  281. * If ENOENT || ENOTDIR is not defined in one of the your OS's
  282. * include files, APR cannot report a good reason why the stat()
  283. * of the file failed; there are cases where it can fail even though
  284. * the file exists. This opens holes in Apache, for example, because
  285. * it becomes possible for someone to get a directory listing of a
  286. * directory even though there is an index (eg. index.html) file in
  287. * it. If you do not have a problem with this, delete the above
  288. * #error lines and start the compile again. If you need to do this,
  289. * please submit a bug report to http://www.apache.org/bug_report.html
  290. * letting us know that you needed to do this. Please be sure to
  291. * include the operating system you are using.
  292. */
  293. /* WARNING: All errors will be handled as not found
  294. */
  295. #if !defined(ENOENT)
  296. return APR_ENOENT;
  297. #else
  298. /* WARNING: All errors but not found will be handled as not directory
  299. */
  300. if (errno != ENOENT)
  301. return APR_ENOENT;
  302. else
  303. return errno;
  304. #endif
  305. #else /* All was defined well, report the usual: */
  306. return errno;
  307. #endif
  308. }
  309. }
  310. APR_DECLARE(fspr_status_t) fspr_file_mtime_set(const char *fname,
  311. fspr_time_t mtime,
  312. fspr_pool_t *pool)
  313. {
  314. fspr_status_t status;
  315. fspr_finfo_t finfo;
  316. status = fspr_stat(&finfo, fname, APR_FINFO_ATIME, pool);
  317. if (status) {
  318. return status;
  319. }
  320. #ifdef HAVE_UTIMES
  321. {
  322. struct timeval tvp[2];
  323. tvp[0].tv_sec = fspr_time_sec(finfo.atime);
  324. tvp[0].tv_usec = fspr_time_usec(finfo.atime);
  325. tvp[1].tv_sec = fspr_time_sec(mtime);
  326. tvp[1].tv_usec = fspr_time_usec(mtime);
  327. if (utimes(fname, tvp) == -1) {
  328. return errno;
  329. }
  330. }
  331. #elif defined(HAVE_UTIME)
  332. {
  333. struct utimbuf buf;
  334. buf.actime = (time_t) (finfo.atime / APR_USEC_PER_SEC);
  335. buf.modtime = (time_t) (mtime / APR_USEC_PER_SEC);
  336. if (utime(fname, &buf) == -1) {
  337. return errno;
  338. }
  339. }
  340. #else
  341. return APR_ENOTIMPL;
  342. #endif
  343. return APR_SUCCESS;
  344. }