save-cwd.c revision 1.1.1.2 1 1.1 christos /* save-cwd.c -- Save and restore current working directory.
2 1.1 christos
3 1.1.1.2 christos Copyright (C) 1995, 1997-1998, 2003-2006, 2009-2022 Free Software
4 1.1 christos Foundation, Inc.
5 1.1 christos
6 1.1 christos This program is free software: you can redistribute it and/or modify
7 1.1 christos it under the terms of the GNU General Public License as published by
8 1.1.1.2 christos the Free Software Foundation, either version 3 of the License, or
9 1.1 christos (at your option) any later version.
10 1.1 christos
11 1.1 christos This program is distributed in the hope that it will be useful,
12 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of
13 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 1.1 christos GNU General Public License for more details.
15 1.1 christos
16 1.1 christos You should have received a copy of the GNU General Public License
17 1.1 christos along with this program. If not, see <https://www.gnu.org/licenses/>. */
18 1.1 christos
19 1.1 christos /* Written by Jim Meyering. */
20 1.1 christos
21 1.1 christos #include <config.h>
22 1.1 christos
23 1.1 christos #include "save-cwd.h"
24 1.1 christos
25 1.1 christos #include <errno.h>
26 1.1 christos #include <fcntl.h>
27 1.1 christos #include <stdbool.h>
28 1.1 christos #include <stdio.h>
29 1.1 christos #include <stdlib.h>
30 1.1 christos
31 1.1 christos #include "chdir-long.h"
32 1.1 christos #include "unistd--.h"
33 1.1 christos
34 1.1 christos #if GNULIB_FCNTL_SAFER
35 1.1 christos # include "fcntl--.h"
36 1.1 christos #else
37 1.1 christos # define GNULIB_FCNTL_SAFER 0
38 1.1 christos #endif
39 1.1 christos
40 1.1 christos /* Record the location of the current working directory in CWD so that
41 1.1 christos the program may change to other directories and later use restore_cwd
42 1.1 christos to return to the recorded location. This function may allocate
43 1.1 christos space using malloc (via getcwd) or leave a file descriptor open;
44 1.1 christos use free_cwd to perform the necessary free or close. Upon failure,
45 1.1 christos no memory is allocated, any locally opened file descriptors are
46 1.1 christos closed; return non-zero -- in that case, free_cwd need not be
47 1.1 christos called, but doing so is ok. Otherwise, return zero.
48 1.1 christos
49 1.1 christos The _raison d'etre_ for this interface is that the working directory
50 1.1 christos is sometimes inaccessible, and getcwd is not robust or as efficient.
51 1.1 christos So, we prefer to use the open/fchdir approach, but fall back on
52 1.1 christos getcwd if necessary. This module works for most cases with just
53 1.1 christos the getcwd-lgpl module, but to be truly robust, use the getcwd module.
54 1.1 christos
55 1.1 christos Some systems lack fchdir altogether: e.g., OS/2, pre-2001 Cygwin,
56 1.1 christos SCO Xenix. Also, SunOS 4 and Irix 5.3 provide the function, yet it
57 1.1 christos doesn't work for partitions on which auditing is enabled. If
58 1.1 christos you're still using an obsolete system with these problems, please
59 1.1 christos send email to the maintainer of this code. */
60 1.1 christos
61 1.1 christos int
62 1.1 christos save_cwd (struct saved_cwd *cwd)
63 1.1 christos {
64 1.1 christos cwd->name = NULL;
65 1.1 christos
66 1.1 christos cwd->desc = open (".", O_SEARCH | O_CLOEXEC);
67 1.1 christos if (!GNULIB_FCNTL_SAFER)
68 1.1 christos cwd->desc = fd_safer_flag (cwd->desc, O_CLOEXEC);
69 1.1 christos if (cwd->desc < 0)
70 1.1 christos {
71 1.1 christos cwd->name = getcwd (NULL, 0);
72 1.1 christos return cwd->name ? 0 : -1;
73 1.1 christos }
74 1.1 christos
75 1.1 christos return 0;
76 1.1 christos }
77 1.1 christos
78 1.1 christos /* Change to recorded location, CWD, in directory hierarchy.
79 1.1 christos Upon failure, return -1 (errno is set by chdir or fchdir).
80 1.1 christos Upon success, return zero. */
81 1.1 christos
82 1.1 christos int
83 1.1 christos restore_cwd (const struct saved_cwd *cwd)
84 1.1 christos {
85 1.1 christos if (0 <= cwd->desc)
86 1.1 christos return fchdir (cwd->desc);
87 1.1 christos else
88 1.1 christos return chdir_long (cwd->name);
89 1.1 christos }
90 1.1 christos
91 1.1 christos void
92 1.1 christos free_cwd (struct saved_cwd *cwd)
93 1.1 christos {
94 1.1 christos if (cwd->desc >= 0)
95 1.1 christos close (cwd->desc);
96 1.1 christos free (cwd->name);
97 1.1 christos }
98