Blame lib/save-cwd.c

Packit 709fb3
/* save-cwd.c -- Save and restore current working directory.
Packit 709fb3
Packit 709fb3
   Copyright (C) 1995, 1997-1998, 2003-2006, 2009-2017 Free Software
Packit 709fb3
   Foundation, Inc.
Packit 709fb3
Packit 709fb3
   This program is free software: you can redistribute it and/or modify
Packit 709fb3
   it under the terms of the GNU General Public License as published by
Packit 709fb3
   the Free Software Foundation; either version 3 of the License, or
Packit 709fb3
   (at your option) any later version.
Packit 709fb3
Packit 709fb3
   This program is distributed in the hope that it will be useful,
Packit 709fb3
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 709fb3
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 709fb3
   GNU General Public License for more details.
Packit 709fb3
Packit 709fb3
   You should have received a copy of the GNU General Public License
Packit 709fb3
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
Packit 709fb3
Packit 709fb3
/* Written by Jim Meyering.  */
Packit 709fb3
Packit 709fb3
#include <config.h>
Packit 709fb3
Packit 709fb3
#include "save-cwd.h"
Packit 709fb3
Packit 709fb3
#include <errno.h>
Packit 709fb3
#include <fcntl.h>
Packit 709fb3
#include <stdbool.h>
Packit 709fb3
#include <stdio.h>
Packit 709fb3
#include <stdlib.h>
Packit 709fb3
Packit 709fb3
#include "chdir-long.h"
Packit 709fb3
#include "unistd--.h"
Packit 709fb3
#include "cloexec.h"
Packit 709fb3
Packit 709fb3
#if GNULIB_FCNTL_SAFER
Packit 709fb3
# include "fcntl--.h"
Packit 709fb3
#else
Packit 709fb3
# define GNULIB_FCNTL_SAFER 0
Packit 709fb3
#endif
Packit 709fb3
Packit 709fb3
/* Record the location of the current working directory in CWD so that
Packit 709fb3
   the program may change to other directories and later use restore_cwd
Packit 709fb3
   to return to the recorded location.  This function may allocate
Packit 709fb3
   space using malloc (via getcwd) or leave a file descriptor open;
Packit 709fb3
   use free_cwd to perform the necessary free or close.  Upon failure,
Packit 709fb3
   no memory is allocated, any locally opened file descriptors are
Packit 709fb3
   closed;  return non-zero -- in that case, free_cwd need not be
Packit 709fb3
   called, but doing so is ok.  Otherwise, return zero.
Packit 709fb3
Packit 709fb3
   The _raison d'etre_ for this interface is that the working directory
Packit 709fb3
   is sometimes inaccessible, and getcwd is not robust or as efficient.
Packit 709fb3
   So, we prefer to use the open/fchdir approach, but fall back on
Packit 709fb3
   getcwd if necessary.  This module works for most cases with just
Packit 709fb3
   the getcwd-lgpl module, but to be truly robust, use the getcwd module.
Packit 709fb3
Packit 709fb3
   Some systems lack fchdir altogether: e.g., OS/2, pre-2001 Cygwin,
Packit 709fb3
   SCO Xenix.  Also, SunOS 4 and Irix 5.3 provide the function, yet it
Packit 709fb3
   doesn't work for partitions on which auditing is enabled.  If
Packit 709fb3
   you're still using an obsolete system with these problems, please
Packit 709fb3
   send email to the maintainer of this code.  */
Packit 709fb3
Packit 709fb3
int
Packit 709fb3
save_cwd (struct saved_cwd *cwd)
Packit 709fb3
{
Packit 709fb3
  cwd->name = NULL;
Packit 709fb3
Packit 709fb3
  cwd->desc = open (".", O_SEARCH);
Packit 709fb3
  if (!GNULIB_FCNTL_SAFER)
Packit 709fb3
    cwd->desc = fd_safer (cwd->desc);
Packit 709fb3
  if (cwd->desc < 0)
Packit 709fb3
    {
Packit 709fb3
      cwd->name = getcwd (NULL, 0);
Packit 709fb3
      return cwd->name ? 0 : -1;
Packit 709fb3
    }
Packit 709fb3
Packit 709fb3
  set_cloexec_flag (cwd->desc, true);
Packit 709fb3
  return 0;
Packit 709fb3
}
Packit 709fb3
Packit 709fb3
/* Change to recorded location, CWD, in directory hierarchy.
Packit 709fb3
   Upon failure, return -1 (errno is set by chdir or fchdir).
Packit 709fb3
   Upon success, return zero.  */
Packit 709fb3
Packit 709fb3
int
Packit 709fb3
restore_cwd (const struct saved_cwd *cwd)
Packit 709fb3
{
Packit 709fb3
  if (0 <= cwd->desc)
Packit 709fb3
    return fchdir (cwd->desc);
Packit 709fb3
  else
Packit 709fb3
    return chdir_long (cwd->name);
Packit 709fb3
}
Packit 709fb3
Packit 709fb3
void
Packit 709fb3
free_cwd (struct saved_cwd *cwd)
Packit 709fb3
{
Packit 709fb3
  if (cwd->desc >= 0)
Packit 709fb3
    close (cwd->desc);
Packit 709fb3
  free (cwd->name);
Packit 709fb3
}