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.
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.
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.
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
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 **/
44
* file.c: system specific functions for reading/writing files
46
* See file.h for formal definitions of what these functions do
52
#include "base/file.h"
55
#include <sys/resource.h>
61
#include <time.h> /* time */
62
#include <sys/stat.h> /* stat */
65
#include <base/nterr.h>
66
/* Removed for ns security integration
72
#include "private/pprio.h"
75
extern "C" char *nscperror_lookup(int err);
77
/* --- globals -------------------------------------------------------------*/
78
/* PRFileDesc * SYS_ERROR_FD = NULL; */
80
const int errbuf_size = 256;
81
const unsigned int LOCKFILERANGE=0x7FFFFFFF;
82
PRLock *_atomic_write_lock = NULL;
84
/* --------------------------------- stat --------------------------------- */
87
/* XXXMB - Can't convert to PR_GetFileInfo because we directly exported
88
* the stat interface... Damn.
90
NSAPI_PUBLIC int system_stat(char *path, struct stat *finfo)
96
/* The NT stat is very peculiar about directory names. */
97
/* XXX aruna - there is a bug here, maybe in the C runtime.
98
* Stating the same path in a separate program succeeds. From
99
* jblack's profiling, this needs to be replaced by the Win32
103
if((path[l - 1] == '/') &&
104
(!(isalpha(path[0]) && (!strcmp(&path[1], ":/")))))
110
#endif /* XP_WIN32 */
113
if(stat(path, finfo) == -1)
117
if(_stat(path, (struct _stat *)finfo) == -1) {
118
/* XXXMB - this sucks;
119
* try to convert to an error code we'll expect...
122
case ENOENT: PR_SetError(PR_FILE_NOT_FOUND_ERROR, errno); break;
123
default: PR_SetError(PR_UNKNOWN_ERROR, errno); break;
128
/* NT sets the time fields to -1 if it thinks that the file
129
* is a device ( like com1.html, lpt1.html etc) In this case
130
* simply set last modified time to the current time....
133
if (finfo->st_mtime == -1) {
134
finfo->st_mtime = time(NULL);
136
if (finfo->st_atime == -1) {
139
if (finfo->st_ctime == -1) {
145
#endif /* XP_WIN32 */
147
if(S_ISREG(finfo->st_mode) && (path[strlen(path) - 1] == '/')) {
148
/* File with trailing slash */
156
NSAPI_PUBLIC int system_fread(SYS_FILE fd, char *buf, int sz)
158
/* XXXMB - this is the *one* function which does return a length
159
* instead of the IO_ERROR/IO_OKAY.
161
return PR_Read(fd, buf, sz);
164
NSAPI_PUBLIC int system_fwrite(SYS_FILE fd, char *buf, int sz) {
167
for(n=sz,o=0; n; n-=w,o+=w) {
168
if((w = PR_Write(fd, &buf[o], n)) < 0)
174
/* ---------------------------- Standard UNIX ----------------------------- */
178
#include <sys/file.h> /* flock */
180
NSAPI_PUBLIC int system_fwrite_atomic(SYS_FILE fd, char *buf, int sz)
184
if(flock(fd,LOCK_EX) == -1)
187
ret = system_fwrite(fd,buf,sz);
189
if(flock(fd,LOCK_UN) == -1)
190
return IO_ERROR; /* ??? */
195
/* -------------------------- system_nocoredumps -------------------------- */
198
NSAPI_PUBLIC int system_nocoredumps(void)
205
return setrlimit(RLIMIT_CORE, &rl);
208
/* C++ compiler seems to find more that one overloaded instance of exit() ?! */
209
#define EXITFUNC ::exit
211
#define EXITFUNC exit
213
signal(SIGQUIT, EXITFUNC);
214
signal(SIGILL, EXITFUNC);
215
signal(SIGTRAP, EXITFUNC);
216
signal(SIGABRT, EXITFUNC);
217
signal(SIGIOT, EXITFUNC);
218
signal(SIGEMT, EXITFUNC);
219
signal(SIGFPE, EXITFUNC);
220
signal(SIGBUS, EXITFUNC);
221
signal(SIGSEGV, EXITFUNC);
222
signal(SIGSYS, EXITFUNC);
230
/* --------------------------- file_setinherit ---------------------------- */
232
NSAPI_PUBLIC int file_setinherit(SYS_FILE fd, int value)
234
#if defined(XP_WIN32)
237
// ret = SetHandleInformation((HANDLE)PR_FileDesc2NativeHandle(fd), 0, value?HANDLE_FLAG_INHERIT:0);
238
// This function did nothing before since the mask was set to 0.
239
ret = SetHandleInformation((HANDLE)PR_FileDesc2NativeHandle(fd), HANDLE_FLAG_INHERIT, value?HANDLE_FLAG_INHERIT:0);
241
#elif defined(XP_UNIX)
244
PRFileDesc *bottom = fd;
246
while (bottom->lower != NULL) {
247
bottom = bottom->lower;
250
nativeFD = PR_FileDesc2NativeHandle(bottom);
252
fprintf(stderr, "\nInfo(file_setinherit): Native file descriptor is %d\n", nativeFD);
254
flags = fcntl(nativeFD, F_GETFD, 0);
258
flags &= (~FD_CLOEXEC);
261
fcntl(nativeFD, F_SETFD, flags);
264
/* Comment out for ns security/ nspr integration (HACK for NOW)
265
int flags = fcntl(PR_FileDesc2NativeHandle(fd), F_GETFD, 0);
269
flags &= (~FD_CLOEXEC);
272
fcntl(PR_FileDesc2NativeHandle(fd), F_SETFD, flags);
278
NSAPI_PUBLIC SYS_FILE system_fopenRO(char *p)
280
SYS_FILE f = PR_Open(p, PR_RDONLY, 0);
287
NSAPI_PUBLIC SYS_FILE system_fopenWA(char *p)
289
SYS_FILE f = PR_Open(p, PR_RDWR|PR_CREATE_FILE|PR_APPEND, 0644);
296
NSAPI_PUBLIC SYS_FILE system_fopenRW(char *p)
298
SYS_FILE f = PR_Open(p, PR_RDWR|PR_CREATE_FILE, 0644);
305
NSAPI_PUBLIC SYS_FILE system_fopenWT(char *p)
307
SYS_FILE f = PR_Open(p, PR_RDWR|PR_CREATE_FILE|PR_TRUNCATE, 0644);
314
NSAPI_PUBLIC int system_fclose(SYS_FILE fd)
316
return (PR_Close(fd));
324
NSAPI_PUBLIC SYS_FILE system_fopen(char *path, int access, int flags)
330
if (strlen(path) >= MAX_PATH) {
334
file_unix2local(path, p2);
336
fd = CreateFile(p2, access, FILE_SHARE_READ | FILE_SHARE_WRITE,
337
NULL, flags, 0, NULL);
338
ret = PR_ImportFile((int32)fd);
340
if(ret == INVALID_HANDLE_VALUE)
348
NSAPI_PUBLIC int system_pread(SYS_FILE fd, char *buf, int BytesToRead) {
349
unsigned long BytesRead = 0;
351
BOOLEAN TimeoutSet = FALSE;
353
/* XXXMB - nspr20 should be able to do this; but right now it doesn't
354
* return proper error info.
357
if(ReadFile((HANDLE)PR_FileDesc2NativeHandle(fd), (LPVOID)buf, BytesToRead, &BytesRead, NULL) == FALSE) {
358
if (GetLastError() == ERROR_BROKEN_PIPE) {
364
return (BytesRead ? BytesRead : IO_EOF);
367
NSAPI_PUBLIC int system_pwrite(SYS_FILE fd, char *buf, int BytesToWrite)
369
unsigned long BytesWritten;
371
if (WriteFile((HANDLE)PR_FileDesc2NativeHandle(fd), (LPVOID)buf,
372
BytesToWrite, &BytesWritten, NULL) == FALSE) {
379
NSAPI_PUBLIC int system_fwrite_atomic(SYS_FILE fd, char *buf, int sz)
384
if(system_flock(fd) == IO_ERROR)
387
/* XXXMB - this is technically thread unsafe, but it catches any
388
* callers of fwrite_atomic when we're single threaded and just coming
391
if (!_atomic_write_lock) {
392
_atomic_write_lock = PR_NewLock();
394
PR_Lock(_atomic_write_lock);
395
ret = system_fwrite(fd,buf,sz);
396
PR_Unlock(_atomic_write_lock);
398
if(system_ulock(fd) == IO_ERROR)
405
NSAPI_PUBLIC void file_unix2local(char *path, char *p2)
407
/* Try to handle UNIX-style paths */
408
if((!strchr(path, FILE_PATHSEP))) {
411
for(x = 0; path[x]; x++)
412
p2[x] = (path[x] == '/' ? '\\' : path[x]);
420
NSAPI_PUBLIC int system_nocoredumps(void)
425
/* --------------------------- system_winerr ------------------------------ */
432
NSAPI_PUBLIC char *system_winsockerr(void)
434
int errn = WSAGetLastError();
436
return FindError(errn);
439
NSAPI_PUBLIC char *system_winerr(void)
441
int errn = GetLastError();
444
errn = WSAGetLastError();
445
return FindError(errn);
448
/* ------------------------- Dir related stuff ---------------------------- */
451
NSAPI_PUBLIC SYS_DIR dir_open(char *pathp)
453
dir_s *ret = (dir_s *) MALLOC(sizeof(dir_s));
457
if (strlen(pathp) >= MAX_PATH) {
461
l = util_sprintf(path, "%s", pathp) - 1;
462
path[strlen(pathp)] = '\0';
463
if(path[strlen(path) - 1] != FILE_PATHSEP)
464
strcpy (path + strlen(path), "\\*.*");
466
util_sprintf(path, "%s*.*", path);
468
ret->de.d_name = NULL;
469
if( (ret->dp = FindFirstFile(path, &ret->fdata)) != INVALID_HANDLE_VALUE)
475
NSAPI_PUBLIC SYS_DIRENT *dir_read(SYS_DIR ds)
477
if(FindNextFile(ds->dp, &ds->fdata) == FALSE)
481
ds->de.d_name = STRDUP(ds->fdata.cFileName);
486
NSAPI_PUBLIC void dir_close(SYS_DIR ds)
494
#endif /* FILE_WIN32 */
496
NSAPI_PUBLIC int file_notfound(void)
499
int errn = PR_GetError();
500
return (errn == PR_FILE_NOT_FOUND_ERROR);
502
return (errno == ENOENT);
507
#if !defined(SNI) && !defined(LINUX)
508
extern char *sys_errlist[];
512
#define ERRMSG_SIZE 35
514
static int errmsg_key = -1;
516
/* Removed for ns security integration
517
#include "xp_error.h"
519
#else /* THREAD_ANY */
520
static char errmsg[ERRMSG_SIZE];
521
#endif /* THREAD_ANY */
525
void system_errmsg_init(void)
527
if (errmsg_key == -1) {
528
#if defined(THREAD_ANY)
529
errmsg_key = systhread_newkey();
534
if (!_atomic_write_lock)
535
_atomic_write_lock = PR_NewLock();
539
NSAPI_PUBLIC int system_errmsg_fn(char **buff, size_t maxlen)
541
char static_error[128];
542
char *lmsg = 0; /* Local message pointer */
544
PRErrorCode nscp_error;
549
nscp_error = PR_GetError();
551
/* If there is a NSPR error, but it is "unknown", try to get the OSError
552
* and use that instead.
554
if (nscp_error == PR_UNKNOWN_ERROR)
555
errno = PR_GetOSError();
557
if (nscp_error != 0 && nscp_error != PR_UNKNOWN_ERROR){
558
char *nscp_error_msg;
560
nscp_error_msg = nscperror_lookup(nscp_error);
563
lmsg = nscp_error_msg;
565
util_snprintf(static_error, sizeof(static_error), "unknown error %d", nscp_error);
569
#if defined(XP_WIN32)
570
msglen = FormatMessage(
571
FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_ALLOCATE_BUFFER,
574
LOCALE_SYSTEM_DEFAULT,
581
lmsg = system_winerr();
585
#if defined(SNI) || defined(LINUX)
586
/ C++ platform has no definition for sys_errlist /
587
lmsg = strerror(errno);
589
lmsg = sys_errlist[errno];
591
with lmsg =strerror(errno);*/
592
lmsg=strerror(errno);
597
/* At this point lmsg points to something. */
598
msglen = strlen(lmsg);
601
*buff = STRDUP(lmsg);
602
else if (maxlen > msglen)
603
memcpy(*buff, lmsg, msglen+1);
608
/* NT's FormatMessage() dynamically allocated the msg; free it */
616
NSAPI_PUBLIC const char *
621
if (errmsg_key == -1)
622
return "unknown early startup error";
624
// rmaxwell - This is extremely lame.
625
// Allocate a buffer in thread local storage to
626
// hold the last error message.
627
// The whole error message facility is broken and should be
628
// updated to get error strings out of the code.
629
if(!(buff = (char *) systhread_getdata(errmsg_key))) {
630
buff = (char *) PERM_MALLOC(errbuf_size);
631
systhread_setdata(errmsg_key, (void *)buff);
633
system_errmsg_fn(&buff, errbuf_size);
635
return "Could not retrieve system error message";
640
system_rename(char *oldpath, char *newpath)
642
return rename(oldpath, newpath);
646
system_unlink(char *path)
648
return PR_Delete(path)==PR_FAILURE?-1:0;
651
NSAPI_PUBLIC int system_lseek(SYS_FILE fd, int off, int wh)
655
return PR_Seek(fd, off, PR_SEEK_SET);
658
return PR_Seek(fd, off, PR_SEEK_CUR);
661
return PR_Seek(fd, off, PR_SEEK_END);
669
system_tlock(SYS_FILE fd)
671
return PR_TLockFile(fd);
675
system_flock(SYS_FILE fd)
677
return PR_LockFile(fd);
681
system_ulock(SYS_FILE fd)
683
return PR_UnlockFile(fd);