Merge from vendor branch OPENSSL:
[dragonfly.git] / contrib / cvs-1.12.9 / lib / savecwd.c
1 #ifdef HAVE_CONFIG_H
2 # include "config.h"
3 #endif
4
5 #include <stdio.h>
6
7 #ifdef STDC_HEADERS
8 # include <stdlib.h>
9 #endif
10
11 #ifdef HAVE_UNISTD_H
12 # include <unistd.h>
13 #endif
14
15 #ifdef HAVE_FCNTL_H
16 # include <sys/types.h>
17 # include <fcntl.h>
18 #else
19 # include <sys/file.h>
20 #endif
21
22 #ifdef HAVE_DIRECT_H
23 # include <direct.h>
24 #endif
25
26 #ifdef HAVE_IO_H
27 # include <io.h>
28 #endif
29
30 #include <errno.h>
31 # ifndef errno
32 extern int errno;
33 #endif
34
35 #include "savecwd.h"
36 #include "error.h"
37
38 char *xgetwd( void );
39
40 /* Record the location of the current working directory in CWD so that
41    the program may change to other directories and later use restore_cwd
42    to return to the recorded location.  This function may allocate
43    space using malloc (via xgetwd) or leave a file descriptor open;
44    use free_cwd to perform the necessary free or close.  Upon failure,
45    no memory is allocated, any locally opened file descriptors are
46    closed;  return non-zero -- in that case, free_cwd need not be
47    called, but doing so is ok.  Otherwise, return zero.  */
48
49 int
50 save_cwd (cwd)
51      struct saved_cwd *cwd;
52 {
53   static int have_working_fchdir = 1;
54
55   cwd->desc = -1;
56   cwd->name = NULL;
57
58   if (have_working_fchdir)
59     {
60 #ifdef HAVE_FCHDIR
61       cwd->desc = open (".", O_RDONLY);
62       if (cwd->desc < 0)
63         {
64           error (0, errno, "cannot open current directory");
65           return 1;
66         }
67
68 # if __sun__ || sun
69       /* On SunOS 4, fchdir returns EINVAL if accounting is enabled,
70          so we have to fall back to chdir.  */
71       if (fchdir (cwd->desc))
72         {
73           if (errno == EINVAL)
74             {
75               close (cwd->desc);
76               cwd->desc = -1;
77               have_working_fchdir = 0;
78             }
79           else
80             {
81               error (0, errno, "current directory");
82               close (cwd->desc);
83               cwd->desc = -1;
84               return 1;
85             }
86         }
87 # endif /* __sun__ || sun */
88 #else
89 #define fchdir(x) (abort (), 0)
90       have_working_fchdir = 0;
91 #endif
92     }
93
94   if (!have_working_fchdir)
95     {
96       cwd->name = xgetwd ();
97       if (cwd->name == NULL)
98         {
99           error (0, errno, "cannot get current directory");
100           return 1;
101         }
102     }
103   return 0;
104 }
105
106 /* Change to recorded location, CWD, in directory hierarchy.
107    If "saved working directory", NULL))
108    */
109
110 int
111 restore_cwd (cwd, dest)
112      const struct saved_cwd *cwd;
113      const char *dest;
114 {
115   int fail = 0;
116   if (cwd->desc >= 0)
117     {
118       if (fchdir (cwd->desc))
119         {
120           error (0, errno, "cannot return to %s",
121                  (dest ? dest : "saved working directory"));
122           fail = 1;
123         }
124     }
125   else if (chdir (cwd->name) < 0)
126     {
127       error (0, errno, "%s", cwd->name);
128       fail = 1;
129     }
130   return fail;
131 }
132
133 void
134 free_cwd (cwd)
135      struct saved_cwd *cwd;
136 {
137   if (cwd->desc >= 0)
138     close (cwd->desc);
139   if (cwd->name)
140     free (cwd->name);
141 }
142