[Top][All Lists]
[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;
}