Filehandles, files, directories

chown#

Change the owner and group of a list of files.

chown takes a numeric user id, a numeric group id, and a list of files, and reassigns ownership on every file that the calling process is allowed to touch. The first two elements of LIST are the new UID and GID, in that order; every element after that is a filename (or, on systems that support fchown(2), a filehandle). A value of -1 in either of the id slots means “leave that id unchanged” — useful when you want to change only the group, or only the owner.

Synopsis#

chown UID, GID, LIST
chown $uid, $gid, $file
chown $uid, $gid, @files
chown -1, $gid, @files          # change group only

What you get back#

The number of files whose ownership was successfully changed, as a plain integer. Not a boolean — a call over ten files that succeeds on seven returns 7. Check against the list length when you need all-or-nothing semantics:

my @files = ('a', 'b', 'c');
my $ok = chown $uid, $gid, @files;
$ok == @files
    or die "chown failed on ", scalar(@files) - $ok, " files: $!";

When any individual file fails, $! holds the errno from the last failing call. A return value less than scalar @files is the reliable “something went wrong” signal; $! tells you what the last failure was, not every failure.

Global state it touches#

  • $! — set to the errno of the last underlying chown(2) call that failed. Unchanged when every file succeeds.

Numeric ids only#

chown does not accept user or group names. Pass the string "root" where a uid is expected and you get a numeric conversion of 0 (with an Argument isn't numeric warning under use warnings) — almost never what you want. Translate names to numbers with getpwnam and getgrnam:

my $uid = getpwnam('alice')  // die "no such user";
my $gid = getgrnam('staff')  // die "no such group";
chown $uid, $gid, @files;

The list-context return of getpwnam gives the full passwd entry; in scalar context it gives just the uid, which is usually what chown wants.

Permission rules#

On Linux and every other POSIX system, only the superuser can give a file away to a different owner. An unprivileged user can change the group of a file they own, but only to one of their own secondary groups. Trying to do more returns failure with $! set to EPERM.

chown 0, 0, 'passwd.new'
    or warn "need root to chown: $!";

The restriction is kernel-enforced, not Perl-enforced — there is no pre-check that would save you a failed system call. Rely on the return value.

Examples#

Change both owner and group on a single file:

chown $uid, $gid, '/var/log/app.log'
    or die "chown failed: $!";

Change the group only, leaving the owner alone:

chown -1, $gid, @files;

Translate names to numeric ids before calling:

my ($login, $pass, $uid, $gid) = getpwnam('www-data')
    or die "www-data not in passwd file";
chown $uid, $gid, glob('/var/www/*');

Count how many files were actually reassigned:

my @targets = glob('/srv/data/*.dat');
my $changed = chown $uid, $gid, @targets;
warn "only $changed of ", scalar(@targets), " files changed: $!"
    if $changed != @targets;

Chown by filehandle on a system that supports fchown(2). The filehandle must be a glob or a glob reference — a bareword is treated as a filename:

open my $fh, '>', '/tmp/out' or die $!;
chown $uid, $gid, $fh;

Edge cases#

  • Empty file list: chown $uid, $gid; — no files to act on, returns 0, does not touch $!.

  • -1 in id position: standard POSIX sentinel meaning “leave this id unchanged.” Works on every supported platform.

  • String id: a non-numeric string silently becomes 0 (root / wheel) after the usual numeric conversion. Under use warnings you get an Argument isn't numeric warning, but there is no hard error. Always pass an integer.

  • Non-existent file: counted as a failure, does not abort the call. Remaining files still get processed.

  • Symlink target: chown follows symlinks and changes the pointed-to file. To chown the link itself, use lchown(2) via syscall or a module that exposes it — core Perl does not.

  • Filehandle form: on systems without fchown(2) (rare in practice on Linux), passing a filehandle raises an exception. Barewords in the file list are always treated as filenames — use \*FH or a my $fh to mean “this handle.”

  • Give-away restriction: on POSIX systems with _PC_CHOWN_RESTRICTED set for the target path, only root can change the owner at all. Probe with:

    use POSIX qw(pathconf _PC_CHOWN_RESTRICTED);
    my $restricted = pathconf($path, _PC_CHOWN_RESTRICTED);
    

Differences from upstream#

Fully compatible with upstream Perl 5.42.

See also#

  • chmod — change file permission bits; takes the same “mode, then file list” shape and returns the same number-of-files-changed count

  • stat — read the current owner, group, and mode of a file before deciding what to change

  • umask — set the default permission mask for files created by this process; complements chown for newly created files

  • getpwnam — translate a user name to the numeric uid chown requires

  • getgrnam — translate a group name to the numeric gid chown requires

  • $! — holds the errno of the last failing per-file chown(2) when the return count is below the list length