Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

535 lines
18 KiB

  1. /***
  2. *open.c - file open
  3. *
  4. * Copyright (c) 1989-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. * defines _open() and _sopen() - open or create a file
  8. *
  9. *Revision History:
  10. * 06-13-89 PHG Module created, based on asm version
  11. * 11-11-89 JCR Replaced DOS32QUERYFILEMODE with DOS32QUERYPATHINFO
  12. * 03-13-90 GJF Made calling type _CALLTYPE2 (for now), added #include
  13. * <cruntime.h>, fixed some compiler warnings and fixed
  14. * copyright. Also, cleaned up the formatting a bit.
  15. * 07-24-90 SBM Removed '32' from API names
  16. * 08-14-90 SBM Compiles cleanly with -W3
  17. * 09-07-90 SBM Added stdarg code (inside #if 0..#endif) to make
  18. * open and sopen match prototypes. Test and use this
  19. * someday.
  20. * 10-01-90 GJF New-style function declarators.
  21. * 11-16-90 GJF Wrote version for Win32 API and appended it via an
  22. * #ifdef. The Win32 version is similar to the old DOS
  23. * version (though in C) and far different from either
  24. * the Cruiser or OS/2 versions.
  25. * 12-03-90 GJF Fixed a dozen or so minor errors in the Win32 version.
  26. * 12-06-90 SRW Changed to use _osfile and _osfhnd instead of _osfinfo
  27. * 12-28-90 SRW Added cast of void * to char * for Mips C Compiler
  28. * 12-31-90 SRW Fixed spen to call CreateFile instead of OpenFile
  29. * 01-16-91 GJF ANSI naming.
  30. * 02-07-91 SRW Changed to call _get_osfhandle [_WIN32_]
  31. * 02-19-91 SRW Adapt to OpenFile/CreateFile changes [_WIN32_]
  32. * 02-25-91 SRW Renamed _get_free_osfhnd to be _alloc_osfhnd [_WIN32_]
  33. * 04-09-91 PNT Added _MAC_ conditional
  34. * 07-10-91 GJF Store fileflags into _osfile array before call to
  35. * _lseek_lk (bug found by LarryO) [_WIN32_].
  36. * 01-02-92 GJF Fixed Win32 version (not Cruiser!) so that pmode is not
  37. * referenced unless _O_CREAT has been specified.
  38. * 02-04-92 GJF Make better use of CreateFile options.
  39. * 04-06-92 SRW Pay attention to _O_NOINHERIT flag in oflag parameter
  40. * 05-02-92 SRW Add support for _O_TEMPORARY flag in oflag parameter.
  41. * Causes FILE_ATTRIBUTE_TEMPORARY flag to be set in call
  42. * to the Win32 CreateFile API.
  43. * 07-01-92 GJF Close handle in case of error. Also, don't try to set
  44. * FRDONLY bit anymore - no longer needed/used. [_WIN32_].
  45. * 01-03-93 SRW Fix va_arg/va_end usage
  46. * 04-06-93 SKS Replace _CRTAPI* with __cdecl
  47. * 05-24-93 PML Add support for _O_SEQUENTIAL, _O_RANDOM,
  48. * and _O_SHORT_LIVED
  49. * 07-12-93 GJF Fixed bug in reading last char in text file. Also,use
  50. * proper SEEK constants in _lseek_lk calls.
  51. * 11-01-93 CFW Enable Unicode variant, rip out CRUISER.
  52. * 02-15-95 GJF Appended Mac version of source file (somewhat cleaned
  53. * up), with appropriate #ifdef-s.
  54. * 06-06-95 CFW Enable shared writing.
  55. * 06-12-95 GJF Replaced _osfile[] with _osfile() (macro referencing
  56. * field in ioinfo struct).
  57. * 05-16-96 GJF Propagate _O_NOINHERIT to FNOINHERIT (new _osfile
  58. * bit). Also detab-ed.
  59. * 05-31-96 SKS Fix expression error in GJF's most recent check-in
  60. * 07-08-96 GJF Replaced defined(_WIN32) with !defined(_MAC), and
  61. * defined(_M_M68K) || defined(_M_MPPC) with
  62. * defined(_MAC). Also, cleaned up the format a bit.
  63. * 08-01-96 RDK For PMac, change data type for _endlowio terminator
  64. * pointer, use safer PBHOpenDFSync call, and process
  65. * _O_TEMPORARY open flag to implement delete after close.
  66. * 12-29-97 GJF Exception-safe locking.
  67. * 02-07-98 GJF Changes for Win64: arg type for _set_osfhnd is now
  68. * intptr_t.
  69. * 04-28-99 PML Wrap __declspec(allocate()) in _CRTALLOC macro.
  70. * 05-17-99 PML Remove all Macintosh support.
  71. * 10-27-99 GB VS7#14742 made a fix for opening the file in
  72. * O_TEMPORARY mode so as to enable sucessive open on the
  73. * same file if share permissions are there.
  74. *
  75. *******************************************************************************/
  76. #include <sect_attribs.h>
  77. #include <cruntime.h>
  78. #include <oscalls.h>
  79. #include <msdos.h>
  80. #include <errno.h>
  81. #include <fcntl.h>
  82. #include <internal.h>
  83. #include <io.h>
  84. #include <share.h>
  85. #include <stdio.h>
  86. #include <stdlib.h>
  87. #include <sys\types.h>
  88. #include <sys\stat.h>
  89. #include <mtdll.h>
  90. #include <stdarg.h>
  91. #include <tchar.h>
  92. #ifdef _MT
  93. static int __cdecl _tsopen_lk ( int *,
  94. int *,
  95. const _TSCHAR *,
  96. int,
  97. int,
  98. int );
  99. #endif /* _MT */
  100. /***
  101. *int _open(path, flag, pmode) - open or create a file
  102. *
  103. *Purpose:
  104. * Opens the file and prepares for subsequent reading or writing.
  105. * the flag argument specifies how to open the file:
  106. * _O_APPEND - reposition file ptr to end before every write
  107. * _O_BINARY - open in binary mode
  108. * _O_CREAT - create a new file* no effect if file already exists
  109. * _O_EXCL - return error if file exists, only use with O_CREAT
  110. * _O_RDONLY - open for reading only
  111. * _O_RDWR - open for reading and writing
  112. * _O_TEXT - open in text mode
  113. * _O_TRUNC - open and truncate to 0 length (must have write permission)
  114. * _O_WRONLY - open for writing only
  115. * _O_NOINHERIT -handle will not be inherited by child processes.
  116. * exactly one of _O_RDONLY, _O_WRONLY, _O_RDWR must be given
  117. *
  118. * The pmode argument is only required when _O_CREAT is specified. Its
  119. * flag settings:
  120. * _S_IWRITE - writing permitted
  121. * _S_IREAD - reading permitted
  122. * _S_IREAD | _S_IWRITE - both reading and writing permitted
  123. * The current file-permission maks is applied to pmode before
  124. * setting the permission (see umask).
  125. *
  126. * The oflag and mode parameter have different meanings under DOS. See
  127. * the A_xxx attributes in msdos.inc
  128. *
  129. * Note, the _creat() function also uses this function but setting up the
  130. * correct arguments and calling _open(). _creat() sets the __creat_flag
  131. * to 1 prior to calling _open() so _open() can return correctly. _open()
  132. * returns the file handle in eax in this case.
  133. *
  134. *Entry:
  135. * _TSCHAR *path - file name
  136. * int flag - flags for _open()
  137. * int pmode - permission mode for new files
  138. *
  139. *Exit:
  140. * returns file handle of open file if successful
  141. * returns -1 (and sets errno) if fails
  142. *
  143. *Exceptions:
  144. *
  145. *******************************************************************************/
  146. int __cdecl _topen (
  147. const _TSCHAR *path,
  148. int oflag,
  149. ...
  150. )
  151. {
  152. va_list ap;
  153. int pmode;
  154. #ifdef _MT
  155. int fh;
  156. int retval;
  157. int unlock_flag = 0;
  158. #endif /* MT */
  159. va_start(ap, oflag);
  160. pmode = va_arg(ap, int);
  161. va_end(ap);
  162. #ifdef _MT
  163. __try {
  164. retval = _tsopen_lk( &unlock_flag,
  165. &fh,
  166. path,
  167. oflag,
  168. _SH_DENYNO,
  169. pmode );
  170. }
  171. __finally {
  172. if ( unlock_flag )
  173. _unlock_fh(fh);
  174. }
  175. return retval;
  176. #else /* ndef _MT */
  177. /* default sharing mode is DENY NONE */
  178. return _tsopen(path, oflag, _SH_DENYNO, pmode);
  179. #endif /* _MT */
  180. }
  181. /***
  182. *int _sopen(path, oflag, shflag, pmode) - opne a file with sharing
  183. *
  184. *Purpose:
  185. * Opens the file with possible file sharing.
  186. * shflag defines the sharing flags:
  187. * _SH_COMPAT - set compatability mode
  188. * _SH_DENYRW - deny read and write access to the file
  189. * _SH_DENYWR - deny write access to the file
  190. * _SH_DENYRD - deny read access to the file
  191. * _SH_DENYNO - permit read and write access
  192. *
  193. * Other flags are the same as _open().
  194. *
  195. * SOPEN is the routine used when file sharing is desired.
  196. *
  197. *Entry:
  198. * _TSCHAR *path - file to open
  199. * int oflag - open flag
  200. * int shflag - sharing flag
  201. * int pmode - permission mode (needed only when creating file)
  202. *
  203. *Exit:
  204. * returns file handle for the opened file
  205. * returns -1 and sets errno if fails.
  206. *
  207. *Exceptions:
  208. *
  209. *******************************************************************************/
  210. int __cdecl _tsopen (
  211. const _TSCHAR *path,
  212. int oflag,
  213. int shflag,
  214. ...
  215. )
  216. {
  217. #ifdef _MT
  218. va_list ap;
  219. int pmode;
  220. int fh;
  221. int retval;
  222. int unlock_flag = 0;
  223. va_start(ap, shflag);
  224. pmode = va_arg(ap, int);
  225. va_end(ap);
  226. __try {
  227. retval = _tsopen_lk( &unlock_flag,
  228. &fh,
  229. path,
  230. oflag,
  231. shflag,
  232. pmode );
  233. }
  234. __finally {
  235. if ( unlock_flag )
  236. _unlock_fh(fh);
  237. }
  238. return retval;
  239. }
  240. static int __cdecl _tsopen_lk (
  241. int *punlock_flag,
  242. int *pfh,
  243. const _TSCHAR *path,
  244. int oflag,
  245. int shflag,
  246. int pmode
  247. )
  248. {
  249. #endif /* _MT */
  250. int fh; /* handle of opened file */
  251. int filepos; /* length of file - 1 */
  252. _TSCHAR ch; /* character at end of file */
  253. char fileflags; /* _osfile flags */
  254. #ifndef _MT
  255. va_list ap;
  256. int pmode;
  257. #endif /* _MT */
  258. HANDLE osfh; /* OS handle of opened file */
  259. DWORD fileaccess; /* OS file access (requested) */
  260. DWORD fileshare; /* OS file sharing mode */
  261. DWORD filecreate; /* OS method of opening/creating */
  262. DWORD fileattrib; /* OS file attribute flags */
  263. DWORD isdev; /* device indicator in low byte */
  264. SECURITY_ATTRIBUTES SecurityAttributes;
  265. SecurityAttributes.nLength = sizeof( SecurityAttributes );
  266. SecurityAttributes.lpSecurityDescriptor = NULL;
  267. if (oflag & _O_NOINHERIT) {
  268. SecurityAttributes.bInheritHandle = FALSE;
  269. fileflags = FNOINHERIT;
  270. }
  271. else {
  272. SecurityAttributes.bInheritHandle = TRUE;
  273. fileflags = 0;
  274. }
  275. /* figure out binary/text mode */
  276. if ((oflag & _O_BINARY) == 0)
  277. if (oflag & _O_TEXT)
  278. fileflags |= FTEXT;
  279. else if (_fmode != _O_BINARY) /* check default mode */
  280. fileflags |= FTEXT;
  281. /*
  282. * decode the access flags
  283. */
  284. switch( oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR) ) {
  285. case _O_RDONLY: /* read access */
  286. fileaccess = GENERIC_READ;
  287. break;
  288. case _O_WRONLY: /* write access */
  289. fileaccess = GENERIC_WRITE;
  290. break;
  291. case _O_RDWR: /* read and write access */
  292. fileaccess = GENERIC_READ | GENERIC_WRITE;
  293. break;
  294. default: /* error, bad oflag */
  295. errno = EINVAL;
  296. _doserrno = 0L; /* not an OS error */
  297. return -1;
  298. }
  299. /*
  300. * decode sharing flags
  301. */
  302. switch ( shflag ) {
  303. case _SH_DENYRW: /* exclusive access */
  304. fileshare = 0L;
  305. break;
  306. case _SH_DENYWR: /* share read access */
  307. fileshare = FILE_SHARE_READ;
  308. break;
  309. case _SH_DENYRD: /* share write access */
  310. fileshare = FILE_SHARE_WRITE;
  311. break;
  312. case _SH_DENYNO: /* share read and write access */
  313. fileshare = FILE_SHARE_READ | FILE_SHARE_WRITE;
  314. break;
  315. default: /* error, bad shflag */
  316. errno = EINVAL;
  317. _doserrno = 0L; /* not an OS error */
  318. return -1;
  319. }
  320. /*
  321. * decode open/create method flags
  322. */
  323. switch ( oflag & (_O_CREAT | _O_EXCL | _O_TRUNC) ) {
  324. case 0:
  325. case _O_EXCL: // ignore EXCL w/o CREAT
  326. filecreate = OPEN_EXISTING;
  327. break;
  328. case _O_CREAT:
  329. filecreate = OPEN_ALWAYS;
  330. break;
  331. case _O_CREAT | _O_EXCL:
  332. case _O_CREAT | _O_TRUNC | _O_EXCL:
  333. filecreate = CREATE_NEW;
  334. break;
  335. case _O_TRUNC:
  336. case _O_TRUNC | _O_EXCL: // ignore EXCL w/o CREAT
  337. filecreate = TRUNCATE_EXISTING;
  338. break;
  339. case _O_CREAT | _O_TRUNC:
  340. filecreate = CREATE_ALWAYS;
  341. break;
  342. default:
  343. // this can't happen ... all cases are covered
  344. errno = EINVAL;
  345. _doserrno = 0L;
  346. return -1;
  347. }
  348. /*
  349. * decode file attribute flags if _O_CREAT was specified
  350. */
  351. fileattrib = FILE_ATTRIBUTE_NORMAL; /* default */
  352. if ( oflag & _O_CREAT ) {
  353. #ifndef _MT
  354. /*
  355. * set up variable argument list stuff
  356. */
  357. va_start(ap, shflag);
  358. pmode = va_arg(ap, int);
  359. va_end(ap);
  360. #endif /* _MT */
  361. if ( !((pmode & ~_umaskval) & _S_IWRITE) )
  362. fileattrib = FILE_ATTRIBUTE_READONLY;
  363. }
  364. /*
  365. * Set temporary file (delete-on-close) attribute if requested.
  366. */
  367. if ( oflag & _O_TEMPORARY ) {
  368. fileattrib |= FILE_FLAG_DELETE_ON_CLOSE;
  369. fileaccess |= DELETE;
  370. if (_osplatform == VER_PLATFORM_WIN32_NT )
  371. fileshare |= FILE_SHARE_DELETE;
  372. }
  373. /*
  374. * Set temporary file (delay-flush-to-disk) attribute if requested.
  375. */
  376. if ( oflag & _O_SHORT_LIVED )
  377. fileattrib |= FILE_ATTRIBUTE_TEMPORARY;
  378. /*
  379. * Set sequential or random access attribute if requested.
  380. */
  381. if ( oflag & _O_SEQUENTIAL )
  382. fileattrib |= FILE_FLAG_SEQUENTIAL_SCAN;
  383. else if ( oflag & _O_RANDOM )
  384. fileattrib |= FILE_FLAG_RANDOM_ACCESS;
  385. /*
  386. * get an available handle.
  387. *
  388. * multi-thread note: the returned handle is locked!
  389. */
  390. if ( (fh = _alloc_osfhnd()) == -1 ) {
  391. errno = EMFILE; /* too many open files */
  392. _doserrno = 0L; /* not an OS error */
  393. return -1; /* return error to caller */
  394. }
  395. #ifdef _MT
  396. *punlock_flag = 1;
  397. *pfh = fh;
  398. #endif
  399. /*
  400. * try to open/create the file
  401. */
  402. if ( (osfh = CreateFile( (LPTSTR)path,
  403. fileaccess,
  404. fileshare,
  405. &SecurityAttributes,
  406. filecreate,
  407. fileattrib,
  408. NULL ))
  409. == (HANDLE)(-1) )
  410. {
  411. /*
  412. * OS call to open/create file failed! map the error, release
  413. * the lock, and return -1. note that it's not necessary to
  414. * call _free_osfhnd (it hasn't been used yet).
  415. */
  416. _dosmaperr(GetLastError()); /* map error */
  417. return -1; /* return error to caller */
  418. }
  419. /* find out what type of file (file/device/pipe) */
  420. if ( (isdev = GetFileType(osfh)) == FILE_TYPE_UNKNOWN ) {
  421. CloseHandle(osfh);
  422. _dosmaperr(GetLastError()); /* map error */
  423. return -1;
  424. }
  425. /* is isdev value to set flags */
  426. if (isdev == FILE_TYPE_CHAR)
  427. fileflags |= FDEV;
  428. else if (isdev == FILE_TYPE_PIPE)
  429. fileflags |= FPIPE;
  430. /*
  431. * the file is open. now, set the info in _osfhnd array
  432. */
  433. _set_osfhnd(fh, (intptr_t)osfh);
  434. /*
  435. * mark the handle as open. store flags gathered so far in _osfile
  436. * array.
  437. */
  438. fileflags |= FOPEN;
  439. _osfile(fh) = fileflags;
  440. if ( !(fileflags & (FDEV|FPIPE)) && (fileflags & FTEXT) &&
  441. (oflag & _O_RDWR) )
  442. {
  443. /* We have a text mode file. If it ends in CTRL-Z, we wish to
  444. remove the CTRL-Z character, so that appending will work.
  445. We do this by seeking to the end of file, reading the last
  446. byte, and shortening the file if it is a CTRL-Z. */
  447. if ((filepos = _lseek_lk(fh, -1, SEEK_END)) == -1) {
  448. /* OS error -- should ignore negative seek error,
  449. since that means we had a zero-length file. */
  450. if (_doserrno != ERROR_NEGATIVE_SEEK) {
  451. _close_lk(fh);
  452. return -1;
  453. }
  454. }
  455. else {
  456. /* Seek was OK, read the last char in file. The last
  457. char is a CTRL-Z if and only if _read returns 0
  458. and ch ends up with a CTRL-Z. */
  459. ch = 0;
  460. if (_read_lk(fh, &ch, 1) == 0 && ch == 26) {
  461. /* read was OK and we got CTRL-Z! Wipe it
  462. out! */
  463. if (_chsize_lk(fh,filepos) == -1)
  464. {
  465. _close_lk(fh);
  466. return -1;
  467. }
  468. }
  469. /* now rewind the file to the beginning */
  470. if ((filepos = _lseek_lk(fh, 0, SEEK_SET)) == -1) {
  471. _close_lk(fh);
  472. return -1;
  473. }
  474. }
  475. }
  476. /*
  477. * Set FAPPEND flag if appropriate. Don't do this for devices or pipes.
  478. */
  479. if ( !(fileflags & (FDEV|FPIPE)) && (oflag & _O_APPEND) )
  480. _osfile(fh) |= FAPPEND;
  481. return fh; /* return handle */
  482. }