/* Change the ownership and mode bits of a directory.
- Copyright (C) 2006 Free Software Foundation, Inc.
+ Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc.
- This program is free software; you can redistribute it and/or modify
+ This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software Foundation,
- Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* Written by Paul Eggert. */
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
+#include <config.h>
#include "dirchownmod.h"
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
-#include <fcntl.h>
#include <unistd.h>
-#include "lchmod.h"
#include "stat-macros.h"
-#ifndef O_DIRECTORY
-# define O_DIRECTORY 0
-#endif
-#ifndef O_NOFOLLOW
-# define O_NOFOLLOW 0
+#ifndef HAVE_FCHMOD
+# define HAVE_FCHMOD 0
+# undef fchmod
+# define fchmod(fd, mode) (-1)
#endif
-/* Change the ownership and mode bits of the directory DIR.
+/* Change the ownership and mode bits of a directory. If FD is
+ nonnegative, it should be a file descriptor associated with the
+ directory; close it before returning. DIR is the name of the
+ directory.
If MKDIR_MODE is not (mode_t) -1, mkdir (DIR, MKDIR_MODE) has just
been executed successfully with umask zero, so DIR should be a
calls may do the chown but not the chmod. */
int
-dirchownmod (char const *dir, mode_t mkdir_mode,
+dirchownmod (int fd, char const *dir, mode_t mkdir_mode,
uid_t owner, gid_t group,
mode_t mode, mode_t mode_bits)
{
struct stat st;
- int result;
-
- /* Manipulate DIR via a file descriptor if possible, to avoid some races. */
- int open_flags = O_RDONLY | O_DIRECTORY | O_NOCTTY | O_NOFOLLOW | O_NONBLOCK;
- int fd = open (dir, open_flags);
-
- /* Fail if the directory is unreadable, the directory previously
- existed or was created without read permission. Otherwise, get
- the file's status. */
- if (0 <= fd)
- result = fstat (fd, &st);
- else if (errno != EACCES
- || (mkdir_mode != (mode_t) -1 && mkdir_mode & S_IRUSR))
- return fd;
- else
- result = stat (dir, &st);
+ int result = (fd < 0 ? stat (dir, &st) : fstat (fd, &st));
if (result == 0)
{
{
mode_t chmod_mode =
mode | (dir_mode & CHMOD_MODE_BITS & ~mode_bits);
- result = (0 <= fd
+ result = (HAVE_FCHMOD && 0 <= fd
? fchmod (fd, chmod_mode)
: mkdir_mode != (mode_t) -1
? lchmod (dir, chmod_mode)