📄 open.c
字号:
/* $Id: open.c 25049 2006-12-03 21:06:03Z fireball $
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS system libraries
* FILE: lib/msvcrt/io/open.c
* PURPOSE: Opens a file and translates handles to fileno
* PROGRAMER: Ariadne
* UPDATE HISTORY:
* 28/12/98: Created
*/
/*
* Some stuff taken from active perl: perl\win32.c (ioinfo stuff)
*
* (c) 1995 Microsoft Corporation. All rights reserved.
* Developed by hip communications inc., http://info.hip.com/info/
* Portions (c) 1993 Intergraph Corporation. All rights reserved.
*
* You may distribute under the terms of either the GNU General Public
* License or the Artistic License, as specified in the README file.
*/
/*
* Some functions taken from/based on wine\dlls\msvcrt\file.c:
* split_oflags
* _open_osfhandle
* many more...
*
* Copyright 1996,1998 Marcus Meissner
* Copyright 1996 Jukka Iivonen
* Copyright 1997,2000 Uwe Bonnes
* Copyright 2000 Jon Griffiths
* Copyright 2004 Eric Pouech
* Copyright 2004 Juan Lang
*/
// rember to interlock the allocation of fileno when making this thread safe
// possibly store extra information at the handle
#include <precomp.h>
#if !defined(NDEBUG) && defined(DBG)
#include <stdarg.h>
#endif
#include <sys/stat.h>
#include <string.h>
#include <share.h>
#define NDEBUG
#include <internal/debug.h>
FDINFO first_bucket[FDINFO_ENTRIES_PER_BUCKET];
FDINFO* __pioinfo[FDINFO_BUCKETS] = {first_bucket};
/* This critical section protects the tables MSVCRT_fdesc and MSVCRT_fstreams,
* and their related indexes, MSVCRT_fdstart, MSVCRT_fdend,
* and MSVCRT_stream_idx, from race conditions.
* It doesn't protect against race conditions manipulating the underlying files
* or flags; doing so would probably be better accomplished with per-file
* protection, rather than locking the whole table for every change.
*/
static CRITICAL_SECTION g_file_cs;
#define LOCK_FILES() do { EnterCriticalSection(&g_file_cs); } while (0)
#define UNLOCK_FILES() do { LeaveCriticalSection(&g_file_cs); } while (0)
/////////////////////////////////////////
static int g_fdstart = 3; /* first unallocated fd */
static int g_fdend = 3; /* highest allocated fd */
/*
* INTERNAL
*/
/*
static __inline FD_INFO* fdinfo(int fd)
{
FD_INFO* bucket = __pioinfo[fd >> FDINFO_ENTRIES_PER_BUCKET_SHIFT];
if (!bucket){
bucket = alloc_init_bucket(fd);
}
return bucket + (fd & (FDINFO_ENTRIES_PER_BUCKET - 1));
}
*/
/*
* INTERNAL
*/
__inline BOOL is_valid_fd(int fd)
{
BOOL b = (fd >= 0 && fd < g_fdend && (fdinfo(fd)->fdflags & FOPEN));
if (!b){
if (fd >= 0 && fd < g_fdend)
{
DPRINT1("not valid fd %i, g_fdend %i, fdinfo %x, bucket %x, fdflags %x\n",
fd,g_fdend,fdinfo(fd),fdinfo_bucket(fd),fdinfo(fd)->fdflags);
}
else
{
DPRINT1("not valid fd %i, g_fdend %i\n",fd,g_fdend);
}
}
return b;
}
/*
* INTERNAL
*/
char split_oflags(int oflags)
{
char fdflags = 0;
if (oflags & _O_APPEND) fdflags |= FAPPEND;
if (oflags & _O_BINARY) ;
else if (oflags & _O_TEXT) fdflags |= FTEXT;
else if (_fmode& _O_BINARY) ;
else fdflags |= FTEXT; /* default to TEXT*/
if (oflags & _O_NOINHERIT) fdflags |= FNOINHERIT;
if (oflags & ~(_O_BINARY|_O_TEXT|_O_APPEND|_O_TRUNC|
_O_EXCL|_O_CREAT|_O_RDWR|_O_WRONLY|
_O_TEMPORARY|_O_NOINHERIT))
DPRINT1(":unsupported oflags 0x%04x\n",oflags);
return fdflags;
}
/*
* INTERNAL
*/
char __is_text_file(FILE* p)
{
if ( p == NULL || fdinfo_bucket((p)->_file) == NULL )
return FALSE;
return (!((p)->_flag&_IOSTRG) && (fdinfo((p)->_file)->fdflags & FTEXT));
}
/*
* @implemented
*/
int _open(const char* _path, int _oflag,...)
{
#if !defined(NDEBUG) && defined(DBG)
va_list arg;
int pmode;
#endif
HANDLE hFile;
DWORD dwDesiredAccess = 0;
DWORD dwShareMode = 0;
DWORD dwCreationDistribution = 0;
DWORD dwFlagsAndAttributes = 0;
SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
#if !defined(NDEBUG) && defined(DBG)
va_start(arg, _oflag);
pmode = va_arg(arg, int);
#endif
TRACE("_open('%s', %x, (%x))\n", _path, _oflag);
if ((_oflag & S_IREAD ) == S_IREAD)
dwShareMode = FILE_SHARE_READ;
else if ((_oflag & S_IWRITE) == S_IWRITE) {
dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
}
/*
*
* _O_BINARY Opens file in binary (untranslated) mode. (See fopen for a description of binary mode.)
* _O_TEXT Opens file in text (translated) mode. (For more information, see Text and Binary Mode File I/O and fopen.)
*
* _O_APPEND Moves file pointer to end of file before every write operation.
*/
#ifdef _OLD_BUILD_
if ((_oflag & _O_RDWR) == _O_RDWR)
dwDesiredAccess |= GENERIC_WRITE|GENERIC_READ;
else if ((_oflag & O_RDONLY) == O_RDONLY)
dwDesiredAccess |= GENERIC_READ;
else if ((_oflag & _O_WRONLY) == _O_WRONLY)
dwDesiredAccess |= GENERIC_WRITE ;
#else
if ((_oflag & _O_WRONLY) == _O_WRONLY )
dwDesiredAccess |= GENERIC_WRITE ;
else if ((_oflag & _O_RDWR) == _O_RDWR )
dwDesiredAccess |= GENERIC_WRITE|GENERIC_READ;
else //if ((_oflag & O_RDONLY) == O_RDONLY)
dwDesiredAccess |= GENERIC_READ;
#endif
if (( _oflag & (_O_CREAT | _O_EXCL)) == (_O_CREAT | _O_EXCL))
dwCreationDistribution |= CREATE_NEW;
else if ((_oflag & O_TRUNC ) == O_TRUNC) {
if ((_oflag & O_CREAT ) == O_CREAT)
dwCreationDistribution |= CREATE_ALWAYS;
else if ((_oflag & O_RDONLY ) != O_RDONLY)
dwCreationDistribution |= TRUNCATE_EXISTING;
}
else if ((_oflag & _O_APPEND) == _O_APPEND)
dwCreationDistribution |= OPEN_EXISTING;
else if ((_oflag & _O_CREAT) == _O_CREAT)
dwCreationDistribution |= OPEN_ALWAYS;
else
dwCreationDistribution |= OPEN_EXISTING;
if ((_oflag & _O_RANDOM) == _O_RANDOM )
dwFlagsAndAttributes |= FILE_FLAG_RANDOM_ACCESS;
if ((_oflag & _O_SEQUENTIAL) == _O_SEQUENTIAL)
dwFlagsAndAttributes |= FILE_FLAG_SEQUENTIAL_SCAN;
if ((_oflag & _O_TEMPORARY) == _O_TEMPORARY) {
dwFlagsAndAttributes |= FILE_FLAG_DELETE_ON_CLOSE;
DPRINT("FILE_FLAG_DELETE_ON_CLOSE\n");
}
if ((_oflag & _O_SHORT_LIVED) == _O_SHORT_LIVED) {
dwFlagsAndAttributes |= FILE_FLAG_DELETE_ON_CLOSE;
DPRINT("FILE_FLAG_DELETE_ON_CLOSE\n");
}
if (_oflag & _O_NOINHERIT)
sa.bInheritHandle = FALSE;
if (dwCreationDistribution == OPEN_EXISTING &&
(dwDesiredAccess & (GENERIC_WRITE|GENERIC_READ)) == GENERIC_READ) {
/* Allow always shared read for a file which is opened for read only */
dwShareMode |= FILE_SHARE_READ;
}
hFile = CreateFileA(_path,
dwDesiredAccess,
dwShareMode,
&sa,
dwCreationDistribution,
dwFlagsAndAttributes,
NULL);
if (hFile == (HANDLE)-1) {
_dosmaperr(GetLastError());
return( -1);
}
DPRINT("OK\n");
if (!(_oflag & (_O_TEXT|_O_BINARY))) {
_oflag |= _fmode;
}
return(alloc_fd(hFile, split_oflags(_oflag)));
}
/*
* INTERNAL
*/
static void init_bucket(FDINFO* entry)
{
int i;
for(i=0;
i < FDINFO_ENTRIES_PER_BUCKET;
i++, entry++)
{
entry->hFile = INVALID_HANDLE_VALUE;
entry->fdflags = 0;
entry->pipechar = LF;
entry->lockinitflag = 0;
}
}
/*
* INTERNAL
*/
static BOOL alloc_init_bucket(int fd)
{
fdinfo_bucket(fd) = malloc(FDINFO_ENTRIES_PER_BUCKET * sizeof(FDINFO));
if (!fdinfo_bucket(fd)) return FALSE;
init_bucket(fdinfo_bucket(fd));
return TRUE;
}
/*
* INTERNAL
* Allocate an fd slot from a Win32 HANDLE, starting from fd
* caller must hold the files lock
*/
static int alloc_fd_from(HANDLE hand, char flag, int fd)
{
if (fd >= FDINFO_ENTRIES)
{
DPRINT1("files exhausted!\n");
return -1;
}
if (!fdinfo_bucket(fd))
{
if (!alloc_init_bucket(fd)){
//errno = ENOMEM
return -1;
}
}
fdinfo(fd)->hFile = hand;
fdinfo(fd)->fdflags = FOPEN | (flag & (FNOINHERIT | FAPPEND | FTEXT));
fdinfo(fd)->pipechar = LF;
fdinfo(fd)->lockinitflag = 0;
//fdinfo(fd)->lock
/* locate next free slot */
if (fd == g_fdstart && fd == g_fdend)
{
g_fdstart = g_fdend + 1;
}
else
{
#if 0 /* alternate (untested) impl. maybe a tiny bit faster? -Gunnar */
int i, bidx;
for (bidx = fdinfo_bucket_idx(g_fdstart); bidx < FDINFO_BUCKETS && __pioinfo[bidx]; bidx++)
{
for (i = fdinfo_bucket_entry_idx(g_fdstart);
g_fdstart < g_fdend && fdinfo(g_fdstart)->fdflags & FOPEN && i < FDINFO_BUCKET_ENTRIES;
i++)
{
g_fdstart++;
}
}
#else
while (g_fdstart < g_fdend &&
fdinfo_bucket(g_fdstart) &&
(fdinfo(g_fdstart)->fdflags & FOPEN))
{
g_fdstart++;
}
#endif
}
/* update last fd in use */
if (fd >= g_fdend)
g_fdend = fd + 1;
/* alloc more fdinfo buckets by demand.
* FIXME: should we dealloc buckets when they become unused also? */
if (!fdinfo_bucket(g_fdstart) && g_fdstart < FDINFO_ENTRIES)
{
alloc_init_bucket(g_fdstart);
}
DPRINT("fdstart is %d, fdend is %d\n", g_fdstart, g_fdend);
switch (fd)
{
case 0: SetStdHandle(STD_INPUT_HANDLE, hand); break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -