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