Package: moreutils ----- Forwarded message from Moshe Kamensky <[EMAIL PROTECTED]> -----
From: Moshe Kamensky <[EMAIL PROTECTED]>
Date: Mon, 1 Jan 2007 13:59:34 +0000
To: Joey Hess <[EMAIL PROTECTED]>
Subject: vidir modifications
User-Agent: Mutt/1.5.11
Hi,
I've been using your vidir script (part of moreutils), and found it very
useful. I made two modifications, in the attached patch:
1. Added a --long option, which lists the files with permissions and
owner, and allows to change them.
2. Added a --pretend option, which outputs shell commands performing the
required modifications, instead of actually making them.
Thanks,
Moshe
--- vidir.orig 2006-11-12 03:01:36.000000000 +0000
+++ vidir 2007-01-01 13:35:25.039264000 +0000
@@ -6,7 +6,7 @@
=head1 SYNOPSIS
-B<vidir> [--verbose] [directory|file|-] ...
+B<vidir> [--verbose] [--pretend] [--long] [directory|file|-] ...
=head1 DESCRIPTION
@@ -31,6 +31,17 @@
Verbosely display the actions taken by the program.
+=item -p, --pretend
+
+Instead of actually performing the operations, produces a list of shell
+commands to achieve the same effect. Probably doesn't make sense together
+with B<--verbose>.
+
+=item -l, --long
+
+In addition to file names, produces for each file the (octal) mode, user and
+group. These can be modified as well.
+
=back
=head1 ENVIRONMENT VARIABLES
@@ -62,14 +73,84 @@
use File::Temp;
use Getopt::Long;
+use warnings;
+use strict;
my $error=0;
my $verbose=0;
-if (! GetOptions("verbose|v" => \$verbose)) {
+my $long = 0;
+my $pretend = 0;
+unless ( GetOptions(
+ 'verbose|v' => \$verbose,
+ 'pretend|p!' => \$pretend,
+ 'long|l!' => \$long,
+) ) {
die "Usage: $0 [--verbose] [directory|file|-]\n";
}
+use vars qw($rename $unlink $chmod $chown $file_exists %rev);
+
+if ( $pretend ) {
+ $rename = sub { print "mv $_[0] $_[1]\n"; delete $rev{$_[0]}; 1 };
+ $unlink = sub { print "rm @_\n"; delete $rev{$_[0]}; 1 };
+ $chmod = sub { printf("chmod %04o %s\n", @_); 1 };
+ $chown = sub {
+ printf("chown %s:%s %s\n", uid2str($_[0]), gid2str($_[1]),
$_[2]);
+ 1
+ };
+ $file_exists = sub { exists $rev{shift()} };
+} else {
+ $rename = sub { rename $_[0], $_[1] };
+ $unlink = sub { unlink @_ };
+ $chmod = sub { chmod @_ };
+ $chown = sub { chown @_ };
+ $file_exists = sub { -l shift || -e _ };
+}
+
+sub mode2str {
+ sprintf("%04o", shift);
+}
+
+sub str2mode {
+ oct(shift);
+}
+
+sub uid2str {
+ my $uid = shift;
+ my $suid = getpwuid($uid);
+ $suid ? $suid : $uid;
+}
+
+sub str2uid {
+ my $suid = shift;
+ my $uid = getpwnam($suid);
+ defined($uid) ? $uid : $suid;
+}
+
+sub gid2str {
+ my $gid = shift;
+ my $sgid = getgrgid($gid);
+ $sgid ? $sgid : $gid;
+}
+
+sub str2gid {
+ my $sgid = shift;
+ my $gid = getgrnam($sgid);
+ defined($gid) ? $gid : $sgid;
+}
+
+use vars qw(@mode @uid @gid);
+
+sub long {
+ use Fcntl ':mode';
+ my ($file, $c) = @_;
+ ($mode[$c], $uid[$c], $gid[$c]) = (stat $file)[2,4,5];
+ $mode[$c] = S_IMODE($mode[$c]);
+ join(' ', mode2str($mode[$c]), uid2str($uid[$c]),
+ gid2str($gid[$c]), $file)
+}
+
my @dir;
if (! @ARGV) {
push @ARGV, "."
@@ -89,7 +170,7 @@
push @dir, $item;
}
}
-
+
my $tmp=File::Temp->new(template => "dirXXXXX");
open (OUT, ">".$tmp->filename) || die "$0: cannot write ".$tmp->filename.":
$!\n";
@@ -98,7 +179,9 @@
foreach (@dir) {
next if /^(.*\/)?\.$/ || /^(.*\/)?\.\.$/;
$item{++$c}=$_;
- print OUT "$c\t$_\n";
+ $rev{$_}=$c;
+ my $file = $long ? long($_, $c) : $_;
+ print OUT "$c\t$file\n";
}
@dir=();
close OUT;
@@ -113,7 +196,7 @@
if (exists $ENV{VISUAL}) {
@editor=split(' ', $ENV{VISUAL});
}
-$ret=system(@editor, $tmp);
+my $ret=system(@editor, $tmp);
if ($ret != 0) {
die "@editor exited nonzero, aborting\n";
}
@@ -121,40 +204,65 @@
open (IN, $tmp->filename) || die "$0: cannot read ".$tmp->filename.": $!\n";
while (<IN>) {
chomp;
+ next if /^\s*$/ or /^\s*#/;
if (/^(\d+)\t{0,1}(.*)/) {
my $num=$1;
my $name=$2;
- if (! exists $item{$num}) {
+ my $src = $item{$num};
+ unless (defined $src) {
print STDERR "$0: unknown item number $num\n";
$error=1;
+ next;
}
- elsif ($name ne $item{$num}) {
+ if ( $long ) {
+ (my ($mode, $uid, $gid), $name) = split(' ', $name, 4);
+
+ $mode = str2mode($mode);
+ if ( $mode != $mode[$num] ) {
+ if (!&$chmod($mode, $src)) {
+ print STDERR "$0: failed to chmod $src
to $mode: $!\n";
+ $error=1;
+ } elsif ($verbose) {
+ printf("'$src': %s -> %s\n",
mode2str($mode[$num]), mode2str($mode));
+ }
+ }
+
+ $uid = str2uid($uid);
+ $gid = str2gid($gid);
+ if ( $uid != $uid[$num] or $gid != $gid[$num] ) {
+ if (!&$chown($uid, $gid, $src)) {
+ print STDERR "$0: failed to chown $src
to '$uid:$gid': $!\n";
+ $error=1;
+ } elsif ($verbose) {
+ print "'$src': $uid[$num]:$gid[$num] ->
$uid:$gid\n";
+ }
+ }
+ }
+
+ if ($name ne $item{$num}) {
next unless length $name;
- my $src=$item{$num};
-
+
# deal with swaps
- if (-e $name || -l $name) {
+ if (&$file_exists($name)) {
my $tmp=$name."~";
my $c=0;
- while (-e $tmp || -l $tmp) {
+ while (&$file_exists($tmp)) {
$c++;
$tmp=$name."~$c";
}
- if (! rename($name, $tmp)) {
+ $rev{$tmp} = delete $rev{$name};
+ $item{$rev{$tmp}}=$tmp;
+ if (! &$rename($name, $tmp)) {
print STDERR "$0: failed to rename
$name to $tmp: $!\n";
$error=1;
}
elsif ($verbose) {
print "'$name' -> '$tmp'\n";
}
- foreach my $item (keys %item) {
- if ($item{$item} eq $name) {
- $item{$item}=$tmp;
- }
- }
+
}
- if (! rename($src, $name)) {
+ if (! &$rename($src, $name)) {
print STDERR "$0: failed to rename $src to
$name: $!\n";
$error=1;
}
@@ -164,9 +272,6 @@
}
delete $item{$num};
}
- elsif (/^\s*$/) {
- # skip empty line
- }
else {
die "$0: unable to parse line \"$_\", aborting\n";
}
@@ -175,7 +280,7 @@
unlink($tmp.'~') if -e $tmp.'~';
foreach my $item (sort values %item) {
- if (! unlink($item)) {
+ if (! &$unlink($item)) {
print STDERR "$0: failed to remove $item: $!\n";
$error=1;
}
@@ -185,3 +290,5 @@
}
exit $error;
+
+# vim: sw=8 noet:
----- End forwarded message -----
--
see shy jo
signature.asc
Description: Digital signature

