FunctionalPerl

 view release on metacpan or  search on metacpan

lib/Chj/xperlfunc.pm  view on Meta::CPAN

package Chj::xperlfunc::xstat {

    # (Alternative to arrays: hashes, so that slices like
    # ->{"dev","ino"} could be done? But so what.)
    sub dev     { shift->[0] }
    sub ino     { shift->[1] }
    sub mode    { shift->[2] }
    sub nlink   { shift->[3] }
    sub uid     { shift->[4] }
    sub gid     { shift->[5] }
    sub rdev    { shift->[6] }
    sub size    { shift->[7] }
    sub atime   { shift->[8] }
    sub mtime   { shift->[9] }
    sub ctime   { shift->[10] }
    sub blksize { shift->[11] }
    sub blocks  { shift->[12] }

    sub set_dev     { my $s = shift; ($s->[0])  = @_; }
    sub set_ino     { my $s = shift; ($s->[1])  = @_; }
    sub set_mode    { my $s = shift; ($s->[2])  = @_; }
    sub set_nlink   { my $s = shift; ($s->[3])  = @_; }
    sub set_uid     { my $s = shift; ($s->[4])  = @_; }
    sub set_gid     { my $s = shift; ($s->[5])  = @_; }
    sub set_rdev    { my $s = shift; ($s->[6])  = @_; }
    sub set_size    { my $s = shift; ($s->[7])  = @_; }
    sub set_atime   { my $s = shift; ($s->[8])  = @_; }
    sub set_mtime   { my $s = shift; ($s->[9])  = @_; }
    sub set_ctime   { my $s = shift; ($s->[10]) = @_; }
    sub set_blksize { my $s = shift; ($s->[11]) = @_; }
    sub set_blocks  { my $s = shift; ($s->[12]) = @_; }

    # test helpers:
    sub permissions     { shift->[2] & 07777 }
    sub permissions_oct { sprintf('%o', shift->permissions) }
    sub permissions_u   { (shift->[2] & 00700) >> 6 }
    sub permissions_g   { (shift->[2] & 00070) >> 3 }
    sub permissions_o   { shift->[2] & 00007 }
    sub permissions_s   { (shift->[2] & 07000) >> 9 }
    sub setuid          { !!(shift->[2] & 04000) }

    # ^ I have no desire to put is_ in front.
    sub setgid { !!(shift->[2] & 02000) }

    # sticky is simply the lowest of the 3 permissions_s bits:
    sub sticky   { !!(shift->[2] & 01000) }
    sub filetype { (shift->[2] & 0170000) >> 12 }    # 4*3bits

    sub fstype {
        my $s = shift;
        Chj::xperlfunc::fstype_for_device($s->dev)
    }

    our $has_no_subdirs_safe_fstype = +{
        ext2     => 1,
        ext3     => 1,
        ext4     => 1,
        tmpfs    => 1,
        vfat     => 1,
        squashfs => 1,
        overlay  => 0,
    };

    sub has_no_subdirs {
        my $s = shift;
        $s->is_dir or die "has_no_subdirs can only be used on directories";
        my $dev    = $s->dev;
        my $fstype = $s->fstype;
        if ($$has_no_subdirs_safe_fstype{$fstype}) {
            my $n = $s->nlink;
            $n < 2
                ? die
                "bug: dir on device node $dev has < 2 links, need to ignore this file system"
                : $n == 2;
        } else {
            undef
        }
    }

    # Guess access rights from permission bits
    # note that these might guess wrong (because of chattr stuff,
    # or things like grsecurity,lids,selinux..)!
    # Also NOTE: this does not check parent folders of this item!
    sub checkaccess_for_submask_by_uid_gids {
        my $s = shift;
        my ($mod, $uid, $gids) = @_;    # the latter being an array ref!
            #return 1 if $uid == 0;
            #  ^ this is not correct for say, is_executable with uid 0;
            #    XXX how should it behave in other cases?
        if ($s->[4] == $uid) {
            return !!($s->[2] & (00100 * $mod))
        } else {
            if ($gids) {
                for my $gid (@$gids) {
                    length($gid) == length($gid +0)
                        or Carp::croak "invalid gid argument '$gid' - maybe "
                        . " you forgot to split '\$)'?";

                    # XXX: what if one is member of group 0, is this special?
                    if ($s->[5] == $gid) {
                        if ($s->[2] & (00010 * $mod)) {
                            return 1;
                        } else {

                            # even if others are allowed, we are not
                            return 0;
                        }
                    }
                }
                return !!($s->[2] & (00001 * $mod))
            } else {
                Carp::croak "missing gids argument - might just be a ref to "
                    . "an empty array";
            }
        }
    }

    sub readable_by_uid_gids {
        splice @_, 1, 0, 4;
        goto &checkaccess_for_submask_by_uid_gids;
    }



( run in 3.209 seconds using v1.01-cache-2.11-cpan-df04353d9ac )