file.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684
  1. /** BEGIN COPYRIGHT BLOCK
  2. * This Program is free software; you can redistribute it and/or modify it under
  3. * the terms of the GNU General Public License as published by the Free Software
  4. * Foundation; version 2 of the License.
  5. *
  6. * This Program is distributed in the hope that it will be useful, but WITHOUT
  7. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  8. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  9. *
  10. * You should have received a copy of the GNU General Public License along with
  11. * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
  12. * Place, Suite 330, Boston, MA 02111-1307 USA.
  13. *
  14. * In addition, as a special exception, Red Hat, Inc. gives You the additional
  15. * right to link the code of this Program with code not covered under the GNU
  16. * General Public License ("Non-GPL Code") and to distribute linked combinations
  17. * including the two, subject to the limitations in this paragraph. Non-GPL Code
  18. * permitted under this exception must only link to the code of this Program
  19. * through those well defined interfaces identified in the file named EXCEPTION
  20. * found in the source code files (the "Approved Interfaces"). The files of
  21. * Non-GPL Code may instantiate templates or use macros or inline functions from
  22. * the Approved Interfaces without causing the resulting work to be covered by
  23. * the GNU General Public License. Only Red Hat, Inc. may make changes or
  24. * additions to the list of Approved Interfaces. You must obey the GNU General
  25. * Public License in all respects for all of the Program code and other code used
  26. * in conjunction with the Program except the Non-GPL Code covered by this
  27. * exception. If you modify this file, you may extend this exception to your
  28. * version of the file, but you are not obligated to do so. If you do not wish to
  29. * provide this exception without modification, you must delete this exception
  30. * statement from your version and license this file solely under the GPL without
  31. * exception.
  32. *
  33. *
  34. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  35. * Copyright (C) 2005 Red Hat, Inc.
  36. * All rights reserved.
  37. * END COPYRIGHT BLOCK **/
  38. #ifdef HAVE_CONFIG_H
  39. # include <config.h>
  40. #endif
  41. /*
  42. * file.c: system specific functions for reading/writing files
  43. *
  44. * See file.h for formal definitions of what these functions do
  45. *
  46. * Rob McCool
  47. */
  48. #include "base/file.h"
  49. #ifdef BSD_RLIMIT
  50. #include <sys/time.h>
  51. #include <sys/resource.h>
  52. #else
  53. #include <stdlib.h>
  54. #include <signal.h>
  55. #endif
  56. #ifdef XP_WIN32
  57. #include <time.h> /* time */
  58. #include <sys/stat.h> /* stat */
  59. #include <errno.h>
  60. #include <direct.h>
  61. #include <base/nterr.h>
  62. /* Removed for ns security integration
  63. #include <xp_error.h>
  64. */
  65. #endif
  66. #include <prerror.h>
  67. #include "private/pprio.h"
  68. #include "prlock.h"
  69. extern "C" char *nscperror_lookup(int err);
  70. /* --- globals -------------------------------------------------------------*/
  71. /* PRFileDesc * SYS_ERROR_FD = NULL; */
  72. const int errbuf_size = 256;
  73. const unsigned int LOCKFILERANGE=0x7FFFFFFF;
  74. PRLock *_atomic_write_lock = NULL;
  75. /* --------------------------------- stat --------------------------------- */
  76. /* XXXMB - Can't convert to PR_GetFileInfo because we directly exported
  77. * the stat interface... Damn.
  78. */
  79. NSAPI_PUBLIC int system_stat(char *path, struct stat *finfo)
  80. {
  81. #ifdef XP_WIN32
  82. int chop, l;
  83. /* The NT stat is very peculiar about directory names. */
  84. /* XXX aruna - there is a bug here, maybe in the C runtime.
  85. * Stating the same path in a separate program succeeds. From
  86. * jblack's profiling, this needs to be replaced by the Win32
  87. * calls anyway.*/
  88. l = strlen(path);
  89. if((path[l - 1] == '/') &&
  90. (!(isalpha(path[0]) && (!strcmp(&path[1], ":/")))))
  91. {
  92. chop = 1;
  93. path[--l] = '\0';
  94. }
  95. else chop = 0;
  96. #endif /* XP_WIN32 */
  97. #ifdef XP_UNIX
  98. if(stat(path, finfo) == -1)
  99. return -1;
  100. #else /* XP_WIN32 */
  101. if(_stat(path, (struct _stat *)finfo) == -1) {
  102. /* XXXMB - this sucks;
  103. * try to convert to an error code we'll expect...
  104. */
  105. switch(errno) {
  106. case ENOENT: PR_SetError(PR_FILE_NOT_FOUND_ERROR, errno); break;
  107. default: PR_SetError(PR_UNKNOWN_ERROR, errno); break;
  108. }
  109. return -1;
  110. }
  111. /* NT sets the time fields to -1 if it thinks that the file
  112. * is a device ( like com1.html, lpt1.html etc) In this case
  113. * simply set last modified time to the current time....
  114. */
  115. if (finfo->st_mtime == -1) {
  116. finfo->st_mtime = time(NULL);
  117. }
  118. if (finfo->st_atime == -1) {
  119. finfo->st_atime = 0;
  120. }
  121. if (finfo->st_ctime == -1) {
  122. finfo->st_ctime = 0;
  123. }
  124. if(chop)
  125. path[l++] = '/';
  126. #endif /* XP_WIN32 */
  127. if(S_ISREG(finfo->st_mode) && (path[strlen(path) - 1] == '/')) {
  128. /* File with trailing slash */
  129. errno = ENOENT;
  130. return -1;
  131. }
  132. return 0;
  133. }
  134. NSAPI_PUBLIC int system_fread(SYS_FILE fd, char *buf, int sz)
  135. {
  136. /* XXXMB - this is the *one* function which does return a length
  137. * instead of the IO_ERROR/IO_OKAY.
  138. */
  139. return PR_Read(fd, buf, sz);
  140. }
  141. NSAPI_PUBLIC int system_fwrite(SYS_FILE fd, char *buf, int sz) {
  142. int n,o,w;
  143. for(n=sz,o=0; n; n-=w,o+=w) {
  144. if((w = PR_Write(fd, &buf[o], n)) < 0)
  145. return IO_ERROR;
  146. }
  147. return IO_OKAY;
  148. }
  149. /* ---------------------------- Standard UNIX ----------------------------- */
  150. #ifdef XP_UNIX
  151. #include <sys/file.h> /* flock */
  152. NSAPI_PUBLIC int system_fwrite_atomic(SYS_FILE fd, char *buf, int sz)
  153. {
  154. int ret;
  155. #if 0
  156. if(flock(fd,LOCK_EX) == -1)
  157. return IO_ERROR;
  158. #endif
  159. ret = system_fwrite(fd,buf,sz);
  160. #if 0
  161. if(flock(fd,LOCK_UN) == -1)
  162. return IO_ERROR; /* ??? */
  163. #endif
  164. return ret;
  165. }
  166. /* -------------------------- system_nocoredumps -------------------------- */
  167. NSAPI_PUBLIC int system_nocoredumps(void)
  168. {
  169. #ifdef BSD_RLIMIT
  170. struct rlimit rl;
  171. rl.rlim_cur = 0;
  172. rl.rlim_max = 0;
  173. return setrlimit(RLIMIT_CORE, &rl);
  174. #else
  175. #if defined(SNI)
  176. /* C++ compiler seems to find more that one overloaded instance of exit() ?! */
  177. #define EXITFUNC ::exit
  178. #else
  179. #define EXITFUNC exit
  180. #endif
  181. signal(SIGQUIT, EXITFUNC);
  182. signal(SIGILL, EXITFUNC);
  183. signal(SIGTRAP, EXITFUNC);
  184. signal(SIGABRT, EXITFUNC);
  185. signal(SIGIOT, EXITFUNC);
  186. signal(SIGEMT, EXITFUNC);
  187. signal(SIGFPE, EXITFUNC);
  188. signal(SIGBUS, EXITFUNC);
  189. signal(SIGSEGV, EXITFUNC);
  190. signal(SIGSYS, EXITFUNC);
  191. return 0;
  192. #endif
  193. }
  194. #endif /* XP_UNIX */
  195. /* --------------------------- file_setinherit ---------------------------- */
  196. NSAPI_PUBLIC int file_setinherit(SYS_FILE fd, int value)
  197. {
  198. #if defined(XP_WIN32)
  199. int ret;
  200. // ret = SetHandleInformation((HANDLE)PR_FileDesc2NativeHandle(fd), 0, value?HANDLE_FLAG_INHERIT:0);
  201. // This function did nothing before since the mask was set to 0.
  202. ret = SetHandleInformation((HANDLE)PR_FileDesc2NativeHandle(fd), HANDLE_FLAG_INHERIT, value?HANDLE_FLAG_INHERIT:0);
  203. return ret==0?-1:0;
  204. #elif defined(XP_UNIX)
  205. int flags = 0;
  206. PRInt32 nativeFD;
  207. PRFileDesc *bottom = fd;
  208. while (bottom->lower != NULL) {
  209. bottom = bottom->lower;
  210. }
  211. nativeFD = PR_FileDesc2NativeHandle(bottom);
  212. #if 0
  213. fprintf(stderr, "\nInfo(file_setinherit): Native file descriptor is %d\n", nativeFD);
  214. #endif
  215. flags = fcntl(nativeFD, F_GETFD, 0);
  216. if(flags == -1)
  217. return -1;
  218. if(value)
  219. flags &= (~FD_CLOEXEC);
  220. else
  221. flags |= FD_CLOEXEC;
  222. fcntl(nativeFD, F_SETFD, flags);
  223. return 0;
  224. /* Comment out for ns security/ nspr integration (HACK for NOW)
  225. int flags = fcntl(PR_FileDesc2NativeHandle(fd), F_GETFD, 0);
  226. if(flags == -1)
  227. return -1;
  228. if(value)
  229. flags &= (~FD_CLOEXEC);
  230. else
  231. flags |= FD_CLOEXEC;
  232. fcntl(PR_FileDesc2NativeHandle(fd), F_SETFD, flags);
  233. return 0;
  234. */
  235. #endif
  236. }
  237. NSAPI_PUBLIC SYS_FILE system_fopenRO(char *p)
  238. {
  239. SYS_FILE f = PR_Open(p, PR_RDONLY, 0);
  240. if (!f)
  241. return SYS_ERROR_FD;
  242. return f;
  243. }
  244. NSAPI_PUBLIC SYS_FILE system_fopenWA(char *p)
  245. {
  246. SYS_FILE f = PR_Open(p, PR_RDWR|PR_CREATE_FILE|PR_APPEND, 0644);
  247. if (!f)
  248. return SYS_ERROR_FD;
  249. return f;
  250. }
  251. NSAPI_PUBLIC SYS_FILE system_fopenRW(char *p)
  252. {
  253. SYS_FILE f = PR_Open(p, PR_RDWR|PR_CREATE_FILE, 0644);
  254. if (!f)
  255. return SYS_ERROR_FD;
  256. return f;
  257. }
  258. NSAPI_PUBLIC SYS_FILE system_fopenWT(char *p)
  259. {
  260. SYS_FILE f = PR_Open(p, PR_RDWR|PR_CREATE_FILE|PR_TRUNCATE, 0644);
  261. if (!f)
  262. return SYS_ERROR_FD;
  263. return f;
  264. }
  265. NSAPI_PUBLIC int system_fclose(SYS_FILE fd)
  266. {
  267. return (PR_Close(fd));
  268. }
  269. #ifdef FILE_WIN32
  270. int CgiBuffering;
  271. NSAPI_PUBLIC SYS_FILE system_fopen(char *path, int access, int flags)
  272. {
  273. char p2[MAX_PATH];
  274. SYS_FILE ret;
  275. HANDLE fd;
  276. if (strlen(path) >= MAX_PATH) {
  277. return SYS_ERROR_FD;
  278. }
  279. file_unix2local(path, p2);
  280. fd = CreateFile(p2, access, FILE_SHARE_READ | FILE_SHARE_WRITE,
  281. NULL, flags, 0, NULL);
  282. ret = PR_ImportFile((int32)fd);
  283. if(ret == INVALID_HANDLE_VALUE)
  284. return SYS_ERROR_FD;
  285. return ret;
  286. }
  287. NSAPI_PUBLIC int system_pread(SYS_FILE fd, char *buf, int BytesToRead) {
  288. unsigned long BytesRead = 0;
  289. int result = 0;
  290. BOOLEAN TimeoutSet = FALSE;
  291. /* XXXMB - nspr20 should be able to do this; but right now it doesn't
  292. * return proper error info.
  293. * fix it later...
  294. */
  295. if(ReadFile((HANDLE)PR_FileDesc2NativeHandle(fd), (LPVOID)buf, BytesToRead, &BytesRead, NULL) == FALSE) {
  296. if (GetLastError() == ERROR_BROKEN_PIPE) {
  297. return IO_EOF;
  298. } else {
  299. return IO_ERROR;
  300. }
  301. }
  302. return (BytesRead ? BytesRead : IO_EOF);
  303. }
  304. NSAPI_PUBLIC int system_pwrite(SYS_FILE fd, char *buf, int BytesToWrite)
  305. {
  306. unsigned long BytesWritten;
  307. if (WriteFile((HANDLE)PR_FileDesc2NativeHandle(fd), (LPVOID)buf,
  308. BytesToWrite, &BytesWritten, NULL) == FALSE) {
  309. return IO_ERROR;
  310. }
  311. return BytesWritten;
  312. }
  313. NSAPI_PUBLIC int system_fwrite_atomic(SYS_FILE fd, char *buf, int sz)
  314. {
  315. int ret;
  316. #if 0
  317. if(system_flock(fd) == IO_ERROR)
  318. return IO_ERROR;
  319. #endif
  320. /* XXXMB - this is technically thread unsafe, but it catches any
  321. * callers of fwrite_atomic when we're single threaded and just coming
  322. * to life.
  323. */
  324. if (!_atomic_write_lock) {
  325. _atomic_write_lock = PR_NewLock();
  326. }
  327. PR_Lock(_atomic_write_lock);
  328. ret = system_fwrite(fd,buf,sz);
  329. PR_Unlock(_atomic_write_lock);
  330. #if 0
  331. if(system_ulock(fd) == IO_ERROR)
  332. return IO_ERROR;
  333. #endif
  334. return ret;
  335. }
  336. NSAPI_PUBLIC void file_unix2local(char *path, char *p2)
  337. {
  338. /* Try to handle UNIX-style paths */
  339. if((!strchr(path, FILE_PATHSEP))) {
  340. int x;
  341. for(x = 0; path[x]; x++)
  342. p2[x] = (path[x] == '/' ? '\\' : path[x]);
  343. p2[x] = '\0';
  344. }
  345. else
  346. strcpy(p2, path);
  347. }
  348. NSAPI_PUBLIC int system_nocoredumps(void)
  349. {
  350. return 0;
  351. }
  352. /* --------------------------- system_winerr ------------------------------ */
  353. #include <winsock.h>
  354. #include <errno.h>
  355. #include "util.h"
  356. NSAPI_PUBLIC char *system_winsockerr(void)
  357. {
  358. int errn = WSAGetLastError();
  359. return FindError(errn);
  360. }
  361. NSAPI_PUBLIC char *system_winerr(void)
  362. {
  363. int errn = GetLastError();
  364. if (errn == 0)
  365. errn = WSAGetLastError();
  366. return FindError(errn);
  367. }
  368. /* ------------------------- Dir related stuff ---------------------------- */
  369. NSAPI_PUBLIC SYS_DIR dir_open(char *pathp)
  370. {
  371. dir_s *ret = (dir_s *) MALLOC(sizeof(dir_s));
  372. char path[MAX_PATH];
  373. int l;
  374. if (strlen(pathp) >= MAX_PATH) {
  375. return NULL;
  376. }
  377. l = util_sprintf(path, "%s", pathp) - 1;
  378. path[strlen(pathp)] = '\0';
  379. if(path[strlen(path) - 1] != FILE_PATHSEP)
  380. strcpy (path + strlen(path), "\\*.*");
  381. else
  382. util_sprintf(path, "%s*.*", path);
  383. ret->de.d_name = NULL;
  384. if( (ret->dp = FindFirstFile(path, &ret->fdata)) != INVALID_HANDLE_VALUE)
  385. return ret;
  386. FREE(ret);
  387. return NULL;
  388. }
  389. NSAPI_PUBLIC SYS_DIRENT *dir_read(SYS_DIR ds)
  390. {
  391. if(FindNextFile(ds->dp, &ds->fdata) == FALSE)
  392. return NULL;
  393. if(ds->de.d_name)
  394. FREE(ds->de.d_name);
  395. ds->de.d_name = STRDUP(ds->fdata.cFileName);
  396. return &ds->de;
  397. }
  398. NSAPI_PUBLIC void dir_close(SYS_DIR ds)
  399. {
  400. FindClose(ds->dp);
  401. if(ds->de.d_name)
  402. FREE(ds->de.d_name);
  403. FREE(ds);
  404. }
  405. #endif /* FILE_WIN32 */
  406. NSAPI_PUBLIC int file_notfound(void)
  407. {
  408. #ifdef FILE_WIN32
  409. int errn = PR_GetError();
  410. return (errn == PR_FILE_NOT_FOUND_ERROR);
  411. #else
  412. return (errno == ENOENT);
  413. #endif
  414. }
  415. #ifdef XP_UNIX
  416. #if !defined(SNI) && !defined(LINUX)
  417. extern char *sys_errlist[];
  418. #endif /* SNI */
  419. #endif
  420. #define ERRMSG_SIZE 35
  421. #ifdef THREAD_ANY
  422. static int errmsg_key = -1;
  423. #include "systhr.h"
  424. /* Removed for ns security integration
  425. #include "xp_error.h"
  426. */
  427. #else /* THREAD_ANY */
  428. static char errmsg[ERRMSG_SIZE];
  429. #endif /* THREAD_ANY */
  430. #include "util.h"
  431. void system_errmsg_init(void)
  432. {
  433. if (errmsg_key == -1) {
  434. #if defined(THREAD_ANY)
  435. errmsg_key = systhread_newkey();
  436. #endif
  437. #ifdef XP_WIN32
  438. HashNtErrors();
  439. #endif
  440. if (!_atomic_write_lock)
  441. _atomic_write_lock = PR_NewLock();
  442. }
  443. }
  444. NSAPI_PUBLIC int system_errmsg_fn(char **buff, size_t maxlen)
  445. {
  446. char static_error[128];
  447. char *lmsg = 0; /* Local message pointer */
  448. size_t msglen = 0;
  449. PRErrorCode nscp_error;
  450. #ifdef XP_WIN32
  451. LPTSTR sysmsg = 0;
  452. #endif
  453. nscp_error = PR_GetError();
  454. /* If there is a NSPR error, but it is "unknown", try to get the OSError
  455. * and use that instead.
  456. */
  457. if (nscp_error == PR_UNKNOWN_ERROR)
  458. errno = PR_GetOSError();
  459. if (nscp_error != 0 && nscp_error != PR_UNKNOWN_ERROR){
  460. char *nscp_error_msg;
  461. nscp_error_msg = nscperror_lookup(nscp_error);
  462. if(nscp_error_msg){
  463. PR_SetError(0, 0);
  464. lmsg = nscp_error_msg;
  465. } else {
  466. util_snprintf(static_error, sizeof(static_error), "unknown error %d", nscp_error);
  467. lmsg = static_error;
  468. }
  469. } else {
  470. #if defined(XP_WIN32)
  471. msglen = FormatMessage(
  472. FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_ALLOCATE_BUFFER,
  473. NULL,
  474. GetLastError(),
  475. LOCALE_SYSTEM_DEFAULT,
  476. (LPTSTR)&sysmsg,
  477. 0,
  478. 0);
  479. if (msglen > 0)
  480. lmsg = sysmsg;
  481. else
  482. lmsg = system_winerr();
  483. SetLastError(0);
  484. #else
  485. /* replaced
  486. #if defined(SNI) || defined(LINUX)
  487. / C++ platform has no definition for sys_errlist /
  488. lmsg = strerror(errno);
  489. #else
  490. lmsg = sys_errlist[errno];
  491. #endif
  492. with lmsg =strerror(errno);*/
  493. lmsg=strerror(errno);
  494. errno = 0;
  495. #endif
  496. }
  497. /* At this point lmsg points to something. */
  498. msglen = strlen(lmsg);
  499. if (*buff == NULL)
  500. *buff = STRDUP(lmsg);
  501. else if (maxlen > msglen)
  502. memcpy(*buff, lmsg, msglen+1);
  503. else
  504. msglen = 0;
  505. #ifdef XP_WIN32
  506. /* NT's FormatMessage() dynamically allocated the msg; free it */
  507. if (sysmsg)
  508. LocalFree(sysmsg);
  509. #endif
  510. return msglen;
  511. }
  512. NSAPI_PUBLIC char *
  513. system_errmsg(void)
  514. {
  515. char *buff = 0;
  516. if (errmsg_key == -1)
  517. return "unknown early startup error";
  518. // rmaxwell - This is extremely lame.
  519. // Allocate a buffer in thread local storage to
  520. // hold the last error message.
  521. // The whole error message facility is broken and should be
  522. // updated to get error strings out of the code.
  523. if(!(buff = (char *) systhread_getdata(errmsg_key))) {
  524. buff = (char *) PERM_MALLOC(errbuf_size);
  525. systhread_setdata(errmsg_key, (void *)buff);
  526. }
  527. system_errmsg_fn(&buff, errbuf_size);
  528. if (buff == 0)
  529. buff = "Could not retrieve system error message";
  530. return buff;
  531. }
  532. NSAPI_PUBLIC int
  533. system_rename(char *oldpath, char *newpath)
  534. {
  535. return rename(oldpath, newpath);
  536. }
  537. NSAPI_PUBLIC int
  538. system_unlink(char *path)
  539. {
  540. return PR_Delete(path)==PR_FAILURE?-1:0;
  541. }
  542. NSAPI_PUBLIC int system_lseek(SYS_FILE fd, int off, int wh)
  543. {
  544. switch (wh) {
  545. case 0:
  546. return PR_Seek(fd, off, PR_SEEK_SET);
  547. break;
  548. case 1:
  549. return PR_Seek(fd, off, PR_SEEK_CUR);
  550. break;
  551. case 2:
  552. return PR_Seek(fd, off, PR_SEEK_END);
  553. break;
  554. default:
  555. return -1;
  556. }
  557. }
  558. NSAPI_PUBLIC int
  559. system_tlock(SYS_FILE fd)
  560. {
  561. return PR_TLockFile(fd);
  562. }
  563. NSAPI_PUBLIC int
  564. system_flock(SYS_FILE fd)
  565. {
  566. return PR_LockFile(fd);
  567. }
  568. NSAPI_PUBLIC int
  569. system_ulock(SYS_FILE fd)
  570. {
  571. return PR_UnlockFile(fd);
  572. }