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
32extern int errno;
33#endif
34
35#include "savecwd.h"
36#include "error.h"
37
38char *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
49int
50save_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
110int
111restore_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
133void
134free_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