summaryrefslogtreecommitdiffstats
path: root/private/crt32/lowio/dup2.c
blob: dfa6724ec17ad0aa9b5dd3af2e0a9de43195f61f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
/***
*dup2.c - Duplicate file handles
*
*	Copyright (c) 1989-1992, Microsoft Corporation. All rights reserved.
*
*Purpose:
*	defines _dup2() - duplicate file handles
*
*Revision History:
*	06-09-89  PHG	Module created, based on asm version
*	03-12-90  GJF	Made calling type _CALLTYPE2 (for now), added #include
*			<cruntime.h> and fixed the copyright. Also, cleaned up
*			the formatting a bit.
*	04-03-90  GJF	Now _CALLTYPE1.
*	07-24-90  SBM	Removed '32' from API names
*	08-14-90  SBM	Compiles cleanly with -W3
*	09-28-90  GJF	New-style function declarator.
*	12-04-90  GJF	Appended Win32 version onto the source with #ifdef-s.
*			It is enough different that there is little point in
*			trying to more closely merge the two versions.
*	12-04-90  SRW	Changed to include <oscalls.h> instead of <doscalls.h>
*	12-06-90  SRW	Changed to use _osfile and _osfhnd instead of _osfinfo
*	01-16-91  GJF	ANSI naming.
*       02-07-91  SRW   Changed to call _get_osfhandle [_WIN32_]
*       02-18-91  SRW   Changed to call _free_osfhnd [_WIN32_]
*	02-25-91  SRW	Renamed _get_free_osfhnd to be _alloc_osfhnd [_WIN32_]
*	02-13-92  GJF	Replaced _nfile by _nhandle for Win32.
*	09-04-92  GJF	Check for unopened fh1 and gracefully handle fh1 ==
*			fh2.
*
*******************************************************************************/

#include <cruntime.h>
#include <io.h>
#include <oscalls.h>
#include <msdos.h>
#include <os2dll.h>
#include <errno.h>
#include <stdlib.h>
#include <internal.h>

/***
*int _dup2(fh1, fh2) - force handle 2 to refer to handle 1
*
*Purpose:
*	Forces file handle 2 to refer to the same file as file
*	handle 1.  If file handle 2 referred to an open file, that file
*	is closed.
*
*	Multi-thread: We must hold 2 lowio locks at the same time
*	to ensure multi-thread integrity.  In order to prevent deadlock,
*	we always get the lower file handle lock first.  Order of unlocking
*	does not matter.  If you modify this routine, make sure you don't
*	cause any deadlocks! Scary stuff, kids!!
*
*Entry:
*	int fh1 - file handle to duplicate
*	int fh2 - file handle to assign to file handle 1
*
*Exit:
*	returns 0 if successful, -1 (and sets errno) if fails.
*
*Exceptions:
*
*******************************************************************************/

int _CALLTYPE1 _dup2 (
	int fh1,
	int fh2
	)
{
	ULONG dosretval;		/* OS/2 return code */

	/* validate file handles */
#ifdef	_WIN32_
	if ( ((unsigned)fh1 >= (unsigned)_nhandle) ||
	     ((unsigned)fh2 >= (unsigned)_nhandle) ) {
#else
	if ((unsigned)fh1 >= (unsigned)_nfile ||
	    (unsigned)fh2 >= (unsigned)_nfile ) {
#endif
		/* handle out of range */
		errno = EBADF;
		_doserrno = 0;	/* not an OS error */
		return -1;
	}

#ifdef MTHREAD
	/* get the two file handle locks; in order to prevent deadlock,
	   get the lowest handle lock first. */
	if ( fh1 < fh2 ) {
		_lock_fh(fh1);
		_lock_fh(fh2);
	}
	else if ( fh1 > fh2 ) {
		_lock_fh(fh2);
		_lock_fh(fh1);
	}
#endif

	/*
	 * Take care of case of equal handles.
	 */
	if ( fh1 == fh2 ) {
		/*
		 * Two handles are the same. Return success or failure
		 * depending on whether or not the handle is open. This is
		 * conformance with the POSIX specification for dup2().
		 */
		if ( _osfile[fh1] & FOPEN )
			return 0;
		else
			return -1;
	}

	/*
	 * Take care of case of unopened source handle.
	 */
	if ( !(_osfile[fh1] & FOPEN) ) {
		/*
		 * Source handle isn't open, release locks and bail out with
		 * an error. Note that the DuplicateHandle API will not detect
		 * this error since it implies that _osfhnd[fh1] ==
		 * INVALID_HANDLE_VALUE, and this is a legal HANDLE value (it's
		 * the HANDLE for the current process).
		 */
		_unlock_fh(fh1);
	        _unlock_fh(fh2);
		errno = EBADF;
		_doserrno = 0;	/* not an OS error */
		return -1;
	}


	/*
	 * if fh2 is open, close it.
	 */
	if ( _osfile[fh2] & FOPEN )
		/*
		 * close the handle. ignore the possibility of an error - an
		 * error simply means that an OS handle value may remain bound
		 * for the duration of the process.  Use _close_lk as we
                 * already own lock
		 */
		(void) _close_lk(fh2);


	/* Duplicate source file onto target file */
#ifdef	_CRUISER_

	dosretval = DOSDUPHANDLE(fh1, &fh2);

#else	/* ndef _CRUISER_ */

#ifdef	_WIN32_

        {
        long new_osfhandle;

	if ( !(DuplicateHandle(GetCurrentProcess(),
			       (HANDLE)_get_osfhandle(fh1),
			       GetCurrentProcess(),
			       (PHANDLE)&new_osfhandle,
			       0L,
			       TRUE,
			       DUPLICATE_SAME_ACCESS)
	    ) ) {

                dosretval = GetLastError();
        } else {
                _set_osfhnd(fh2, new_osfhandle);
                dosretval = 0;
        }
        }


#else	/* ndef _WIN32_ */

#error ERROR - ONLY CRUISER OR WIN32 TARGET SUPPORTED!

#endif	/* _WIN32_ */

#endif	/* _CRUISER_ */

        if (dosretval) {
	        _dosmaperr(dosretval);
	        _unlock_fh(fh1);
	        _unlock_fh(fh2);
	        return -1;
        }

	/* copy _osfile information */
	_osfile[fh2] = _osfile[fh1];

	/* unlock file handles */
	_unlock_fh(fh1);
	_unlock_fh(fh2);

	return 0;
}