1*86d7f5d3SJohn Marino /* save-cwd.c -- Save and restore current working directory.
2*86d7f5d3SJohn Marino
3*86d7f5d3SJohn Marino Copyright (C) 1995, 1997, 1998, 2003, 2004, 2005 Free Software
4*86d7f5d3SJohn Marino Foundation, Inc.
5*86d7f5d3SJohn Marino
6*86d7f5d3SJohn Marino This program is free software; you can redistribute it and/or modify
7*86d7f5d3SJohn Marino it under the terms of the GNU General Public License as published by
8*86d7f5d3SJohn Marino the Free Software Foundation; either version 2, or (at your option)
9*86d7f5d3SJohn Marino any later version.
10*86d7f5d3SJohn Marino
11*86d7f5d3SJohn Marino This program is distributed in the hope that it will be useful,
12*86d7f5d3SJohn Marino but WITHOUT ANY WARRANTY; without even the implied warranty of
13*86d7f5d3SJohn Marino MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14*86d7f5d3SJohn Marino GNU General Public License for more details.
15*86d7f5d3SJohn Marino
16*86d7f5d3SJohn Marino You should have received a copy of the GNU General Public License
17*86d7f5d3SJohn Marino along with this program; if not, write to the Free Software Foundation,
18*86d7f5d3SJohn Marino Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
19*86d7f5d3SJohn Marino
20*86d7f5d3SJohn Marino /* Written by Jim Meyering. */
21*86d7f5d3SJohn Marino
22*86d7f5d3SJohn Marino #ifdef HAVE_CONFIG_H
23*86d7f5d3SJohn Marino # include <config.h>
24*86d7f5d3SJohn Marino #endif
25*86d7f5d3SJohn Marino
26*86d7f5d3SJohn Marino #include "save-cwd.h"
27*86d7f5d3SJohn Marino
28*86d7f5d3SJohn Marino #include <stdbool.h>
29*86d7f5d3SJohn Marino #include <stdio.h>
30*86d7f5d3SJohn Marino #include <stdlib.h>
31*86d7f5d3SJohn Marino
32*86d7f5d3SJohn Marino #if HAVE_UNISTD_H
33*86d7f5d3SJohn Marino # include <unistd.h>
34*86d7f5d3SJohn Marino #endif
35*86d7f5d3SJohn Marino
36*86d7f5d3SJohn Marino #include <fcntl.h>
37*86d7f5d3SJohn Marino
38*86d7f5d3SJohn Marino #include <errno.h>
39*86d7f5d3SJohn Marino
40*86d7f5d3SJohn Marino #include "unistd-safer.h"
41*86d7f5d3SJohn Marino #include "xgetcwd.h"
42*86d7f5d3SJohn Marino
43*86d7f5d3SJohn Marino /* On systems without the fchdir function (WOE), pretend that open
44*86d7f5d3SJohn Marino always returns -1 so that save_cwd resorts to using xgetcwd.
45*86d7f5d3SJohn Marino Since chdir_long requires fchdir, use chdir instead. */
46*86d7f5d3SJohn Marino #if !HAVE_FCHDIR
47*86d7f5d3SJohn Marino # undef open
48*86d7f5d3SJohn Marino # define open(File, Flags) (-1)
49*86d7f5d3SJohn Marino # undef fchdir
50*86d7f5d3SJohn Marino # define fchdir(Fd) (abort (), -1)
51*86d7f5d3SJohn Marino # undef chdir_long
52*86d7f5d3SJohn Marino # define chdir_long(Dir) chdir (Dir)
53*86d7f5d3SJohn Marino #endif
54*86d7f5d3SJohn Marino
55*86d7f5d3SJohn Marino /* Record the location of the current working directory in CWD so that
56*86d7f5d3SJohn Marino the program may change to other directories and later use restore_cwd
57*86d7f5d3SJohn Marino to return to the recorded location. This function may allocate
58*86d7f5d3SJohn Marino space using malloc (via xgetcwd) or leave a file descriptor open;
59*86d7f5d3SJohn Marino use free_cwd to perform the necessary free or close. Upon failure,
60*86d7f5d3SJohn Marino no memory is allocated, any locally opened file descriptors are
61*86d7f5d3SJohn Marino closed; return non-zero -- in that case, free_cwd need not be
62*86d7f5d3SJohn Marino called, but doing so is ok. Otherwise, return zero.
63*86d7f5d3SJohn Marino
64*86d7f5d3SJohn Marino The `raison d'etre' for this interface is that the working directory
65*86d7f5d3SJohn Marino is sometimes inaccessible, and getcwd is not robust or as efficient.
66*86d7f5d3SJohn Marino So, we prefer to use the open/fchdir approach, but fall back on
67*86d7f5d3SJohn Marino getcwd if necessary.
68*86d7f5d3SJohn Marino
69*86d7f5d3SJohn Marino Some systems lack fchdir altogether: e.g., OS/2, pre-2001 Cygwin,
70*86d7f5d3SJohn Marino SCO Xenix. Also, SunOS 4 and Irix 5.3 provide the function, yet it
71*86d7f5d3SJohn Marino doesn't work for partitions on which auditing is enabled. If
72*86d7f5d3SJohn Marino you're still using an obsolete system with these problems, please
73*86d7f5d3SJohn Marino send email to the maintainer of this code. */
74*86d7f5d3SJohn Marino
75*86d7f5d3SJohn Marino int
save_cwd(struct saved_cwd * cwd)76*86d7f5d3SJohn Marino save_cwd (struct saved_cwd *cwd)
77*86d7f5d3SJohn Marino {
78*86d7f5d3SJohn Marino cwd->name = NULL;
79*86d7f5d3SJohn Marino
80*86d7f5d3SJohn Marino cwd->desc = fd_safer (open (".", O_RDONLY));
81*86d7f5d3SJohn Marino if (cwd->desc < 0)
82*86d7f5d3SJohn Marino {
83*86d7f5d3SJohn Marino cwd->desc = fd_safer (open (".", O_WRONLY));
84*86d7f5d3SJohn Marino if (cwd->desc < 0)
85*86d7f5d3SJohn Marino {
86*86d7f5d3SJohn Marino cwd->name = xgetcwd ();
87*86d7f5d3SJohn Marino return cwd->name ? 0 : -1;
88*86d7f5d3SJohn Marino }
89*86d7f5d3SJohn Marino }
90*86d7f5d3SJohn Marino
91*86d7f5d3SJohn Marino return 0;
92*86d7f5d3SJohn Marino }
93*86d7f5d3SJohn Marino
94*86d7f5d3SJohn Marino /* Change to recorded location, CWD, in directory hierarchy.
95*86d7f5d3SJohn Marino Upon failure, return -1 (errno is set by chdir or fchdir).
96*86d7f5d3SJohn Marino Upon success, return zero. */
97*86d7f5d3SJohn Marino
98*86d7f5d3SJohn Marino int
restore_cwd(const struct saved_cwd * cwd)99*86d7f5d3SJohn Marino restore_cwd (const struct saved_cwd *cwd)
100*86d7f5d3SJohn Marino {
101*86d7f5d3SJohn Marino if (0 <= cwd->desc)
102*86d7f5d3SJohn Marino return fchdir (cwd->desc);
103*86d7f5d3SJohn Marino else
104*86d7f5d3SJohn Marino return -1;
105*86d7f5d3SJohn Marino }
106*86d7f5d3SJohn Marino
107*86d7f5d3SJohn Marino void
free_cwd(struct saved_cwd * cwd)108*86d7f5d3SJohn Marino free_cwd (struct saved_cwd *cwd)
109*86d7f5d3SJohn Marino {
110*86d7f5d3SJohn Marino if (cwd->desc >= 0)
111*86d7f5d3SJohn Marino close (cwd->desc);
112*86d7f5d3SJohn Marino if (cwd->name)
113*86d7f5d3SJohn Marino free (cwd->name);
114*86d7f5d3SJohn Marino }
115