xref: /dflybsd-src/contrib/cvs-1.12/lib/save-cwd.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
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