172f24e79af68d59749901c154372ce4548806b6
[debian/tar] / gnu / dup2.c
1 /* -*- buffer-read-only: t -*- vi: set ro: */
2 /* DO NOT EDIT! GENERATED AUTOMATICALLY! */
3 /* Duplicate an open file descriptor to a specified file descriptor.
4
5    Copyright (C) 1999, 2004-2007, 2009-2013 Free Software Foundation, Inc.
6
7    This program is free software: you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
19
20 /* written by Paul Eggert */
21
22 #include <config.h>
23
24 /* Specification.  */
25 #include <unistd.h>
26
27 #include <errno.h>
28 #include <fcntl.h>
29
30 #if HAVE_DUP2
31
32 # undef dup2
33
34 # if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
35
36 /* Get declarations of the native Windows API functions.  */
37 #  define WIN32_LEAN_AND_MEAN
38 #  include <windows.h>
39
40 #  include "msvc-inval.h"
41
42 /* Get _get_osfhandle.  */
43 #  include "msvc-nothrow.h"
44
45 static int
46 ms_windows_dup2 (int fd, int desired_fd)
47 {
48   int result;
49
50   /* If fd is closed, mingw hangs on dup2 (fd, fd).  If fd is open,
51      dup2 (fd, fd) returns 0, but all further attempts to use fd in
52      future dup2 calls will hang.  */
53   if (fd == desired_fd)
54     {
55       if ((HANDLE) _get_osfhandle (fd) == INVALID_HANDLE_VALUE)
56         {
57           errno = EBADF;
58           return -1;
59         }
60       return fd;
61     }
62
63   /* Wine 1.0.1 return 0 when desired_fd is negative but not -1:
64      http://bugs.winehq.org/show_bug.cgi?id=21289 */
65   if (desired_fd < 0)
66     {
67       errno = EBADF;
68       return -1;
69     }
70
71   TRY_MSVC_INVAL
72     {
73       result = dup2 (fd, desired_fd);
74     }
75   CATCH_MSVC_INVAL
76     {
77       errno = EBADF;
78       result = -1;
79     }
80   DONE_MSVC_INVAL;
81
82   if (result == 0)
83     result = desired_fd;
84
85   return result;
86 }
87
88 #  define dup2 ms_windows_dup2
89
90 # endif
91
92 int
93 rpl_dup2 (int fd, int desired_fd)
94 {
95   int result;
96
97 # ifdef F_GETFL
98   /* On Linux kernels 2.6.26-2.6.29, dup2 (fd, fd) returns -EBADF.
99      On Cygwin 1.5.x, dup2 (1, 1) returns 0.
100      On Cygwin 1.7.17, dup2 (1, -1) dumps core.
101      On Haiku, dup2 (fd, fd) mistakenly clears FD_CLOEXEC.  */
102   if (desired_fd < 0)
103     fd = desired_fd;
104   if (fd == desired_fd)
105     return fcntl (fd, F_GETFL) == -1 ? -1 : fd;
106 # endif
107
108   result = dup2 (fd, desired_fd);
109
110   /* Correct an errno value on FreeBSD 6.1 and Cygwin 1.5.x.  */
111   if (result == -1 && errno == EMFILE)
112     errno = EBADF;
113 # if REPLACE_FCHDIR
114   if (fd != desired_fd && result != -1)
115     result = _gl_register_dup (fd, result);
116 # endif
117   return result;
118 }
119
120 #else /* !HAVE_DUP2 */
121
122 /* On older platforms, dup2 did not exist.  */
123
124 # ifndef F_DUPFD
125 static int
126 dupfd (int fd, int desired_fd)
127 {
128   int duplicated_fd = dup (fd);
129   if (duplicated_fd < 0 || duplicated_fd == desired_fd)
130     return duplicated_fd;
131   else
132     {
133       int r = dupfd (fd, desired_fd);
134       int e = errno;
135       close (duplicated_fd);
136       errno = e;
137       return r;
138     }
139 }
140 # endif
141
142 int
143 dup2 (int fd, int desired_fd)
144 {
145   int result = fcntl (fd, F_GETFL) < 0 ? -1 : fd;
146   if (result == -1 || fd == desired_fd)
147     return result;
148   close (desired_fd);
149 # ifdef F_DUPFD
150   result = fcntl (fd, F_DUPFD, desired_fd);
151 #  if REPLACE_FCHDIR
152   if (0 <= result)
153     result = _gl_register_dup (fd, result);
154 #  endif
155 # else
156   result = dupfd (fd, desired_fd);
157 # endif
158   if (result == -1 && (errno == EMFILE || errno == EINVAL))
159     errno = EBADF;
160   return result;
161 }
162 #endif /* !HAVE_DUP2 */