summaryrefslogtreecommitdiffstats
path: root/private/crt32/lowio/open.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/crt32/lowio/open.c')
-rw-r--r--private/crt32/lowio/open.c590
1 files changed, 590 insertions, 0 deletions
diff --git a/private/crt32/lowio/open.c b/private/crt32/lowio/open.c
new file mode 100644
index 000000000..a365f4aac
--- /dev/null
+++ b/private/crt32/lowio/open.c
@@ -0,0 +1,590 @@
+/***
+*open.c - file open
+*
+* Copyright (c) 1989-1993, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* defines _open() and _sopen() - open or create a file
+*
+*Revision History:
+* 06-13-89 PHG Module created, based on asm version
+* 11-11-89 JCR Replaced DOS32QUERYFILEMODE with DOS32QUERYPATHINFO
+* 03-13-90 GJF Made calling type _CALLTYPE2 (for now), added #include
+* <cruntime.h>, fixed some compiler warnings and fixed
+* copyright. Also, cleaned up the formatting a bit.
+* 07-24-90 SBM Removed '32' from API names
+* 08-14-90 SBM Compiles cleanly with -W3
+* 09-07-90 SBM Added stdarg code (inside #if 0..#endif) to make
+* open and sopen match prototypes. Test and use this
+* someday.
+* 10-01-90 GJF New-style function declarators.
+* 11-16-90 GJF Wrote version for Win32 API and appended it via an
+* #ifdef. The Win32 version is similar to the old DOS
+* version (though in C) and far different from either
+* the Cruiser or OS/2 versions.
+* 12-03-90 GJF Fixed a dozen or so minor errors in the Win32 version.
+* 12-06-90 SRW Changed to use _osfile and _osfhnd instead of _osfinfo
+* 12-28-90 SRW Added cast of void * to char * for Mips C Compiler
+* 12-31-90 SRW Fixed spen to call CreateFile instead of OpenFile
+* 01-16-91 GJF ANSI naming.
+* 02-07-91 SRW Changed to call _get_osfhandle [_WIN32_]
+* 02-19-91 SRW Adapt to OpenFile/CreateFile changes [_WIN32_]
+* 02-25-91 SRW Renamed _get_free_osfhnd to be _alloc_osfhnd [_WIN32_]
+* 04-09-91 PNT Added _MAC_ conditional
+* 07-10-91 GJF Store fileflags into _osfile array before call to
+* _lseek_lk (bug found by LarryO) [_WIN32_].
+* 01-02-92 GJF Fixed Win32 version (not Cruiser!) so that pmode is not
+* referenced unless _O_CREAT has been specified.
+* 02-04-92 GJF Make better use of CreateFile options.
+* 04-06-92 SRW Pay attention to _O_NOINHERIT flag in oflag parameter
+* 05-02-92 SRW Add support for _O_TEMPORARY flag in oflag parameter.
+* Causes FILE_ATTRIBUTE_TEMPORARY flag to be set in call
+* to the Win32 CreateFile API.
+* 07-01-92 GJF Close handle in case of error. Also, don't try to set
+* FRDONLY bit anymore - no longer needed/used. [_WIN32_].
+* 01-03-93 SRW Fix va_arg/va_end usage
+* 05-24-93 PML Add support for _O_SEQUENTIAL, _O_RANDOM,
+* and _O_SHORT_LIVED
+*
+*******************************************************************************/
+
+#include <cruntime.h>
+#include <oscalls.h>
+#include <msdos.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <internal.h>
+#include <io.h>
+#include <share.h>
+#include <stdlib.h>
+#include <sys\types.h>
+#include <sys\stat.h>
+#include <os2dll.h>
+#include <stdarg.h>
+
+/***
+*int _open(path, flag, pmode) - open or create a file
+*
+*Purpose:
+* Opens the file and prepares for subsequent reading or writing.
+* the flag argument specifies how to open the file:
+* _O_APPEND - reposition file ptr to end before every write
+* _O_BINARY - open in binary mode
+* _O_CREAT - create a new file* no effect if file already exists
+* _O_EXCL - return error if file exists, only use with O_CREAT
+* _O_RDONLY - open for reading only
+* _O_RDWR - open for reading and writing
+* _O_TEXT - open in text mode
+* _O_TRUNC - open and truncate to 0 length (must have write permission)
+* _O_WRONLY - open for writing only
+* _O_NOINHERIT -handle will not be inherited by child processes.
+* exactly one of _O_RDONLY, _O_WRONLY, _O_RDWR must be given
+*
+* The pmode argument is only required when _O_CREAT is specified. Its
+* flag settings:
+* _S_IWRITE - writing permitted
+* _S_IREAD - reading permitted
+* _S_IREAD | _S_IWRITE - both reading and writing permitted
+* The current file-permission maks is applied to pmode before
+* setting the permission (see umask).
+*
+* The oflag and mode parameter have different meanings under DOS. See
+* the A_xxx attributes in msdos.inc
+*
+* Note, the _creat() function also uses this function but setting up the
+* correct arguments and calling _open(). _creat() sets the __creat_flag
+* to 1 prior to calling _open() so _open() can return correctly. _open()
+* returns the file handle in eax in this case.
+*
+*Entry:
+* char *path - file name
+* int flag - flags for _open()
+* int pmode - permission mode for new files
+*
+*Exit:
+* returns file handle of open file if successful
+* returns -1 (and sets errno) if fails
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+int _CRTAPI2 _open (
+ const char *path,
+ int oflag,
+ ...
+ )
+{
+ va_list ap;
+ int pmode;
+
+ va_start(ap, oflag);
+ pmode = va_arg(ap, int);
+ va_end(ap);
+
+ /* default sharing mode is DENY NONE */
+ return _sopen(path, oflag, _SH_DENYNO, pmode);
+}
+
+/***
+*int _sopen(path, oflag, shflag, pmode) - opne a file with sharing
+*
+*Purpose:
+* Opens the file with possible file sharing.
+* shflag defines the sharing flags:
+* _SH_COMPAT - set compatability mode
+* _SH_DENYRW - deny read and write access to the file
+* _SH_DENYWR - deny write access to the file
+* _SH_DENYRD - deny read access to the file
+* _SH_DENYNO - permit read and write access
+*
+* Other flags are the same as _open().
+*
+* SOPEN is the routine used when file sharing is desired.
+*
+*Entry:
+* char *path - file to open
+* int oflag - open flag
+* int shflag - sharing flag
+* int pmode - permission mode (needed only when creating file)
+*
+*Exit:
+* returns file handle for the opened file
+* returns -1 and sets errno if fails.
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+int _CRTAPI2 _sopen (
+ const char *path,
+ int oflag,
+ int shflag,
+ ...
+ )
+{
+
+ int fh; /* handle of opened file */
+ int filepos; /* length of file - 1 */
+ char ch; /* character at end of file */
+ char fileflags; /* _osfile flags */
+ va_list ap; /* variable argument (pmode) */
+ int pmode;
+
+#ifdef _CRUISER_
+ int t; /* temp */
+ int dosretval; /* OS/2 return value */
+ int isdev; /* device indicator in low byte */
+ int attrib; /* attribute */
+ int openflag; /* OS/2 open flag */
+ int openmode; /* OS/2 open mode */
+#endif /* _CRUISER_ */
+
+#ifdef _WIN32_
+ HANDLE osfh; /* OS handle of opened file */
+ DWORD fileaccess; /* OS file access (requested) */
+ DWORD fileshare; /* OS file sharing mode */
+ DWORD filecreate; /* OS method of opening/creating */
+ DWORD fileattrib; /* OS file attribute flags */
+ DWORD isdev; /* device indicator in low byte */
+ SECURITY_ATTRIBUTES SecurityAttributes;
+
+ SecurityAttributes.nLength = sizeof( SecurityAttributes );
+ SecurityAttributes.lpSecurityDescriptor = NULL;
+ if (oflag & _O_NOINHERIT) {
+ SecurityAttributes.bInheritHandle = FALSE;
+ }
+ else {
+ SecurityAttributes.bInheritHandle = TRUE;
+ }
+
+#endif /* _WIN32_ */
+#ifdef _CRUISER_
+/* Set up variable argument list stuff */
+
+ va_start(ap, shflag);
+ pmode = va_arg(ap, int);
+ va_end(ap);
+#endif
+
+ /* figure out binary/text mode */
+ if (oflag & _O_BINARY)
+ fileflags = 0;
+ else if (oflag & _O_TEXT)
+ fileflags = (char)FTEXT;
+ else if (_fmode == _O_BINARY) /* check default mode */
+ fileflags = 0;
+ else
+ fileflags = (char)FTEXT;
+
+#ifdef _CRUISER_ /* CRUISER TARGET */
+
+/* code requires below conditions */
+#if _O_RDONLY != OPEN_ACCESS_READONLY || _O_WRONLY != OPEN_ACCESS_WRITEONLY || _O_RDWR != OPEN_ACCESS_READWRITE
+ #error OS/2 and XENIX flags not compatible
+#endif
+#if _O_RDWR != 2 || _O_RDONLY != 0 || _O_WRONLY != 1
+ #error access flags are wrong
+#endif
+
+/*
+ Set up the OpenMode and OpenFlag parameters for the DOSOPEN call
+
+ OpenMode fields will be set as follows:
+ high byte
+ DASD 0 (normal file)
+ File Write-through 0 (use buffer cache)
+ Fail-Errors 0 (use hard error handler)
+ low byte
+ Inheritance 0 (child inherits files)
+ Sharing Mode <from shflag param>
+ Access Mode <from oflag parameter>
+
+ OpenFlag bytes are set as follows:
+ high byte
+ 0x00
+ low byte - low nibble
+ 0x0 _O_EXCL specified
+ 0x2 _O_TRUNC specified
+ 0x1 otherwise
+ low byte - high nibble
+ 0x1 _O_CREAT specified
+ 0x0 otherwise
+*/
+
+
+ /* first, convert the permission mode to the DOS attribute byte */
+ if ((pmode & ~_umaskval) & _S_IWRITE)
+ attrib = 0; /* writable */
+ else
+ attrib = FILE_READONLY; /* read-only */
+
+ if ((oflag & _O_EXCL) && !(oflag & _O_CREAT))
+ oflag &= ~_O_EXCL; /* _O_EXCL only works with _O_CREAT */
+
+ if (oflag & _O_EXCL) {
+ openflag = 0; /* just create */
+ }
+ else if (oflag & _O_TRUNC) {
+ FILESTATUS fs; /* File Status structure */
+
+ openflag = FILE_TRUNCATE; /* truncate file */
+
+ /* if the file exists, don't change its attribute */
+ if (!DOSQUERYPATHINFO((char *)path, 1, &fs, sizeof(fs)))
+ /* file exists, use current attribute */
+ attrib = fs.attrFile;
+ }
+ else
+ openflag = FILE_OPEN; /* open the file */
+
+ if (oflag & _O_CREAT)
+ openflag |= FILE_CREATE;
+
+ /* here we take advantage of the fact that OS/2 and XENIX access flags
+ are the same bits -- the bottom two */
+ openmode = shflag | (oflag & 3);
+
+ /* OK, we're now ready to open the file */
+ if (dosretval = DOSOPEN((char *)path, &fh, &t, 0, attrib, openflag,
+ openmode, 0, 0)) {
+ /* OS/2 error occured */
+ if (dosretval == ERROR_OPEN_FAILED) {
+ _doserrno = dosretval;
+ if (openflag & FILE_CREATE)
+ errno = EEXIST; /* file existed */
+ else
+ errno = ENOENT; /* file didn't exist */
+ return -1;
+ }
+ else {
+ _dosmaperr(dosretval); /* map error */
+ return -1;
+ }
+ }
+
+ if ((unsigned)fh >= (unsigned)_nfile) {
+ /* handle is out of range; close and return EMFILE */
+ DOSCLOSE(fh);
+ errno = EMFILE;
+ _doserrno = 0; /* not OS/2 error */
+ return -1;
+ }
+
+ _lock_fh(fh); /* lock the file handle */
+
+ /* find out what type of file (file/device/pipe) */
+ if (dosretval = DOSQUERYHTYPE(fh, &isdev, &t)) {
+ /* OS/2 error */
+ _unlock_fh(fh);
+ _dosmaperr(dosretval); /* map error */
+ return -1;
+ }
+
+ /* is isdev value to set flags */
+ if ((isdev & 0xFF) == HANDTYPE_DEVICE)
+ fileflags |= FDEV;
+ else if ((isdev & 0xFF) == HANDTYPE_PIPE)
+ fileflags |= FPIPE;
+
+#else /* ndef _CRUISER_ */
+
+#ifdef _WIN32_
+
+ /*
+ * decode the access flags
+ */
+ switch( oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR) ) {
+
+ case _O_RDONLY: /* read access */
+ fileaccess = GENERIC_READ;
+ break;
+ case _O_WRONLY: /* write access */
+ fileaccess = GENERIC_WRITE;
+ break;
+ case _O_RDWR: /* read and write access */
+ fileaccess = GENERIC_READ | GENERIC_WRITE;
+ break;
+ default: /* error, bad oflag */
+ errno = EINVAL;
+ _doserrno = 0L; /* not an OS error */
+ return -1;
+ }
+
+ /*
+ * decode sharing flags
+ */
+ switch ( shflag ) {
+
+ case _SH_DENYRW: /* exclusive access */
+ fileshare = 0L;
+ break;
+
+ case _SH_DENYWR: /* share read access */
+ fileshare = FILE_SHARE_READ;
+ break;
+
+ case _SH_DENYRD: /* share write access */
+ fileshare = FILE_SHARE_WRITE;
+ break;
+
+ case _SH_DENYNO: /* share read and write access */
+ fileshare = FILE_SHARE_READ | FILE_SHARE_WRITE;
+ break;
+
+ default: /* error, bad shflag */
+ errno = EINVAL;
+ _doserrno = 0L; /* not an OS error */
+ return -1;
+ }
+
+ /*
+ * decode open/create method flags
+ */
+ switch ( oflag & (_O_CREAT | _O_EXCL | _O_TRUNC) ) {
+ case 0:
+ filecreate = OPEN_EXISTING;
+ break;
+
+ case _O_CREAT:
+ filecreate = OPEN_ALWAYS;
+ break;
+
+ case _O_CREAT | _O_EXCL:
+ filecreate = CREATE_NEW;
+ break;
+
+ case _O_TRUNC:
+ filecreate = TRUNCATE_EXISTING;
+ break;
+
+ case _O_CREAT | _O_TRUNC:
+ filecreate = CREATE_ALWAYS;
+ break;
+
+ default:
+ errno = EINVAL;
+ _doserrno = 0L;
+ return -1;
+ }
+
+ /*
+ * decode file attribute flags if _O_CREAT was specified
+ */
+ fileattrib = FILE_ATTRIBUTE_NORMAL; /* default */
+
+ if ( oflag & _O_CREAT ) {
+ /*
+ * set up variable argument list stuff
+ */
+ va_start(ap, shflag);
+ pmode = va_arg(ap, int);
+ va_end(ap);
+
+ if ( !((pmode & ~_umaskval) & _S_IWRITE) )
+ fileattrib = FILE_ATTRIBUTE_READONLY;
+ }
+
+ /*
+ * Set temporary file (delete-on-close) attribute if requested.
+ */
+ if ( oflag & _O_TEMPORARY ) {
+ fileattrib |= FILE_FLAG_DELETE_ON_CLOSE;
+ fileaccess |= DELETE;
+ }
+
+ /*
+ * Set temporary file (delay-flush-to-disk) attribute if requested.
+ */
+ if ( oflag & _O_SHORT_LIVED )
+ fileattrib |= FILE_ATTRIBUTE_TEMPORARY;
+
+ /*
+ * Set sequential or random access attribute if requested.
+ */
+ if ( oflag & _O_SEQUENTIAL )
+ fileattrib |= FILE_FLAG_SEQUENTIAL_SCAN;
+ else if ( oflag & _O_RANDOM )
+ fileattrib |= FILE_FLAG_RANDOM_ACCESS;
+
+ /*
+ * get an available handle.
+ *
+ * multi-thread note: the returned handle is locked!
+ */
+ if ( (fh = _alloc_osfhnd()) == -1 ) {
+ errno = EMFILE; /* too many open files */
+ _doserrno = 0L; /* not an OS error */
+ return -1; /* return error to caller */
+ }
+
+ /*
+ * try to open/create the file
+ */
+ if ( (osfh = CreateFile((LPSTR)path,
+ fileaccess,
+ fileshare,
+ &SecurityAttributes,
+ filecreate,
+ fileattrib,
+ NULL
+ ))
+ == (HANDLE)0xffffffff ) {
+ /*
+ * OS call to open/create file failed! map the error, release
+ * the lock, and return -1. note that it's not necessary to
+ * call _free_osfhnd (it hasn't been used yet).
+ */
+ _dosmaperr(GetLastError()); /* map error */
+ _unlock_fh(fh);
+ return -1; /* return error to caller */
+ }
+
+ /* find out what type of file (file/device/pipe) */
+ if ( (isdev = GetFileType(osfh)) == FILE_TYPE_UNKNOWN ) {
+ CloseHandle(osfh);
+ _dosmaperr(GetLastError()); /* map error */
+ _unlock_fh(fh);
+ return -1;
+ }
+
+ /* is isdev value to set flags */
+ if (isdev == FILE_TYPE_CHAR)
+ fileflags |= FDEV;
+ else if (isdev == FILE_TYPE_PIPE)
+ fileflags |= FPIPE;
+
+ /*
+ * the file is open. now, set the info in _osfhnd array
+ */
+ _set_osfhnd(fh, (long)osfh);
+
+#else /* ndef _WIN32_ */
+
+#ifdef _MAC_
+
+ TBD();
+
+#else /* ndef _MAC_ */
+
+#error ERROR - ONLY CRUISER, WIN32, OR MAC TARGET SUPPORTED!
+
+#endif /* _MAC_ */
+
+#endif /* _WIN32_ */
+
+#endif /* _CRUISER_ */
+
+ /*
+ * mark the handle as open. store flags gathered so far in _osfile
+ * array.
+ */
+ fileflags |= FOPEN;
+ _osfile[fh] = fileflags;
+
+ if (!(fileflags & (FDEV|FPIPE)) && (fileflags & FTEXT) &&
+ (oflag & _O_RDWR)) {
+ /* We have a text mode file. If it ends in CTRL-Z, we wish to
+ remove the CTRL-Z character, so that appending will work.
+ We do this by seeking to the end of file, reading the last
+ byte, and shortening the file if it is a CTRL-Z. */
+
+ if ((filepos = _lseek_lk(fh, -1, FILE_END)) == -1) {
+ /* OS error -- should ignore negative seek error,
+ since that means we had a zero-length file. */
+ if (_doserrno != ERROR_NEGATIVE_SEEK) {
+ _close(fh);
+ _unlock_fh(fh);
+ return -1;
+ }
+ }
+ else {
+ /* seek was OK, read the last char in file */
+ if (_read_lk(fh, &ch, 1) == 1 && ch == 26) {
+ /* read was OK and we got CTRL-Z! Wipe it
+ out! */
+ if (_chsize_lk(fh,filepos) == -1)
+ {
+ _close(fh);
+ _unlock_fh(fh);
+ return -1;
+ }
+ }
+
+ /* now rewind the file to the beginning */
+ if ((filepos = _lseek_lk(fh, 0, FILE_BEGIN)) == -1) {
+ _close(fh);
+ _unlock_fh(fh);
+ return -1;
+ }
+ }
+ }
+
+#ifdef _CRUISER_
+ /* We want to know if we have write access to set the FRDONLY flag
+ in the _osfile entry. We also set the FAPPEND flag.
+ Don't do this for pipes or devices. */
+
+ if (!(fileflags & (FDEV|FPIPE))) {
+ if (_access((char *)path, 2) == -1)
+ _osfile[fh] |= FRDONLY;
+
+ if (oflag & _O_APPEND)
+ _osfile[fh] |= FAPPEND;
+ }
+#else /* ndef _CRUISER_ */
+#ifdef _WIN32_
+
+ /*
+ * Set FAPPEND flag if appropriate. Don't do this for devices or pipes.
+ */
+ if ( !(fileflags & (FDEV|FPIPE)) && (oflag & _O_APPEND) )
+ _osfile[fh] |= FAPPEND;
+
+#endif /* _WIN32_ */
+#endif /* _CRUISER_*/
+
+ _unlock_fh(fh); /* unlock handle */
+
+ return fh; /* return handle */
+}