/*** *open.c - file open * * Copyright (c) 1989-1997, Microsoft Corporation. All rights reserved. * *Purpose: * defines _open() and _sopen() - open or create a file * *******************************************************************************/ #ifndef _MAC #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /*** *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; va_start(ap, oflag); pmode = va_arg(ap, int); va_end(ap); /* default sharing mode is DENY NONE */ return _tsopen(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: * _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, ... ) { int fh; /* handle of opened file */ int filepos; /* length of file - 1 */ _TSCHAR ch; /* character at end of file */ char fileflags; /* _osfile flags */ va_list ap; /* variable argument (pmode) */ int pmode; 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 ) { /* * 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( (LPTSTR)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); /* * 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(fh); _unlock_fh(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(fh); _unlock_fh(fh); return -1; } } /* now rewind the file to the beginning */ if ((filepos = _lseek_lk(fh, 0, SEEK_SET)) == -1) { _close(fh); _unlock_fh(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; _unlock_fh(fh); /* unlock handle */ return fh; /* return handle */ } #else /* _MAC */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* define the entry in terminator table */ #pragma data_seg(".CRT$XTX") _PVFV pendlowio = _endlowio; #pragma data_seg() /* Mac definitions for ioDenyModes */ #define MAC_PERMRD 0x0001 #define MAC_PERMWR 0x0002 #define MAC_DENYRD 0x0010 #define MAC_DENYWR 0x0020 /*** *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 * 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 masks is applied to pmode before * setting the permission (see umask). * * Note, the _creat() function also uses this function but setting up the * correct arguments and calling _open(). * *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 __cdecl _open ( const char *path, int oflag, ... ) { va_list ap; va_start(ap, oflag); /* default sharing mode is DENY NONE */ return _sopen(path, oflag, _SH_DENYNO, va_arg(ap, int)); } /*** *void __mopen(stpath, fh, ioPermssn, ioDenyModes) - MAC open a file with sharing * *Purpose: * Worker routine to open a file on the MAC. It only opens the file. * If local open fails it will try AppleShare oepn. * *Entry: * char *stpath - file to open (Pascal string) * int fh - file handle to use * int ioPermssn - persmission modes flags * int ioDenyModes - Deny mode flags * *Exit: * returns TRUE if successful and sets errno & _osfhnd[fh] & * _osfile[fh] if successful * *Exceptions: * *******************************************************************************/ int __cdecl __mopen ( char *stpath, int fh, int ioPermssn, int ioDenyModes ) { HParamBlockRec parm; OSErr osErr; char sz[256]; char buf[10]; char *pch; //if starts with full path, test the availability of the volume memcpy(sz, stpath, (*stpath+1)); _p2cstr(sz); if (*sz != ':' && (pch = strchr(sz, ':')) != NULL) { *(pch+1) = '\0'; _c2pstr(sz); memset(&parm, 0, sizeof(HParamBlockRec)); memset(buf, 0, 10); parm.ioParam.ioNamePtr = sz; parm.ioParam.ioBuffer = buf; parm.ioParam.ioReqCount = 6; osErr = PBHGetVolParmsSync(&parm); if (!osErr) { if (!(buf[4]&0x8000)) { parm.ioParam.ioNamePtr = stpath; parm.ioParam.ioVRefNum = 0; goto local; } } else { _dosmaperr(osErr); return osErr; } } /* try to open the file using Appleshare calls*/ parm.ioParam.ioNamePtr = stpath; parm.ioParam.ioVRefNum = 0; parm.accessParam.ioDenyModes = (unsigned char)ioDenyModes; _osperm[fh] = (unsigned char)ioDenyModes; parm.fileParam.ioDirID = 0; parm.ioParam.ioMisc = NULL; osErr = PBHOpenDenySync(&parm); if (osErr == paramErr) { local: /* Try local open */ parm.ioParam.ioPermssn = ioPermssn; _osperm[fh] = (unsigned char)ioPermssn; osErr = PBHOpenDFSync(&parm); } if (!osErr) { _osfile[fh] |= FOPEN; _osfhnd[fh] = parm.ioParam.ioRefNum; } else { _dosmaperr(osErr); } return osErr; } /*** *int _sopen(path, oflag, shflag, pmode) - open a file with sharing * *Purpose: * Opens the file with possible file sharing. * shflag defines the sharing flags: * _SH_DENYRW - deny read and write 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 (C string) * 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 _sopen ( const char *path, int oflag, int shflag, ... ) { int fh; /* handle of opened file */ OSErr osErr = 0; unsigned char ioPermssn; short int ioDenyModes; ParamBlockRec parm; int pmode; va_list ap; /* variable argument (pmode) */ char lpath[256]; if (!*path) { errno = ENOENT; return -1; } strcpy(lpath,path); _c2pstr(lpath); /* get a file handle*/ for (fh = 0; fh <_nfile; fh++) { if (!(_osfile[fh] & FOPEN)) { break; } } if (fh >= _nfile) { errno = EMFILE; _macerrno = 0; return -1; } _osfile[fh] = 0; _osfileflags[fh] = 0; /* figure out binary/text mode */ switch (oflag & (_O_BINARY | _O_TEXT)) { case _O_BINARY: break; case _O_TEXT: _osfile[fh] = (unsigned char)FTEXT; break; case _O_TEXT | _O_BINARY: errno = EINVAL; return -1; default: if (_fmode != _O_BINARY) { _osfile[fh] = (unsigned char)FTEXT; } break; } /* figure out read/write modes */ switch (oflag & (_O_RDWR | _O_RDONLY | _O_WRONLY)) { case _O_RDONLY: ioPermssn = fsRdPerm; _osfile[fh] |= FRDONLY; if (oflag & _O_TRUNC) { errno = EINVAL; return -1; } ioDenyModes = MAC_PERMRD; break; case _O_WRONLY: ioPermssn = fsRdWrShPerm; _osfile[fh] |= FWRONLY; ioDenyModes = MAC_PERMWR; break; case _O_RDWR: ioPermssn = fsRdWrPerm; ioDenyModes = MAC_PERMRD | MAC_PERMWR; break; default: errno = EINVAL; return -1; } switch (shflag) { case _SH_DENYRD: ioDenyModes |= MAC_DENYRD; break; case _SH_DENYWR: ioDenyModes |= MAC_DENYWR; break; case _SH_DENYRW: ioDenyModes |= MAC_DENYRD | MAC_DENYWR; break; case _SH_DENYNO: if (ioPermssn == fsRdWrPerm) { ioPermssn = fsRdWrShPerm; } break; default: errno = EINVAL; return -1; } if (!(oflag & _O_CREAT && oflag & _O_EXCL)) { /* try to open the file */ if (!__mopen(lpath, fh, ioPermssn, ioDenyModes)) { oflag &= ~_O_CREAT; /*file open - no need to create*/ } } /* Didn't work try creating the file if requested */ if (oflag & _O_CREAT) { /* reset errno from mopen, since we can try create*/ errno = 0; va_start(ap, shflag); pmode = va_arg(ap, int); pmode &= ~_umaskval; if (!(pmode & (_S_IREAD | _S_IWRITE))) { errno = EINVAL; return -1; } parm.fileParam.ioNamePtr = lpath; parm.fileParam.ioVRefNum = 0; osErr = PBCreateSync(&parm); if (!osErr) { parm.fileParam.ioFDirIndex = 0; PBGetFInfoSync(&parm); parm.fileParam.ioFlFndrInfo.fdType = (_osfile[fh] & FTEXT ? 'TEXT' : ' '); parm.fileParam.ioFlFndrInfo.fdCreator = ' '; PBSetFInfoSync(&parm); } else { if (osErr == dupFNErr && oflag & _O_EXCL) { errno = EEXIST; /*special case normally returns EACCES*/ _macerrno = osErr; } else { _dosmaperr(osErr); } return -1; } if (osErr = __mopen(lpath, fh, ioPermssn, ioDenyModes)) { _dosmaperr(osErr); return -1; } else if (!(pmode & _S_IWRITE)) { PBSetFLockSync(&parm); } } if (!(_osfile[fh] & FOPEN)) { goto ErrExit; } parm.ioParam.ioRefNum = _osfhnd[fh]; /* Truncate file */ if (oflag & _O_TRUNC) { parm.ioParam.ioMisc = 0; osErr = PBSetEOFSync(&parm); if (osErr) { _dosmaperr(osErr); goto ErrExit; } } /* get vol reference */ parm.volumeParam.ioVolIndex = -1; parm.ioParam.ioNamePtr = lpath; parm.ioParam.ioVRefNum = 0; osErr = PBGetVInfoSync(&parm); if (osErr) { _dosmaperr(osErr); goto ErrExit; } _osVRefNum[fh] = parm.volumeParam.ioVRefNum; if (oflag & _O_APPEND) { _osfile[fh] |= FAPPEND; } if (oflag & _O_TEMPORARY) { _osfileflags[fh] |= FTEMP; } return fh; /* return handle */ ErrExit: if (_osfile[fh] & FOPEN) { PBCloseSync(&parm); _osfile[fh] = 0; } return -1; } #endif /* _MAC */