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