2
0

open.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635
  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_private.h"
  17. #include "fspr_arch_file_io.h"
  18. #include "fspr_file_io.h"
  19. #include "fspr_general.h"
  20. #include "fspr_strings.h"
  21. #include "fspr_portable.h"
  22. #include "fspr_thread_mutex.h"
  23. #if APR_HAVE_ERRNO_H
  24. #include <errno.h>
  25. #endif
  26. #include <winbase.h>
  27. #include <string.h>
  28. #if APR_HAVE_SYS_STAT_H
  29. #include <sys/stat.h>
  30. #endif
  31. #include "fspr_arch_misc.h"
  32. #include "fspr_arch_inherit.h"
  33. #if APR_HAS_UNICODE_FS
  34. fspr_status_t utf8_to_unicode_path(fspr_wchar_t* retstr, fspr_size_t retlen,
  35. const char* srcstr)
  36. {
  37. /* TODO: The computations could preconvert the string to determine
  38. * the true size of the retstr, but that's a memory over speed
  39. * tradeoff that isn't appropriate this early in development.
  40. *
  41. * Allocate the maximum string length based on leading 4
  42. * characters of \\?\ (allowing nearly unlimited path lengths)
  43. * plus the trailing null, then transform /'s into \\'s since
  44. * the \\?\ form doesn't allow '/' path seperators.
  45. *
  46. * Note that the \\?\ form only works for local drive paths, and
  47. * \\?\UNC\ is needed UNC paths.
  48. */
  49. fspr_size_t srcremains = strlen(srcstr) + 1;
  50. fspr_wchar_t *t = retstr;
  51. fspr_status_t rv;
  52. /* This is correct, we don't twist the filename if it is will
  53. * definately be shorter than MAX_PATH. It merits some
  54. * performance testing to see if this has any effect, but there
  55. * seem to be applications that get confused by the resulting
  56. * Unicode \\?\ style file names, especially if they use argv[0]
  57. * or call the Win32 API functions such as GetModuleName, etc.
  58. * Not every application is prepared to handle such names.
  59. *
  60. * Note that a utf-8 name can never result in more wide chars
  61. * than the original number of utf-8 narrow chars.
  62. */
  63. if (srcremains > MAX_PATH) {
  64. if (srcstr[1] == ':' && (srcstr[2] == '/' || srcstr[2] == '\\')) {
  65. wcscpy (retstr, L"\\\\?\\");
  66. retlen -= 4;
  67. t += 4;
  68. }
  69. else if ((srcstr[0] == '/' || srcstr[0] == '\\')
  70. && (srcstr[1] == '/' || srcstr[1] == '\\')
  71. && (srcstr[2] != '?')) {
  72. /* Skip the slashes */
  73. srcstr += 2;
  74. srcremains -= 2;
  75. wcscpy (retstr, L"\\\\?\\UNC\\");
  76. retlen -= 8;
  77. t += 8;
  78. }
  79. }
  80. if (rv = fspr_conv_utf8_to_ucs2(srcstr, &srcremains, t, &retlen)) {
  81. return (rv == APR_INCOMPLETE) ? APR_EINVAL : rv;
  82. }
  83. if (srcremains) {
  84. return APR_ENAMETOOLONG;
  85. }
  86. for (; *t; ++t)
  87. if (*t == L'/')
  88. *t = L'\\';
  89. return APR_SUCCESS;
  90. }
  91. fspr_status_t unicode_to_utf8_path(char* retstr, fspr_size_t retlen,
  92. const fspr_wchar_t* srcstr)
  93. {
  94. /* Skip the leading 4 characters if the path begins \\?\, or substitute
  95. * // for the \\?\UNC\ path prefix, allocating the maximum string
  96. * length based on the remaining string, plus the trailing null.
  97. * then transform \\'s back into /'s since the \\?\ form never
  98. * allows '/' path seperators, and APR always uses '/'s.
  99. */
  100. fspr_size_t srcremains = wcslen(srcstr) + 1;
  101. fspr_status_t rv;
  102. char *t = retstr;
  103. if (srcstr[0] == L'\\' && srcstr[1] == L'\\' &&
  104. srcstr[2] == L'?' && srcstr[3] == L'\\') {
  105. if (srcstr[4] == L'U' && srcstr[5] == L'N' &&
  106. srcstr[6] == L'C' && srcstr[7] == L'\\') {
  107. srcremains -= 8;
  108. srcstr += 8;
  109. retstr[0] = '\\';
  110. retstr[1] = '\\';
  111. retlen -= 2;
  112. t += 2;
  113. }
  114. else {
  115. srcremains -= 4;
  116. srcstr += 4;
  117. }
  118. }
  119. if (rv = fspr_conv_ucs2_to_utf8(srcstr, &srcremains, t, &retlen)) {
  120. return rv;
  121. }
  122. if (srcremains) {
  123. return APR_ENAMETOOLONG;
  124. }
  125. return APR_SUCCESS;
  126. }
  127. #endif
  128. void *res_name_from_filename(const char *file, int global, fspr_pool_t *pool)
  129. {
  130. #if APR_HAS_UNICODE_FS
  131. IF_WIN_OS_IS_UNICODE
  132. {
  133. fspr_wchar_t *wpre, *wfile, *ch;
  134. fspr_size_t n = strlen(file) + 1;
  135. fspr_size_t r, d;
  136. fspr_status_t rv;
  137. if (fspr_os_level >= APR_WIN_2000) {
  138. if (global)
  139. wpre = L"Global\\";
  140. else
  141. wpre = L"Local\\";
  142. }
  143. else
  144. wpre = L"";
  145. r = wcslen(wpre);
  146. if (n > 256 - r) {
  147. file += n - 256 - r;
  148. n = 256;
  149. /* skip utf8 continuation bytes */
  150. while ((*file & 0xC0) == 0x80) {
  151. ++file;
  152. --n;
  153. }
  154. }
  155. wfile = fspr_palloc(pool, (r + n) * sizeof(fspr_wchar_t));
  156. wcscpy(wfile, wpre);
  157. d = n;
  158. if (rv = fspr_conv_utf8_to_ucs2(file, &n, wfile + r, &d)) {
  159. return NULL;
  160. }
  161. for (ch = wfile + r; *ch; ++ch) {
  162. if (*ch == ':' || *ch == '/' || *ch == '\\')
  163. *ch = '_';
  164. }
  165. return wfile;
  166. }
  167. #endif
  168. #if APR_HAS_ANSI_FS
  169. ELSE_WIN_OS_IS_ANSI
  170. {
  171. char *nfile, *ch;
  172. fspr_size_t n = strlen(file) + 1;
  173. #if !APR_HAS_UNICODE_FS
  174. fspr_status_t rv;
  175. fspr_size_t r, d;
  176. char *pre;
  177. if (fspr_os_level >= APR_WIN_2000) {
  178. if (global)
  179. pre = "Global\\";
  180. else
  181. pre = "Local\\";
  182. }
  183. else
  184. pre = "";
  185. r = strlen(pre);
  186. if (n > 256 - r) {
  187. file += n - 256 - r;
  188. n = 256;
  189. }
  190. nfile = fspr_palloc(pool, (r + n) * sizeof(fspr_wchar_t));
  191. memcpy(nfile, pre, r);
  192. memcpy(nfile + r, file, n);
  193. #else
  194. const fspr_size_t r = 0;
  195. if (n > 256) {
  196. file += n - 256;
  197. n = 256;
  198. }
  199. nfile = fspr_pmemdup(pool, file, n);
  200. #endif
  201. for (ch = nfile + r; *ch; ++ch) {
  202. if (*ch == ':' || *ch == '/' || *ch == '\\')
  203. *ch = '_';
  204. }
  205. return nfile;
  206. }
  207. #endif
  208. }
  209. fspr_status_t file_cleanup(void *thefile)
  210. {
  211. fspr_file_t *file = thefile;
  212. fspr_status_t flush_rv = APR_SUCCESS;
  213. if (file->filehand != INVALID_HANDLE_VALUE) {
  214. /* In order to avoid later segfaults with handle 'reuse',
  215. * we must protect against the case that a dup2'ed handle
  216. * is being closed, and invalidate the corresponding StdHandle
  217. */
  218. if (file->filehand == GetStdHandle(STD_ERROR_HANDLE)) {
  219. SetStdHandle(STD_ERROR_HANDLE, INVALID_HANDLE_VALUE);
  220. }
  221. if (file->filehand == GetStdHandle(STD_OUTPUT_HANDLE)) {
  222. SetStdHandle(STD_OUTPUT_HANDLE, INVALID_HANDLE_VALUE);
  223. }
  224. if (file->filehand == GetStdHandle(STD_INPUT_HANDLE)) {
  225. SetStdHandle(STD_INPUT_HANDLE, INVALID_HANDLE_VALUE);
  226. }
  227. if (file->buffered) {
  228. /* XXX: flush here is not mutex protected */
  229. flush_rv = fspr_file_flush((fspr_file_t *)thefile);
  230. }
  231. CloseHandle(file->filehand);
  232. file->filehand = INVALID_HANDLE_VALUE;
  233. }
  234. if (file->pOverlapped && file->pOverlapped->hEvent) {
  235. CloseHandle(file->pOverlapped->hEvent);
  236. file->pOverlapped = NULL;
  237. }
  238. return flush_rv;
  239. }
  240. APR_DECLARE(fspr_status_t) fspr_file_open(fspr_file_t **new, const char *fname,
  241. fspr_int32_t flag, fspr_fileperms_t perm,
  242. fspr_pool_t *pool)
  243. {
  244. HANDLE handle = INVALID_HANDLE_VALUE;
  245. DWORD oflags = 0;
  246. DWORD createflags = 0;
  247. DWORD attributes = 0;
  248. DWORD sharemode = FILE_SHARE_READ | FILE_SHARE_WRITE;
  249. fspr_status_t rv;
  250. if (flag & APR_READ) {
  251. oflags |= GENERIC_READ;
  252. }
  253. if (flag & APR_WRITE) {
  254. oflags |= GENERIC_WRITE;
  255. }
  256. if (flag & APR_WRITEATTRS) {
  257. oflags |= FILE_WRITE_ATTRIBUTES;
  258. }
  259. if (fspr_os_level >= APR_WIN_NT)
  260. sharemode |= FILE_SHARE_DELETE;
  261. if (flag & APR_CREATE) {
  262. if (flag & APR_EXCL) {
  263. /* only create new if file does not already exist */
  264. createflags = CREATE_NEW;
  265. } else if (flag & APR_TRUNCATE) {
  266. /* truncate existing file or create new */
  267. createflags = CREATE_ALWAYS;
  268. } else {
  269. /* open existing but create if necessary */
  270. createflags = OPEN_ALWAYS;
  271. }
  272. } else if (flag & APR_TRUNCATE) {
  273. /* only truncate if file already exists */
  274. createflags = TRUNCATE_EXISTING;
  275. } else {
  276. /* only open if file already exists */
  277. createflags = OPEN_EXISTING;
  278. }
  279. if ((flag & APR_EXCL) && !(flag & APR_CREATE)) {
  280. return APR_EACCES;
  281. }
  282. if (flag & APR_DELONCLOSE) {
  283. attributes |= FILE_FLAG_DELETE_ON_CLOSE;
  284. }
  285. if (flag & APR_OPENLINK) {
  286. attributes |= FILE_FLAG_OPEN_REPARSE_POINT;
  287. }
  288. /* Without READ or WRITE, we fail unless apr called fspr_file_open
  289. * internally with the private APR_OPENINFO flag.
  290. *
  291. * With the APR_OPENINFO flag on NT, use the option flag
  292. * FILE_FLAG_BACKUP_SEMANTICS to allow us to open directories.
  293. * See the static resolve_ident() fn in file_io/win32/filestat.c
  294. */
  295. if (!(flag & (APR_READ | APR_WRITE))) {
  296. if (flag & APR_OPENINFO) {
  297. if (fspr_os_level >= APR_WIN_NT) {
  298. attributes |= FILE_FLAG_BACKUP_SEMANTICS;
  299. }
  300. }
  301. else {
  302. return APR_EACCES;
  303. }
  304. if (flag & APR_READCONTROL)
  305. oflags |= READ_CONTROL;
  306. }
  307. if (flag & APR_XTHREAD) {
  308. /* This win32 specific feature is required
  309. * to allow multiple threads to work with the file.
  310. */
  311. attributes |= FILE_FLAG_OVERLAPPED;
  312. }
  313. #if APR_HAS_UNICODE_FS
  314. IF_WIN_OS_IS_UNICODE
  315. {
  316. fspr_wchar_t wfname[APR_PATH_MAX];
  317. if (flag & APR_SENDFILE_ENABLED) {
  318. /* This feature is required to enable sendfile operations
  319. * against the file on Win32. Also implies APR_XTHREAD.
  320. */
  321. flag |= APR_XTHREAD;
  322. attributes |= FILE_FLAG_SEQUENTIAL_SCAN | FILE_FLAG_OVERLAPPED;
  323. }
  324. if (rv = utf8_to_unicode_path(wfname, sizeof(wfname)
  325. / sizeof(fspr_wchar_t), fname))
  326. return rv;
  327. handle = CreateFileW(wfname, oflags, sharemode,
  328. NULL, createflags, attributes, 0);
  329. }
  330. #endif
  331. #if APR_HAS_ANSI_FS
  332. ELSE_WIN_OS_IS_ANSI {
  333. handle = CreateFileA(fname, oflags, sharemode,
  334. NULL, createflags, attributes, 0);
  335. if (flag & APR_SENDFILE_ENABLED) {
  336. /* This feature is not supported on this platform.
  337. */
  338. flag &= ~APR_SENDFILE_ENABLED;
  339. }
  340. }
  341. #endif
  342. if (handle == INVALID_HANDLE_VALUE) {
  343. return fspr_get_os_error();
  344. }
  345. (*new) = (fspr_file_t *)fspr_pcalloc(pool, sizeof(fspr_file_t));
  346. (*new)->pool = pool;
  347. (*new)->filehand = handle;
  348. (*new)->fname = fspr_pstrdup(pool, fname);
  349. (*new)->flags = flag;
  350. (*new)->timeout = -1;
  351. (*new)->ungetchar = -1;
  352. if (flag & APR_APPEND) {
  353. (*new)->append = 1;
  354. SetFilePointer((*new)->filehand, 0, NULL, FILE_END);
  355. }
  356. if (flag & APR_BUFFERED) {
  357. (*new)->buffered = 1;
  358. (*new)->buffer = fspr_palloc(pool, APR_FILE_BUFSIZE);
  359. }
  360. /* Need the mutex to handled buffered and O_APPEND style file i/o */
  361. if ((*new)->buffered || (*new)->append) {
  362. rv = fspr_thread_mutex_create(&(*new)->mutex,
  363. APR_THREAD_MUTEX_DEFAULT, pool);
  364. if (rv) {
  365. if (file_cleanup(*new) == APR_SUCCESS) {
  366. fspr_pool_cleanup_kill(pool, *new, file_cleanup);
  367. }
  368. return rv;
  369. }
  370. }
  371. /* Create a pollset with room for one descriptor. */
  372. /* ### check return codes */
  373. (void) fspr_pollset_create(&(*new)->pollset, 1, pool, 0);
  374. if (!(flag & APR_FILE_NOCLEANUP)) {
  375. fspr_pool_cleanup_register((*new)->pool, (void *)(*new), file_cleanup,
  376. fspr_pool_cleanup_null);
  377. }
  378. return APR_SUCCESS;
  379. }
  380. APR_DECLARE(fspr_status_t) fspr_file_close(fspr_file_t *file)
  381. {
  382. fspr_status_t stat;
  383. if ((stat = file_cleanup(file)) == APR_SUCCESS) {
  384. fspr_pool_cleanup_kill(file->pool, file, file_cleanup);
  385. if (file->mutex) {
  386. fspr_thread_mutex_destroy(file->mutex);
  387. }
  388. return APR_SUCCESS;
  389. }
  390. return stat;
  391. }
  392. APR_DECLARE(fspr_status_t) fspr_file_remove(const char *path, fspr_pool_t *pool)
  393. {
  394. #if APR_HAS_UNICODE_FS
  395. IF_WIN_OS_IS_UNICODE
  396. {
  397. fspr_wchar_t wpath[APR_PATH_MAX];
  398. fspr_status_t rv;
  399. if (rv = utf8_to_unicode_path(wpath, sizeof(wpath)
  400. / sizeof(fspr_wchar_t), path)) {
  401. return rv;
  402. }
  403. if (DeleteFileW(wpath))
  404. return APR_SUCCESS;
  405. }
  406. #endif
  407. #if APR_HAS_ANSI_FS
  408. ELSE_WIN_OS_IS_ANSI
  409. if (DeleteFile(path))
  410. return APR_SUCCESS;
  411. #endif
  412. return fspr_get_os_error();
  413. }
  414. APR_DECLARE(fspr_status_t) fspr_file_rename(const char *frompath,
  415. const char *topath,
  416. fspr_pool_t *pool)
  417. {
  418. IF_WIN_OS_IS_UNICODE
  419. {
  420. #if APR_HAS_UNICODE_FS
  421. fspr_wchar_t wfrompath[APR_PATH_MAX], wtopath[APR_PATH_MAX];
  422. fspr_status_t rv;
  423. if (rv = utf8_to_unicode_path(wfrompath, sizeof(wfrompath)
  424. / sizeof(fspr_wchar_t), frompath)) {
  425. return rv;
  426. }
  427. if (rv = utf8_to_unicode_path(wtopath, sizeof(wtopath)
  428. / sizeof(fspr_wchar_t), topath)) {
  429. return rv;
  430. }
  431. #ifndef _WIN32_WCE
  432. if (MoveFileExW(wfrompath, wtopath, MOVEFILE_REPLACE_EXISTING |
  433. MOVEFILE_COPY_ALLOWED))
  434. #else
  435. if (MoveFileW(wfrompath, wtopath))
  436. #endif
  437. return APR_SUCCESS;
  438. #else
  439. if (MoveFileEx(frompath, topath, MOVEFILE_REPLACE_EXISTING |
  440. MOVEFILE_COPY_ALLOWED))
  441. return APR_SUCCESS;
  442. #endif
  443. }
  444. #if APR_HAS_ANSI_FS
  445. ELSE_WIN_OS_IS_ANSI
  446. {
  447. /* Windows 95 and 98 do not support MoveFileEx, so we'll use
  448. * the old MoveFile function. However, MoveFile requires that
  449. * the new file not already exist...so we have to delete that
  450. * file if it does. Perhaps we should back up the to-be-deleted
  451. * file in case something happens?
  452. */
  453. HANDLE handle = INVALID_HANDLE_VALUE;
  454. if ((handle = CreateFile(topath, GENERIC_WRITE, 0, 0,
  455. OPEN_EXISTING, 0, 0 )) != INVALID_HANDLE_VALUE )
  456. {
  457. CloseHandle(handle);
  458. if (!DeleteFile(topath))
  459. return fspr_get_os_error();
  460. }
  461. if (MoveFile(frompath, topath))
  462. return APR_SUCCESS;
  463. }
  464. #endif
  465. return fspr_get_os_error();
  466. }
  467. APR_DECLARE(fspr_status_t) fspr_os_file_get(fspr_os_file_t *thefile,
  468. fspr_file_t *file)
  469. {
  470. *thefile = file->filehand;
  471. return APR_SUCCESS;
  472. }
  473. APR_DECLARE(fspr_status_t) fspr_os_file_put(fspr_file_t **file,
  474. fspr_os_file_t *thefile,
  475. fspr_int32_t flags,
  476. fspr_pool_t *pool)
  477. {
  478. (*file) = fspr_pcalloc(pool, sizeof(fspr_file_t));
  479. (*file)->pool = pool;
  480. (*file)->filehand = *thefile;
  481. (*file)->ungetchar = -1; /* no char avail */
  482. (*file)->timeout = -1;
  483. (*file)->flags = flags;
  484. if (flags & APR_APPEND) {
  485. (*file)->append = 1;
  486. }
  487. if (flags & APR_BUFFERED) {
  488. (*file)->buffered = 1;
  489. (*file)->buffer = fspr_palloc(pool, APR_FILE_BUFSIZE);
  490. }
  491. if ((*file)->append || (*file)->buffered) {
  492. fspr_status_t rv;
  493. rv = fspr_thread_mutex_create(&(*file)->mutex,
  494. APR_THREAD_MUTEX_DEFAULT, pool);
  495. if (rv) {
  496. if (file_cleanup(*file) == APR_SUCCESS) {
  497. fspr_pool_cleanup_kill(pool, *file, file_cleanup);
  498. }
  499. return rv;
  500. }
  501. }
  502. /* Create a pollset with room for one descriptor. */
  503. /* ### check return codes */
  504. (void) fspr_pollset_create(&(*file)->pollset, 1, pool, 0);
  505. /* XXX... we pcalloc above so all others are zeroed.
  506. * Should we be testing if thefile is a handle to
  507. * a PIPE and set up the mechanics appropriately?
  508. *
  509. * (*file)->pipe;
  510. */
  511. return APR_SUCCESS;
  512. }
  513. APR_DECLARE(fspr_status_t) fspr_file_eof(fspr_file_t *fptr)
  514. {
  515. if (fptr->eof_hit == 1) {
  516. return APR_EOF;
  517. }
  518. return APR_SUCCESS;
  519. }
  520. APR_DECLARE(fspr_status_t) fspr_file_open_stderr(fspr_file_t **thefile, fspr_pool_t *pool)
  521. {
  522. #ifdef _WIN32_WCE
  523. return APR_ENOTIMPL;
  524. #else
  525. fspr_os_file_t file_handle;
  526. fspr_set_os_error(APR_SUCCESS);
  527. file_handle = GetStdHandle(STD_ERROR_HANDLE);
  528. if (!file_handle || (file_handle == INVALID_HANDLE_VALUE)) {
  529. fspr_status_t rv = fspr_get_os_error();
  530. if (rv == APR_SUCCESS) {
  531. return APR_EINVAL;
  532. }
  533. return rv;
  534. }
  535. return fspr_os_file_put(thefile, &file_handle, 0, pool);
  536. #endif
  537. }
  538. APR_DECLARE(fspr_status_t) fspr_file_open_stdout(fspr_file_t **thefile, fspr_pool_t *pool)
  539. {
  540. #ifdef _WIN32_WCE
  541. return APR_ENOTIMPL;
  542. #else
  543. fspr_os_file_t file_handle;
  544. fspr_set_os_error(APR_SUCCESS);
  545. file_handle = GetStdHandle(STD_OUTPUT_HANDLE);
  546. if (!file_handle || (file_handle == INVALID_HANDLE_VALUE)) {
  547. fspr_status_t rv = fspr_get_os_error();
  548. if (rv == APR_SUCCESS) {
  549. return APR_EINVAL;
  550. }
  551. return rv;
  552. }
  553. return fspr_os_file_put(thefile, &file_handle, 0, pool);
  554. #endif
  555. }
  556. APR_DECLARE(fspr_status_t) fspr_file_open_stdin(fspr_file_t **thefile, fspr_pool_t *pool)
  557. {
  558. #ifdef _WIN32_WCE
  559. return APR_ENOTIMPL;
  560. #else
  561. fspr_os_file_t file_handle;
  562. fspr_set_os_error(APR_SUCCESS);
  563. file_handle = GetStdHandle(STD_INPUT_HANDLE);
  564. if (!file_handle || (file_handle == INVALID_HANDLE_VALUE)) {
  565. fspr_status_t rv = fspr_get_os_error();
  566. if (rv == APR_SUCCESS) {
  567. return APR_EINVAL;
  568. }
  569. return rv;
  570. }
  571. return fspr_os_file_put(thefile, &file_handle, 0, pool);
  572. #endif
  573. }
  574. APR_POOL_IMPLEMENT_ACCESSOR(file);
  575. APR_IMPLEMENT_INHERIT_SET(file, flags, pool, file_cleanup)
  576. APR_IMPLEMENT_INHERIT_UNSET(file, flags, pool, file_cleanup)