Do not assume tar's default archive is stdout
[debian/tar] / src / open3.c
1 /* Defines for Sys V style 3-argument open call.
2    Copyright (C) 1988, 1994, 1995, 1996 Free Software Foundation, Inc.
3
4    This program is free software; you can redistribute it and/or modify it
5    under the terms of the GNU General Public License as published by the
6    Free Software Foundation; either version 2, or (at your option) any later
7    version.
8
9    This program is distributed in the hope that it will be useful, but
10    WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
12    Public License for more details.
13
14    You should have received a copy of the GNU General Public License along
15    with this program; if not, write to the Free Software Foundation, Inc.,
16    59 Place - Suite 330, Boston, MA 02111-1307, USA.  */
17
18 #include "system.h"
19
20 #if EMUL_OPEN3
21
22 /* open3.h -- #defines for the various flags for the Sys V style 3-argument
23    open() call.  On BSD or System 5, the system already has this in an
24    include file.  This file is needed for V7 and MINIX systems for the
25    benefit of open3() in port.c, a routine that emulates the 3-argument call
26    using system calls available on V7/MINIX.
27
28    Written 1987-06-10 by Richard Todd.
29
30    The names have been changed by John Gilmore, 1987-07-31, since Richard
31    called it "bsdopen", and really this change was introduced in AT&T Unix
32    systems before BSD picked it up.  */
33
34 /*-----------------------------------------------------------------------.
35 | open3 -- routine to emulate the 3-argument open system.                |
36 |                                                                        |
37 | open3 (path, flag, mode);                                              |
38 |                                                                        |
39 | Attempts to open the file specified by the given pathname.  The        |
40 | following flag bits specify options to the routine.  Needless to say,  |
41 | you should only specify one of the first three.  Function returns file |
42 | descriptor if successful, -1 and errno if not.                         |
43 `-----------------------------------------------------------------------*/
44
45 /* The routine obeys the following mode arguments:
46
47    O_RDONLY     file open for read only
48    O_WRONLY     file open for write only
49    O_RDWR       file open for both read & write
50
51    O_CREAT      file is created with specified mode if it needs to be
52    O_TRUNC      if file exists, it is truncated to 0 bytes
53    O_EXCL       used with O_CREAT--routine returns error if file exists  */
54
55 /* Call that if present in most modern Unix systems.  This version attempts
56    to support all the flag bits except for O_NDELAY and O_APPEND, which are
57    silently ignored.  The emulation is not as efficient as the real thing
58    (at worst, 4 system calls instead of one), but there's not much I can do
59    about that.  */
60
61 /* Array to give arguments to access for various modes FIXME, this table
62    depends on the specific integer values of O_*, and also contains
63    integers (args to 'access') that should be #define's.  */
64
65 static int modes[] =
66   {
67     04,                         /* O_RDONLY */
68     02,                         /* O_WRONLY */
69     06,                         /* O_RDWR */
70     06,                         /* invalid, just cope: O_WRONLY+O_RDWR */
71   };
72
73 /* Shut off the automatic emulation of open(), we'll need it. */
74 #undef open
75
76 int
77 open3 (char *path, int flags, int mode)
78 {
79   int exists = 1;
80   int call_creat = 0;
81
82   /* We actually do the work by calling the open() or creat() system
83      call, depending on the flags.  Call_creat is true if we will use
84      creat(), false if we will use open().  */
85
86   /* See if the file exists and is accessible in the requested mode.
87
88      Strictly speaking we shouldn't be using access, since access checks
89      against real uid, and the open call should check against euid.  Most
90      cases real uid == euid, so it won't matter.  FIXME.  FIXME, the
91      construction "flags & 3" and the modes table depends on the specific
92      integer values of the O_* #define's.  Foo!  */
93
94   if (access (path, modes[flags & 3]) < 0)
95     {
96       if (errno == ENOENT)
97         {
98           /* The file does not exist.  */
99
100           exists = 0;
101         }
102       else
103         {
104           /* Probably permission violation.  */
105
106           if (flags & O_EXCL)
107             {
108               /* Oops, the file exists, we didn't want it.  No matter
109                  what the error, claim EEXIST.  */
110
111               errno = EEXIST;   /* FIXME: errno should be read-only */
112             }
113           return -1;
114         }
115     }
116
117   /* If we have the O_CREAT bit set, check for O_EXCL.  */
118
119   if (flags & O_CREAT)
120     {
121       if ((flags & O_EXCL) && exists)
122         {
123           /* Oops, the file exists and we didn't want it to.  */
124
125           errno = EEXIST;       /* FIXME: errno should be read-only */
126           return -1;
127         }
128
129       /* If the file doesn't exist, be sure to call creat() so that it
130          will be created with the proper mode.  */
131
132       if (!exists)
133         call_creat = 1;
134     }
135   else
136     {
137       /* If O_CREAT isn't set and the file doesn't exist, error.  */
138
139       if (!exists)
140         {
141           errno = ENOENT;       /* FIXME: errno should be read-only */
142           return -1;
143         }
144     }
145
146   /* If the O_TRUNC flag is set and the file exists, we want to call
147      creat() anyway, since creat() guarantees that the file will be
148      truncated and open()-for-writing doesn't.  (If the file doesn't
149      exist, we're calling creat() anyway and the file will be created
150      with zero length.)  */
151
152   if ((flags & O_TRUNC) && exists)
153     call_creat = 1;
154
155   /* Actually do the call.  */
156
157   if (call_creat)
158
159     /* Call creat.  May have to close and reopen the file if we want
160        O_RDONLY or O_RDWR access -- creat() only gives O_WRONLY.  */
161
162     {
163       int fd = creat (path, mode);
164
165       if (fd < 0 || (flags & O_WRONLY))
166         return fd;
167       if (close (fd) < 0)
168         return -1;
169
170       /* Fall out to reopen the file we've created.  */
171     }
172
173   /* Calling old open, we strip most of the new flags just in case.  */
174
175   return open (path, flags & (O_RDONLY | O_WRONLY | O_RDWR | O_BINARY));
176 }
177
178 #endif /* EMUL_OPEN3 */