#!/usr/bin/perl -w
use strict;

use Fuse;
use POSIX qw(ENOENT EISDIR EINVAL);
use Data::Dumper;

my $files = {
	'.' => {
		type => 0040,
		mode => 0755,
		ctime => time(),
	},
	'..' => {
		type => 0040,
		mode => 0755,
		ctime => time(),
	},
	'/' => {
		type => 0040,
		mode => 0755,
		ctime => time(),
	},
};

sub filename_fixup {
	my ($file) = shift;
	warn "## fixup: $file\n";
	$file = '.' unless length($file);
	return $file;
}

sub wmiir {
	my ($action,$arg) = @_;

	my @out;

	warn "# wmiir $action $arg\n";

	open(my $vfs, "wmiir $action $arg |") || die "can't open wmiir: $!";
	while(<$vfs>) {
		chomp;
		next if ($_ eq '');
		push @out, $_;

		my $path = $arg . '/' . $_;
		$path =~ s,//,/,g;

		if ($path =~ s#/$##) {
			$files->{$path} = {
				type => 0040,
				mode => 0755,
				ctime => time(),
			};
		} else {
			$files->{$path} = {
				type => 0100,
				mode => 0644,
				ctime => time(),
			};

		}
	}

	print Dumper($files);

	return @out;
}


sub e_getattr {
	my ($file) = filename_fixup(shift);

	print "# getattr($file)\n";

	return -ENOENT() unless exists($files->{$file});

	my ($size) = 0;
	my ($modes) = ($files->{$file}->{type}<<9) + $files->{$file}->{mode};
	my ($dev, $ino, $rdev, $blocks, $gid, $uid, $nlink, $blksize) = (0,0,0,1,0,0,1,1024);
	my ($atime, $ctime, $mtime);
	$atime = $ctime = $mtime = $files->{$file}->{ctime};
	# 2 possible types of return values:
	#return -ENOENT(); # or any other error you care to
	#print(join(",",($dev,$ino,$modes,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks)),"\n");
	return ($dev,$ino,$modes,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks);
}

sub e_getdir {
	my ($dir) = filename_fixup(shift);
	my @i = map { s#/$##; $_ } wmiir('read', $dir);
	return @i,0;
}

sub e_open {
	# VFS sanity check; it keeps all the necessary state, not much to do here.
	my ($file) = filename_fixup(shift);
	print("open called\n");
	return -ENOENT() unless exists($files->{$file});
	return -EISDIR() unless ($files->{$file}->{type} && 0100);
	print("open ok\n");
	return 0;
}

sub e_read {
	# return an error numeric, or binary/text string.  (note: 0 means EOF, "0" will
	# give a byte (ascii "0") to the reading program)
	my ($file) = filename_fixup(shift);
	my ($len,$off) = @_;
	return -ENOENT() unless exists($files->{$file});
	my $cont = join("\n",wmiir('read', $file));
	return -EINVAL() if $off > length($cont);
	return 0 if $off == length($cont);
	warn "## $cont\n";
	return substr($cont,$off,$len);
}

sub e_statfs {
	return 255, 1, 1, 1, 1, 2;
}

wmiir('read','/');

# If you run the script directly, it will run fusermount, which will in turn
# re-run this script.  Hence the funky semantics.
my ($mountpoint) = "/mnt2";
$mountpoint = shift(@ARGV) if @ARGV;
Fuse::main(
	mountpoint=>$mountpoint,
	getattr=>"main::e_getattr",
	getdir =>"main::e_getdir",
	open   =>"main::e_open",
	statfs =>"main::e_statfs",
	read   =>"main::e_read",
	threaded=>0,
	debug=>1,
);
