savecwd.c revision 1.1.1.1
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
31extern int errno;
32#endif
33
34#include "savecwd.h"
35#include "error.h"
36
37char *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
48int
49save_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
109int
110restore_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
132void
133free_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