bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

FYI: new openat-like function: mkdirat


From: Jim Meyering
Subject: FYI: new openat-like function: mkdirat
Date: Wed, 30 Nov 2005 14:40:15 +0100

Thinking about how to make thread-safe the directory-creating parts
of cp -r, mv, tar, cpio, and even mkdir -p (i.e., don't change
the initial working directory), while remaining efficient even for
deep hierarchies, I realized that we need a new function, mkdirat,
which I've just checked in to coreutils/lib/mkdirat.c.

Unlike the other openat-like functions, this one is in a separate
file, since it's compiled unconditionally, which is because no
system provides it, yet...  But if my mentioning it to Ulrich works
as quickly this time as it did for openat et al, it'll be in glibc
by week's end :-)

So far, only on Linux+PROC_FS can we emulate this without resorting
to the save_cwd/fchdir/restore_cwd crutch.  If anyone knows how to do
the same thing using /proc on some other type of system, please tell.

Note that Solaris seems not to provide this function -- I wonder why.

2005-11-30  Jim Meyering  <address@hidden>

        * mkdirat.c (mkdirat): New file and function.
        * openat.h (mkdirat): Declare.

2005-11-30  Jim Meyering  <address@hidden>

        * openat.m4 (gl_FUNC_OPENAT): Require and compile mkdirat.c.

Here is the important part of the new file:

/* Solaris 10 has no function like this.
   Create a subdirectory, FILE, with mode MODE, in the directory
   open on descriptor FD.  If possible, do it without changing the
   working directory.  Otherwise, resort to using save_cwd/fchdir,
   then mkdir/restore_cwd.  If either the save_cwd or the restore_cwd
   fails, then give a diagnostic and exit nonzero.  */
int
mkdirat (int fd, char const *file, mode_t mode)
{
  struct saved_cwd saved_cwd;
  int saved_errno;
  int err;

  if (fd == AT_FDCWD || IS_ABSOLUTE_FILE_NAME (file))
    return mkdir (file, mode);

  {
    char *proc_file;
    BUILD_PROC_NAME (proc_file, fd, file);
    err = mkdir (proc_file, mode);
    /* If the syscall succeeds, or if it fails with an unexpected
       errno value, then return right away.  Otherwise, fall through
       and resort to using save_cwd/restore_cwd.  */
    if (0 <= err || ! EXPECTED_ERRNO (errno))
      return err;
  }

  if (save_cwd (&saved_cwd) != 0)
    openat_save_fail (errno);

  if (fchdir (fd) != 0)
    {
      saved_errno = errno;
      free_cwd (&saved_cwd);
      errno = saved_errno;
      return -1;
    }

  err = mkdir (file, mode);
  saved_errno = (err < 0 ? errno : 0);

  if (restore_cwd (&saved_cwd) != 0)
    openat_restore_fail (errno);

  free_cwd (&saved_cwd);

  if (saved_errno)
    errno = saved_errno;
  return err;
}




reply via email to

[Prev in Thread] Current Thread [Next in Thread]