/*** *open.c - file open * * Copyright (c) 1989-2001, 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 * , 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 * 04-06-93 SKS Replace _CRTAPI* with __cdecl * 05-24-93 PML Add support for _O_SEQUENTIAL, _O_RANDOM, * and _O_SHORT_LIVED * 07-12-93 GJF Fixed bug in reading last char in text file. Also,use * proper SEEK constants in _lseek_lk calls. * 11-01-93 CFW Enable Unicode variant, rip out CRUISER. * 02-15-95 GJF Appended Mac version of source file (somewhat cleaned * up), with appropriate #ifdef-s. * 06-06-95 CFW Enable shared writing. * 06-12-95 GJF Replaced _osfile[] with _osfile() (macro referencing * field in ioinfo struct). * 05-16-96 GJF Propagate _O_NOINHERIT to FNOINHERIT (new _osfile * bit). Also detab-ed. * 05-31-96 SKS Fix expression error in GJF's most recent check-in * 07-08-96 GJF Replaced defined(_WIN32) with !defined(_MAC), and * defined(_M_M68K) || defined(_M_MPPC) with * defined(_MAC). Also, cleaned up the format a bit. * 08-01-96 RDK For PMac, change data type for _endlowio terminator * pointer, use safer PBHOpenDFSync call, and process * _O_TEMPORARY open flag to implement delete after close. * 12-29-97 GJF Exception-safe locking. * 02-07-98 GJF Changes for Win64: arg type for _set_osfhnd is now * intptr_t. * 04-28-99 PML Wrap __declspec(allocate()) in _CRTALLOC macro. * 05-17-99 PML Remove all Macintosh support. * 10-27-99 GB VS7#14742 made a fix for opening the file in * O_TEMPORARY mode so as to enable sucessive open on the * same file if share permissions are there. * *******************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef _MT static int __cdecl _tsopen_lk ( int *, int *, const _TSCHAR *, int, int, int ); #endif /* _MT */ /*** *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: * _TSCHAR *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 __cdecl _topen ( const _TSCHAR *path, int oflag, ... ) { va_list ap; int pmode; #ifdef _MT int fh; int retval; int unlock_flag = 0; #endif /* MT */ va_start(ap, oflag); pmode = va_arg(ap, int); va_end(ap); #ifdef _MT __try { retval = _tsopen_lk( &unlock_flag, &fh, path, oflag, _SH_DENYNO, pmode ); } __finally { if ( unlock_flag ) _unlock_fh(fh); } return retval; #else /* ndef _MT */ /* default sharing mode is DENY NONE */ return _tsopen(path, oflag, _SH_DENYNO, pmode); #endif /* _MT */ } /*** *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: * _TSCHAR *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 __cdecl _tsopen ( const _TSCHAR *path, int oflag, int shflag, ... ) { #ifdef _MT va_list ap; int pmode; int fh; int retval; int unlock_flag = 0; va_start(ap, shflag); pmode = va_arg(ap, int); va_end(ap); __try { retval = _tsopen_lk( &unlock_flag, &fh, path, oflag, shflag, pmode ); } __finally { if ( unlock_flag ) _unlock_fh(fh); } return retval; } static int __cdecl _tsopen_lk ( int *punlock_flag, int *pfh, const _TSCHAR *path, int oflag, int shflag, int pmode ) { #endif /* _MT */ int fh; /* handle of opened file */ int filepos; /* length of file - 1 */ _TSCHAR ch; /* character at end of file */ char fileflags; /* _osfile flags */ #ifndef _MT va_list ap; int pmode; #endif /* _MT */ 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; fileflags = FNOINHERIT; } else { SecurityAttributes.bInheritHandle = TRUE; fileflags = 0; } /* figure out binary/text mode */ if ((oflag & _O_BINARY) == 0) if (oflag & _O_TEXT) fileflags |= FTEXT; else if (_fmode != _O_BINARY) /* check default mode */ fileflags |= FTEXT; /* * 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: case _O_EXCL: // ignore EXCL w/o CREAT filecreate = OPEN_EXISTING; break; case _O_CREAT: filecreate = OPEN_ALWAYS; break; case _O_CREAT | _O_EXCL: case _O_CREAT | _O_TRUNC | _O_EXCL: filecreate = CREATE_NEW; break; case _O_TRUNC: case _O_TRUNC | _O_EXCL: // ignore EXCL w/o CREAT filecreate = TRUNCATE_EXISTING; break; case _O_CREAT | _O_TRUNC: filecreate = CREATE_ALWAYS; break; default: // this can't happen ... all cases are covered errno = EINVAL; _doserrno = 0L; return -1; } /* * decode file attribute flags if _O_CREAT was specified */ fileattrib = FILE_ATTRIBUTE_NORMAL; /* default */ if ( oflag & _O_CREAT ) { #ifndef _MT /* * set up variable argument list stuff */ va_start(ap, shflag); pmode = va_arg(ap, int); va_end(ap); #endif /* _MT */ 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; if (_osplatform == VER_PLATFORM_WIN32_NT ) fileshare |= FILE_SHARE_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 */ } #ifdef _MT *punlock_flag = 1; *pfh = fh; #endif /* * try to open/create the file */ if ( (osfh = CreateFile( (LPTSTR)path, fileaccess, fileshare, &SecurityAttributes, filecreate, fileattrib, NULL )) == (HANDLE)(-1) ) { /* * 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 */ 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 */ 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, (intptr_t)osfh); /* * 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, SEEK_END)) == -1) { /* OS error -- should ignore negative seek error, since that means we had a zero-length file. */ if (_doserrno != ERROR_NEGATIVE_SEEK) { _close_lk(fh); return -1; } } else { /* Seek was OK, read the last char in file. The last char is a CTRL-Z if and only if _read returns 0 and ch ends up with a CTRL-Z. */ ch = 0; if (_read_lk(fh, &ch, 1) == 0 && ch == 26) { /* read was OK and we got CTRL-Z! Wipe it out! */ if (_chsize_lk(fh,filepos) == -1) { _close_lk(fh); return -1; } } /* now rewind the file to the beginning */ if ((filepos = _lseek_lk(fh, 0, SEEK_SET)) == -1) { _close_lk(fh); return -1; } } } /* * Set FAPPEND flag if appropriate. Don't do this for devices or pipes. */ if ( !(fileflags & (FDEV|FPIPE)) && (oflag & _O_APPEND) ) _osfile(fh) |= FAPPEND; return fh; /* return handle */ }