xref: /openbsd/gnu/usr.bin/cvs/lib/savecwd.c (revision 7b36286a)
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 __PROTO((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 
143