Package: debhelper
Followup-For: Bug #894549

Hello.

This new diff should fix the same issues in dh_usrlocal.
The result is more readable in my opinion, hopefully preventing
similar errors in the future.

It should also be a bit more efficient: instead of sorting two huge
lists of paths all starting with "/usr/share/", it sorts once simple
names in each directory.

When a normal file is encountered, it displays an error instead of a
warning. This does not change much, as rmdir would fail with a less
explicit message when attempting to remove the containing directory.
--- a/dh_usrlocal
+++ b/dh_usrlocal
@@ -76,55 +76,50 @@
 	my $tmp = tmpdir($package);
 
 	if (-d "$tmp/usr/local") {
-		my (@dirs, @justdirs);
-		find({bydepth => 1,
-		      no_chdir => 1,
+		my ($dirs, $justdirs);
+		find({no_chdir => 1,
+		      preprocess => sub {
+			# Ensure a reproducible traversal.
+			return sort @_;
+		      },
+		      postprocess => sub {
+			# Uninstall, unless a direct child of /usr/local.
+			$_ = $File::Find::dir;
+			s!^\Q$tmp\E!!;
+			$justdirs .= "\\\\\n$_" if m!/usr/local/.*/!;
+			# Remove a directory after its childs.
+			doit('rmdir', $File::Find::dir);
+		      },
 		      wanted => sub {
+			# rmdir would fail later anyways.
+			error("${File::Find::name} is not a directory")
+				if not -d $File::Find::name;
+			# Install directory before its childs.
 			my $fn = $File::Find::name;
-			if (-d $fn) {
-				my $user = 'root';
-				my $group = 'staff';
-				my $mode = '02775';
-				if (should_use_root()) {
-					my $stat = stat $fn;
-					$user = getpwuid $stat->uid;
-					$group = getgrgid $stat->gid;
-					$mode = sprintf "%04lo", ($stat->mode & 07777);
-					if ($stat->uid == 0 && $stat->gid == 0) {
-						$group = 'staff';
-						$mode = '02775';
-					}
+			$fn =~ s!^\Q$tmp\E!!;
+			return if $fn eq '/usr/local';
+			if (should_use_root()) {
+				my $stat = stat $File::Find::dir;
+				if ($stat->uid == 0 && $stat->gid == 0) {
+					$dirs .= "\\\\\n$fn 02775 root staff";
+				} else {
+					my $user = getpwuid $stat->uid;
+					my $group = getgrgid $stat->gid;
+					my $mode = sprintf "%04lo", ($stat->mode & 07777);
+					$dirs .= "\\\\\n$fn $mode $user $group";
 				}
-
-
-
-				$fn =~ s!^\Q$tmp\E!!;
-				return if $fn eq '/usr/local';
-				
-				# @dirs is in parents-first order for dir creation...
-				unshift @dirs, "$fn $mode $user $group";
-				# ...whereas @justdirs is depth-first for removal.
-				push @justdirs, $fn;
-				doit('rmdir', $_);
-			}
-			else {
-				warning("$fn is not a directory");
+			} else {
+				$dirs .= "\\\\\n$fn 02775 root staff";
 			}
 		      }}, "$tmp/usr/local");
-		doit('rmdir', "$tmp/usr/local");
-	
-		my $bs = "\\";     # A single plain backslash
-		my $ebs = $bs x 2; # Escape the backslash from the shell
+
 		# This constructs the body of a 'sed' c\ expression which
 		# is parsed by the shell in double-quotes
-		my $dirs = join("$ebs\n", sort @dirs);
-		pop @justdirs; # don't remove directories directly in /usr/local
-		my $justdirs = join("$ebs\n", reverse sort @justdirs);
 		if (! $dh{NOSCRIPTS}) { 
 			autoscript($package,"postinst", "postinst-usrlocal",
-				   "/#DIRS#/ c${ebs}\n${dirs}");
+				   "/#DIRS#/ c$dirs") if $dirs;
 			autoscript($package,"prerm", "prerm-usrlocal",
-				   "/#JUSTDIRS#/ c${ebs}\n${justdirs}") if length $justdirs;
+				   "/#JUSTDIRS#/ c$justdirs") if $justdirs;
 		}
 	}
 }

Reply via email to