|  line  | 
 stmt  | 
 bran  | 
 cond  | 
 sub  | 
 pod  | 
 time  | 
 code  | 
| 
1
 | 
  
 
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 package DataStore::CAS::FS;  | 
| 
2
 | 
4
 | 
 
 | 
 
 | 
  
4
  
 | 
 
 | 
67728
 | 
 use 5.008;  | 
| 
 
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10
 | 
    | 
| 
3
 | 
4
 | 
 
 | 
 
 | 
  
4
  
 | 
 
 | 
430
 | 
 use Moo 1.000007;  | 
| 
 
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
9487
 | 
    | 
| 
 
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
20
 | 
    | 
| 
4
 | 
4
 | 
 
 | 
 
 | 
  
4
  
 | 
 
 | 
1642
 | 
 use Carp;  | 
| 
 
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
13
 | 
    | 
| 
 
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
209
 | 
    | 
| 
5
 | 
4
 | 
 
 | 
 
 | 
  
4
  
 | 
 
 | 
402
 | 
 use Try::Tiny 0.11;  | 
| 
 
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
975
 | 
    | 
| 
 
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
182
 | 
    | 
| 
6
 | 
4
 | 
 
 | 
 
 | 
  
4
  
 | 
 
 | 
17
 | 
 use File::Spec 3.33;  | 
| 
 
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
60
 | 
    | 
| 
 
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
79
 | 
    | 
| 
7
 | 
4
 | 
 
 | 
 
 | 
  
4
  
 | 
 
 | 
452
 | 
 use DataStore::CAS 0.02;  | 
| 
 
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
20503
 | 
    | 
| 
 
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10459
 | 
    | 
| 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 our $VERSION= '0.011000';  | 
| 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 require DataStore::CAS::FS::Dir;  | 
| 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 require DataStore::CAS::FS::DirCodec::Universal;  | 
| 
13
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 require DataStore::CAS::FS::DirCodec::Minimal;  | 
| 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 require DataStore::CAS::FS::DirCodec::Unix;  | 
| 
15
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
16
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # ABSTRACT: Virtual Filesystem backed by Content-Addressable Storage  | 
| 
17
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
18
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
19
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 has store             => ( is => 'ro', required => 1, isa => \&_validate_cas );  | 
| 
20
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 has root_entry        => ( is => 'rwp', required => 1 );  | 
| 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 has case_insensitive  => ( is => 'ro', default => sub { 0 } );  | 
| 
22
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
23
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
  
1
  
 | 
45
 | 
 sub hash_of_null         { $_[0]->store->hash_of_null }  | 
| 
24
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 has hash_of_empty_dir => ( is => 'lazy' );  | 
| 
25
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
26
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 has dir_cache         => ( is => 'rw', default => sub { DataStore::CAS::FS::DirCache->new() } );  | 
| 
27
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
28
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # _nodes is a tree of nodes, each of the form:  | 
| 
29
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # $node= {  | 
| 
30
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 #   dirent  => $Dir_Entry,  # mandatory  | 
| 
31
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 #   dir     => $CAS_FS_Dir, # optional, created on demand  | 
| 
32
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 #   subtree => {  | 
| 
33
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 #     KEY1 => $node1,  | 
| 
34
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 #     KEY2 => $node2,  | 
| 
35
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 #     ...  | 
| 
36
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 #   }  | 
| 
37
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 #   changed => 1 # set if a path override has happened here, or in any child node  | 
| 
38
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 #   invalid => 1 # set whenever a path override deletes this node  | 
| 
39
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # }  | 
| 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 #  | 
| 
41
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 #  If 'case_insensitive' is true, the keys will all be upper-case, but the $Dir_Entry  | 
| 
42
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 #  objects will contain the correct-case name.  | 
| 
43
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 #  | 
| 
44
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 has _nodes   => ( is => 'rw' );  | 
| 
45
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
46
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
47
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub _build_hash_of_empty_dir {  | 
| 
48
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
 
 | 
10
 | 
 	my $self= shift;  | 
| 
49
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
12
 | 
 	my $empty= DataStore::CAS::FS::DirCodec::Minimal->encode([],{});  | 
| 
50
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
12
 | 
 	return $self->store->put_scalar($empty);  | 
| 
51
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
52
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
53
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub _validate_cas {  | 
| 
54
 | 
7
 | 
 
 | 
 
 | 
  
7
  
 | 
 
 | 
67
 | 
 	my $cas= shift;  | 
| 
55
 | 
7
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
179
 | 
 	ref($cas) && ref($cas)->can('get') && ref($cas)->can('put')  | 
| 
 
 | 
 
 | 
 
 | 
  
 33
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
56
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		or croak "Invalid CAS object: $cas"  | 
| 
57
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 };  | 
| 
58
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
59
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub BUILDARGS {  | 
| 
60
 | 
7
 | 
 
 | 
 
 | 
  
7
  
 | 
  
0
  
 | 
15636
 | 
 	my $class= shift;  | 
| 
61
 | 
7
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
40
 | 
 	my %p= (@_ == 1 && ref $_[0] eq 'HASH')? %{$_[0]} : @_;  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
62
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# Root is an alias for root_entry  | 
| 
63
 | 
7
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
18
 | 
 	if (defined $p{root}) {  | 
| 
64
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		defined $p{root_entry}  | 
| 
65
 | 
7
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
17
 | 
 			and croak "Specify only one of 'root' or 'root_entry'";  | 
| 
66
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
14
 | 
 		$p{root_entry}= delete $p{root};  | 
| 
67
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
68
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
98
 | 
 	return \%p;  | 
| 
69
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
70
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
71
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub BUILD {  | 
| 
72
 | 
7
 | 
 
 | 
 
 | 
  
7
  
 | 
  
0
  
 | 
52
 | 
 	my ($self, $args)= @_;  | 
| 
73
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
19
 | 
 	my @invalid= grep { !$self->can($_) } keys %$args;  | 
| 
 
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
44
 | 
    | 
| 
74
 | 
7
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
19
 | 
 	croak "Invalid param(s): ".join(', ', @invalid)  | 
| 
75
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		if @invalid;  | 
| 
76
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
77
 | 
7
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
57
 | 
 	croak "Missing/Invalid parameter 'dir_cache'"  | 
| 
78
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		unless defined $self->dir_cache and $self->dir_cache->can('clear');  | 
| 
79
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
80
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# coerce root_entry to an actual DirEnt object  | 
| 
81
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
14
 | 
 	my $root= $self->root_entry;  | 
| 
82
 | 
7
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
16
 | 
 	defined $root  | 
| 
83
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		or croak "root_entry is required";  | 
| 
84
 | 
7
 | 
  
100
  
 | 
  
 66
  
 | 
 
 | 
 
 | 
55
 | 
 	unless (ref $root && ref($root)->isa('DataStore::CAS::FS::DirEnt')) {  | 
| 
85
 | 
2
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
44
 | 
 		$self->_set_root_entry(  | 
| 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
86
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			DataStore::CAS::FS::DirEnt->new({  | 
| 
87
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 				type => 'dir',  | 
| 
88
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 				name => '',  | 
| 
89
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 				# Assume scalars are digest_hash values.  | 
| 
90
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 				!ref $root? ( ref => $root )  | 
| 
91
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 					# Hashrefs might be empty, to indicate an empty directory  | 
| 
92
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 					: ref $root eq 'HASH'? ( ref => $self->hash_of_empty_dir, %$root )  | 
| 
93
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 					# Is it a ::File or ::Dir object?  | 
| 
94
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 					: ref($root)->can('hash')? ( ref => $root->hash )  | 
| 
95
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 					# Else take a guess that it is a digest_hash wrapped in an object  | 
| 
96
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 					: ( ref => "$root" )  | 
| 
97
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			})  | 
| 
98
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		);  | 
| 
99
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
100
 | 
7
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
210
 | 
 	croak "Invalid parameter 'root_entry'"  | 
| 
 
 | 
 
 | 
 
 | 
  
 33
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
 
 | 
  
 33
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
101
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		unless ref $self->root_entry  | 
| 
102
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			and ref($self->root_entry)->can('type')  | 
| 
103
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			and $self->root_entry->type eq 'dir'  | 
| 
104
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			and defined $self->root_entry->ref;  | 
| 
105
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# If they gave us a 'root_entry', make sure we can load it  | 
| 
106
 | 
7
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
158
 | 
 	$self->get_dir($self->root_entry->ref)  | 
| 
107
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		or croak "Unable to load root directory '".$self->root_entry->ref."'";  | 
| 
108
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
109
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
110
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
111
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub get {  | 
| 
112
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
  
1
  
 | 
10
 | 
 	(shift)->store->get(@_);  | 
| 
113
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
114
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
115
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
116
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub get_dir {  | 
| 
117
 | 
124
 | 
 
 | 
 
 | 
  
124
  
 | 
  
1
  
 | 
511
 | 
 	my ($self, $hash_or_file, $flags)= @_;  | 
| 
118
 | 
124
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
362
 | 
 	my ($hash, $file)= (ref $hash_or_file and $hash_or_file->can('hash'))  | 
| 
119
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		? ( $hash_or_file->hash, $hash_or_file )  | 
| 
120
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		: ( $hash_or_file, undef );  | 
| 
121
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	  | 
| 
122
 | 
124
 | 
 
 | 
 
 | 
 
 | 
 
 | 
254
 | 
 	my $dir= $self->dir_cache->get($hash);  | 
| 
123
 | 
124
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
360
 | 
 	return $dir if defined $dir;  | 
| 
124
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	  | 
| 
125
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# Return undef if the directory doesn't exist.  | 
| 
126
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	return undef  | 
| 
127
 | 
48
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
174
 | 
 		unless defined ($file ||= $self->store->get($hash));  | 
| 
128
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	  | 
| 
129
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# Deserialize directory.  This can throw exceptions if it isn't a valid encoding.  | 
| 
130
 | 
48
 | 
 
 | 
 
 | 
 
 | 
 
 | 
619
 | 
 	$dir= DataStore::CAS::FS::DirCodec->load($file);  | 
| 
131
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# Cache it  | 
| 
132
 | 
48
 | 
 
 | 
 
 | 
 
 | 
 
 | 
204
 | 
 	$self->dir_cache->put($dir);  | 
| 
133
 | 
48
 | 
 
 | 
 
 | 
 
 | 
 
 | 
388
 | 
 	return $dir;  | 
| 
134
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
135
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
136
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
137
 | 
  
0
  
 | 
 
 | 
 
 | 
  
0
  
 | 
  
1
  
 | 
0
 | 
 sub put        { (shift)->store->put(@_) }  | 
| 
138
 | 
  
0
  
 | 
 
 | 
 
 | 
  
0
  
 | 
  
1
  
 | 
0
 | 
 sub put_scalar { (shift)->store->put_scalar(@_) }  | 
| 
139
 | 
  
0
  
 | 
 
 | 
 
 | 
  
0
  
 | 
  
1
  
 | 
0
 | 
 sub put_file   { (shift)->store->put_file(@_) }  | 
| 
140
 | 
  
0
  
 | 
 
 | 
 
 | 
  
0
  
 | 
  
1
  
 | 
0
 | 
 sub put_handle { (shift)->store->put_handle(@_) }  | 
| 
141
 | 
  
0
  
 | 
 
 | 
 
 | 
  
0
  
 | 
  
1
  
 | 
0
 | 
 sub validate   { (shift)->store->validate(@_) }  | 
| 
142
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
143
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
144
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub path {  | 
| 
145
 | 
10
 | 
 
 | 
 
 | 
  
10
  
 | 
  
1
  
 | 
2007
 | 
 	bless { filesystem => (shift), path_names => [ map { File::Spec->splitdir($_) } @_ ] },  | 
| 
 
 | 
18
 | 
 
 | 
 
 | 
 
 | 
 
 | 
119
 | 
    | 
| 
146
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		'DataStore::CAS::FS::Path';  | 
| 
147
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
148
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
149
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
150
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub path_if_exists {  | 
| 
151
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
  
1
  
 | 
625
 | 
 	my $self= shift;  | 
| 
152
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
 	my $path= $self->path(@_);  | 
| 
153
 | 
2
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
7
 | 
 	$path->resolve({no_die => 1})? $path : undef;  | 
| 
154
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
155
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
156
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
157
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub tree_iterator {  | 
| 
158
 | 
3
 | 
 
 | 
 
 | 
  
3
  
 | 
  
1
  
 | 
1112
 | 
 	my $self= shift;  | 
| 
159
 | 
3
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
15
 | 
 	my %p= (@_ == 1 && ref $_[0] eq 'HASH')? %{$_[0]} : @_;  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
160
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
19
 | 
 	return DataStore::CAS::FS::TreeIterator->new(  | 
| 
161
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		path => [],  | 
| 
162
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		%p,  | 
| 
163
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		fs => $self  | 
| 
164
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	);  | 
| 
165
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
166
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
167
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
168
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
169
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub resolve_path {  | 
| 
170
 | 
21
 | 
 
 | 
 
 | 
  
21
  
 | 
  
1
  
 | 
368
 | 
 	my ($self, $path, $flags)= @_;  | 
| 
171
 | 
21
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
74
 | 
 	$flags ||= {};  | 
| 
172
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	  | 
| 
173
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
67
 | 
 	my $ret= $self->_resolve_path(undef, $path, { follow_symlinks => 1, %$flags });  | 
| 
174
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	  | 
| 
175
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# Array means success, scalar means error.  | 
| 
176
 | 
21
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
50
 | 
 	if (ref($ret) eq 'ARRAY') {  | 
| 
177
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		# The user wants directory entries, not "nodes".  | 
| 
178
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
77
 | 
 		$_= $_->{dirent} for @$ret;  | 
| 
179
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
384
 | 
 		return $ret;  | 
| 
180
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
181
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
182
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# else, got an error...  | 
| 
183
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	${$flags->{error_out}}= $ret  | 
| 
184
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		if ref $flags->{error_out};  | 
| 
185
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	croak $ret unless $flags->{no_die};  | 
| 
186
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	return undef;  | 
| 
187
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
188
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
189
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub _resolve_path {  | 
| 
190
 | 
241
 | 
 
 | 
 
 | 
  
241
  
 | 
 
 | 
280
 | 
 	my ($self, $nodes, $path_names, $flags)= @_;  | 
| 
191
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
192
 | 
241
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
779
 | 
 	my @path= ref($path_names)? @$path_names : File::Spec->splitdir($path_names);  | 
| 
193
 | 
241
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
407
 | 
 	$nodes ||= [];  | 
| 
194
 | 
241
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
542
 | 
 	push @$nodes, ($self->{_nodes} ||= { dirent => $self->root_entry })  | 
| 
195
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		unless @$nodes;  | 
| 
196
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	  | 
| 
197
 | 
241
 | 
 
 | 
 
 | 
 
 | 
 
 | 
164
 | 
 	my $mkdir_defaults;  | 
| 
198
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	sub _build_mkdir_defaults {  | 
| 
199
 | 
3
 | 
 
 | 
 
 | 
  
3
  
 | 
 
 | 
3
 | 
 		my $flags= shift;  | 
| 
200
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		my @ret= %{$flags->{mkdir_defaults}}  | 
| 
201
 | 
3
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
7
 | 
 			if defined $flags->{mkdir_defaults};  | 
| 
202
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
 		push @ret, type => 'dir', ref => undef;  | 
| 
203
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		\@ret  | 
| 
204
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
16
 | 
 	}  | 
| 
205
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
206
 | 
241
 | 
 
 | 
 
 | 
 
 | 
 
 | 
342
 | 
 	while (@path) {  | 
| 
207
 | 
761
 | 
 
 | 
 
 | 
 
 | 
 
 | 
765
 | 
 		my $ent= $nodes->[-1]{dirent};  | 
| 
208
 | 
761
 | 
 
 | 
 
 | 
 
 | 
 
 | 
488
 | 
 		my $dir;  | 
| 
209
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
210
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		# Support for "symlink" is always UNIX-based (or compatible)  | 
| 
211
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		# As support for other systems' symbolic paths are added, they  | 
| 
212
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		# will be given unique '->type' values, and appropriate handling.  | 
| 
213
 | 
761
 | 
  
 50
  
 | 
  
 66
  
 | 
 
 | 
 
 | 
14636
 | 
 		if ($ent->type eq 'symlink' and $flags->{follow_symlinks}) {  | 
| 
214
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			# Sanity check on symlink entry  | 
| 
215
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
72
 | 
 			my $target= $ent->ref;  | 
| 
216
 | 
4
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
24
 | 
 			defined $target and length $target  | 
| 
217
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 				or return 'Invalid symbolic link "'.$ent->name.'"';  | 
| 
218
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
219
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
15
 | 
 			unshift @path, split('/', $target, -1);  | 
| 
220
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8
 | 
 			pop @$nodes;  | 
| 
221
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			  | 
| 
222
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			# If an absolute link, we start over from the root  | 
| 
223
 | 
4
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
10
 | 
 			@$nodes= ( $nodes->[0] )  | 
| 
224
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 				if $path[0] eq '';  | 
| 
225
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
226
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
11
 | 
 			next;  | 
| 
227
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		}  | 
| 
228
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
229
 | 
757
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
13611
 | 
 		if ($ent->type ne 'dir') {  | 
| 
230
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			return 'Cannot descend into directory entry "'.$ent->name.'" of type "'.$ent->type.'"'  | 
| 
231
 | 
  
0
  
 | 
  
  0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
0
 | 
 				unless ($flags->{mkdir}||0) > 1;  | 
| 
232
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			# Here, mkdir flag converts entry into a directory  | 
| 
233
 | 
  
0
  
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
0
 | 
 			$nodes->[-1]{dirent}= $ent->clone(@{ $mkdir_defaults ||= _build_mkdir_defaults($flags)});  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
234
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		}  | 
| 
235
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
236
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		# Get the next path component, ignoring empty and '.'  | 
| 
237
 | 
757
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1101
 | 
 		my $name= shift @path;  | 
| 
238
 | 
757
 | 
  
100
  
 | 
  
 66
  
 | 
 
 | 
 
 | 
4502
 | 
 		next unless defined $name and length $name and ($name ne '.');  | 
| 
 
 | 
 
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
239
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
240
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		# We handle '..' procedurally, moving up one real directory and *not* backing out of a symlink.  | 
| 
241
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		# This is the same way the kernel does it, but perhaps shell behavior is preferred...  | 
| 
242
 | 
638
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
953
 | 
 		if ($name eq '..') {  | 
| 
243
 | 
9
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
17
 | 
 			return "Cannot access '..' at root directory"  | 
| 
244
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 				unless @$nodes > 1;  | 
| 
245
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10
 | 
 			pop @$nodes;  | 
| 
246
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
23
 | 
 			next;  | 
| 
247
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		}  | 
| 
248
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
249
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		# If this directory has an in-memory override for this name, use it  | 
| 
250
 | 
629
 | 
 
 | 
 
 | 
 
 | 
 
 | 
453
 | 
 		my $subnode;  | 
| 
251
 | 
629
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
968
 | 
 		if ($nodes->[-1]{subtree}) {  | 
| 
252
 | 
516
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
971
 | 
 			my $key= $self->case_insensitive? uc $name : $name;  | 
| 
253
 | 
516
 | 
 
 | 
 
 | 
 
 | 
 
 | 
696
 | 
 			$subnode= $nodes->[-1]{subtree}{$key};  | 
| 
254
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		}  | 
| 
255
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
256
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		# Else we need to find the name within the current directory  | 
| 
257
 | 
629
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
2578
 | 
 		if (!defined $subnode && (defined $nodes->[-1]{dir} || defined $ent->ref)) {  | 
| 
 
 | 
 
 | 
 
 | 
  
 66
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
258
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			# load it if it isn't cached  | 
| 
259
 | 
196
 | 
  
 50
  
 | 
  
 66
  
 | 
 
 | 
 
 | 
1591
 | 
 			($nodes->[-1]{dir} ||= $self->get_dir($ent->ref))  | 
| 
260
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 				or return 'Failed to open directory "'.$ent->name.' ('.$ent->ref.')"';  | 
| 
261
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
262
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			# See if the directory contains this entry  | 
| 
263
 | 
196
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
416
 | 
 			if (defined (my $subent= $nodes->[-1]{dir}->get_entry($name))) {  | 
| 
264
 | 
190
 | 
 
 | 
 
 | 
 
 | 
 
 | 
244
 | 
 				$subnode= { dirent => $subent };  | 
| 
265
 | 
190
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
347
 | 
 				my $key= $self->case_insensitive? uc $name : $name;  | 
| 
266
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 				# Weak reference, until _apply_overrides is called.  | 
| 
267
 | 
190
 | 
 
 | 
 
 | 
 
 | 
 
 | 
559
 | 
 				Scalar::Util::weaken( $nodes->[-1]{subtree}{$key}= $subnode );  | 
| 
268
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			}  | 
| 
269
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		}  | 
| 
270
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
271
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		# If we haven't found one, or if it is 0 (deleted), either create or die.  | 
| 
272
 | 
629
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
867
 | 
 		if (!$subnode) {  | 
| 
273
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			# If we're supposed to create virtual entries, do so  | 
| 
274
 | 
15
 | 
  
100
  
 | 
  
 66
  
 | 
 
 | 
 
 | 
41
 | 
 			if ($flags->{mkdir} or $flags->{partial}) {  | 
| 
275
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 				$subnode= {  | 
| 
276
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 					invalid => 1, # not valid until _apply_overrides  | 
| 
277
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 					dirent => DataStore::CAS::FS::DirEnt->new(  | 
| 
278
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 						name => $name,  | 
| 
279
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 						# It is a directory if there are more path components to resolve.  | 
| 
280
 | 
12
 | 
  
100
  
 | 
  
 66
  
 | 
 
 | 
 
 | 
31
 | 
 						(@path? @{ $mkdir_defaults ||= _build_mkdir_defaults($flags)} : ())  | 
| 
 
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
14
 | 
    | 
| 
281
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 					)  | 
| 
282
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 				};  | 
| 
283
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			}  | 
| 
284
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			# Else it doesn't exist and we fail.  | 
| 
285
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			else {  | 
| 
286
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
 				my $dir_path= File::Spec->catdir(map { $_->{dirent}->name } @$nodes);  | 
| 
 
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
78
 | 
    | 
| 
287
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 				return "Directory \"$dir_path\" is not present in storage"  | 
| 
288
 | 
3
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
10
 | 
 					unless defined $nodes->[-1]{dir};  | 
| 
289
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
13
 | 
 				return "No such directory entry \"$name\" at \"$dir_path\"";  | 
| 
290
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			}  | 
| 
291
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		}  | 
| 
292
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
293
 | 
626
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1456
 | 
 		push @$nodes, $subnode;  | 
| 
294
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
295
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	  | 
| 
296
 | 
238
 | 
 
 | 
 
 | 
 
 | 
 
 | 
356
 | 
 	$nodes;  | 
| 
297
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
298
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
299
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
300
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub get_dir_entries {  | 
| 
301
 | 
10
 | 
 
 | 
 
 | 
  
10
  
 | 
  
1
  
 | 
11
 | 
 	my ($self, $path)= @_;  | 
| 
302
 | 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
33
 | 
 	my $nodes= $self->_resolve_path(undef, $path);  | 
| 
303
 | 
10
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
22
 | 
 	ref $nodes  | 
| 
304
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		or croak $nodes;  | 
| 
305
 | 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
20
 | 
 	return $self->_get_dir_entries($nodes->[-1]);  | 
| 
306
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
307
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
308
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub readdir {  | 
| 
309
 | 
10
 | 
 
 | 
 
 | 
  
10
  
 | 
  
1
  
 | 
352
 | 
 	my $self= shift;  | 
| 
310
 | 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
11
 | 
 	my @names= map { $_->name } @{ $self->get_dir_entries(@_) };  | 
| 
 
 | 
17
 | 
 
 | 
 
 | 
 
 | 
 
 | 
382
 | 
    | 
| 
 
 | 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
20
 | 
    | 
| 
311
 | 
10
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
67
 | 
 	return wantarray? @names : \@names;  | 
| 
312
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
313
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
314
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # This method combines the original directory with its overrides.  | 
| 
315
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub _get_dir_entries {  | 
| 
316
 | 
52
 | 
 
 | 
 
 | 
  
52
  
 | 
 
 | 
49
 | 
 	my ($self, $node)= @_;  | 
| 
317
 | 
52
 | 
 
 | 
 
 | 
 
 | 
 
 | 
55
 | 
 	my $ent= $node->{dirent};  | 
| 
318
 | 
52
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
936
 | 
 	croak "Can't get listing for non-directory"  | 
| 
319
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		unless $ent->type eq 'dir';  | 
| 
320
 | 
52
 | 
 
 | 
 
 | 
 
 | 
 
 | 
59
 | 
 	my %dirents;  | 
| 
321
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# load dir if it isn't cached  | 
| 
322
 | 
52
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
917
 | 
 	if (!defined $node->{dir} && defined $ent->ref) {  | 
| 
323
 | 
45
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
782
 | 
 		defined ( $node->{dir}= $self->get_dir($ent->ref) )  | 
| 
324
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			or return 'Failed to open directory "'.$ent->name.' ('.$ent->ref.')"';  | 
| 
325
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
326
 | 
52
 | 
 
 | 
 
 | 
 
 | 
 
 | 
93
 | 
 	my $caseless= $self->case_insensitive;  | 
| 
327
 | 
52
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
88
 | 
 	if (defined $node->{dir}) {  | 
| 
328
 | 
47
 | 
 
 | 
 
 | 
 
 | 
 
 | 
102
 | 
 		my $iter= $node->{dir}->iterator;  | 
| 
329
 | 
47
 | 
 
 | 
 
 | 
 
 | 
 
 | 
46
 | 
 		my $dirent;  | 
| 
330
 | 
47
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
68
 | 
 		$dirents{$caseless? uc($dirent->name) : $dirent->name}= $dirent  | 
| 
331
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			while defined ($dirent= $iter->());  | 
| 
332
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
333
 | 
52
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
93
 | 
 	if (my $t= $node->{subtree}) {  | 
| 
334
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
15
 | 
 		for (keys %$t) {  | 
| 
335
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
 			my $subnode= $t->{$_};  | 
| 
336
 | 
8
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
14
 | 
 			next unless defined $subnode;  | 
| 
337
 | 
8
 | 
  
 50
  
 | 
  
 66
  
 | 
 
 | 
 
 | 
23
 | 
 			die "BUG" if ref $subnode && $subnode->{invalid};  | 
| 
338
 | 
8
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
20
 | 
 			if (ref $subnode) {  | 
| 
339
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 				$dirents{$_}= $subnode->{dirent}  | 
| 
340
 | 
7
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
17
 | 
 					if $subnode->{changed};  | 
| 
341
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			} else {  | 
| 
342
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
 				delete $dirents{$_};  | 
| 
343
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			}  | 
| 
344
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		}  | 
| 
345
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
346
 | 
52
 | 
 
 | 
 
 | 
 
 | 
 
 | 
158
 | 
 	return [ map { $dirents{$_} } sort keys %dirents ];  | 
| 
 
 | 
109
 | 
 
 | 
 
 | 
 
 | 
 
 | 
230
 | 
    | 
| 
347
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
348
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
349
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
350
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub set_path {  | 
| 
351
 | 
4
 | 
 
 | 
 
 | 
  
4
  
 | 
  
1
  
 | 
109
 | 
 	my ($self, $path, $newent, $flags)= @_;  | 
| 
352
 | 
4
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
22
 | 
 	$flags ||= {};  | 
| 
353
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
21
 | 
 	my $nodes= $self->_resolve_path(undef, $path, { follow_symlinks => 1, partial => 1, %$flags });  | 
| 
354
 | 
4
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
13
 | 
 	croak $nodes unless ref $nodes;  | 
| 
355
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# replace the final entry, after applying defaults  | 
| 
356
 | 
4
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
9
 | 
 	if (!$newent) {  | 
| 
357
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		# unlink request.  Ignore if node didn't exist.  | 
| 
358
 | 
1
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
3
 | 
 		return if $nodes->[-1]{invalid};  | 
| 
359
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
360
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		# Can't unlink the root node  | 
| 
361
 | 
1
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
4
 | 
 		croak "Can't unlink root node"  | 
| 
362
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			unless @$nodes > 1;  | 
| 
363
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
364
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
 		$nodes->[-1]{invalid}= 1;  | 
| 
365
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		# Recursively invalidate all nodes beneath this one  | 
| 
366
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
 		&_invalidate_subtree for ($nodes->[-1]);  | 
| 
367
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
368
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		# Mark in prev node that this item is gone  | 
| 
369
 | 
1
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
24
 | 
 		my $key= $self->case_insensitive? uc $nodes->[-1]{dirent}->name : $nodes->[-1]{dirent}->name;  | 
| 
370
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
 		pop @$nodes;  | 
| 
371
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
 		$nodes->[-1]{subtree}{$key}= 0;  | 
| 
372
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	} else {  | 
| 
373
 | 
3
 | 
  
  0
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
11
 | 
 		if (ref $newent eq 'HASH' or !defined $newent->name or !defined $newent->type) {  | 
| 
 
 | 
 
 | 
 
 | 
  
 33
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
374
 | 
3
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
3
 | 
 			my %ent_hash= %{ref $newent eq 'HASH'? $newent : $newent->as_hash};  | 
| 
 
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
17
 | 
    | 
| 
375
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			$ent_hash{name}= $nodes->[-1]{dirent}->name  | 
| 
376
 | 
3
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
64
 | 
 				unless defined $ent_hash{name};  | 
| 
377
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			defined $ent_hash{name} && length $ent_hash{name}  | 
| 
378
 | 
3
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
15
 | 
 				or die "No name for new dir entry";  | 
| 
379
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			$ent_hash{type}= $nodes->[-1]{dirent}->type || 'file'  | 
| 
380
 | 
3
 | 
  
100
  
 | 
  
 50
  
 | 
 
 | 
 
 | 
44
 | 
 				unless defined $ent_hash{type};  | 
| 
381
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10
 | 
 			$newent= DataStore::CAS::FS::DirEnt->new(\%ent_hash);  | 
| 
382
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		}  | 
| 
383
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
 		$nodes->[-1]{dirent}= $newent;  | 
| 
384
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
9
 | 
 		delete $nodes->[-1]{dir};  | 
| 
385
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		# Recursively invalidate all nodes beneath this one  | 
| 
386
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
9
 | 
 		&_invalidate_subtree for ($nodes->[-1]);  | 
| 
387
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
388
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# Now connect nodes with strong references, and mark as changed  | 
| 
389
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
13
 | 
 	$self->_apply_overrides($nodes);  | 
| 
390
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
391
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub _invalidate_subtree {  | 
| 
392
 | 
23
 | 
  
100
  
 | 
 
 | 
  
23
  
 | 
 
 | 
47
 | 
 	if ($_->{subtree}) {  | 
| 
393
 | 
10
 | 
 
 | 
  
 33
  
 | 
 
 | 
 
 | 
8
 | 
 		++$_->{invalid} && &_invalidate_subtree for grep { ref $_ } values %{delete $_->{subtree}};  | 
| 
 
 | 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
34
 | 
    | 
| 
 
 | 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
15
 | 
    | 
| 
394
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
395
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
396
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
397
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
398
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub update_path {  | 
| 
399
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
  
1
  
 | 
313
 | 
 	my ($self, $path, $changes, $flags)= @_;  | 
| 
400
 | 
2
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
11
 | 
 	$flags ||= {};  | 
| 
401
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
9
 | 
 	my $nodes= $self->_resolve_path(undef, $path, { follow_symlinks => 1, partial => 1, %$flags });  | 
| 
402
 | 
2
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
7
 | 
 	croak $nodes unless ref $nodes;  | 
| 
403
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
404
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# update the final entry, after applying defaults  | 
| 
405
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
 	my $entref= \$nodes->[-1]{dirent};  | 
| 
406
 | 
2
 | 
  
100
  
 | 
  
 66
  
 | 
 
 | 
 
 | 
39
 | 
 	my $old_dir_ref= defined $$entref->type && $$entref->type eq 'dir'? $$entref->ref : undef;  | 
| 
407
 | 
2
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
37
 | 
 	$$entref= $$entref->clone(  | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
408
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		(defined $$entref->type? () : ( type => 'file' )),  | 
| 
409
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		ref $changes eq 'HASH'? %$changes  | 
| 
410
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			: ref $changes eq 'ARRAY'? @$changes  | 
| 
411
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			: croak 'parameter "changes" must be a hashref or arrayref'  | 
| 
412
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	);  | 
| 
413
 | 
2
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
40
 | 
 	my $new_dir_ref= $$entref->type eq 'dir'? $$entref->ref : undef;  | 
| 
414
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
415
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# If we changed the type of a directory, or changed which digest_hash it  | 
| 
416
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# refers to, then we should clear the subtree under this node.  | 
| 
417
 | 
2
 | 
  
 50
  
 | 
  
100
  
 | 
 
 | 
 
 | 
18
 | 
 	if (($old_dir_ref || '') ne ($new_dir_ref || '') && $nodes->[-1]{subtree}) {  | 
| 
 
 | 
 
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
 
 | 
  
 66
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
418
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		# Recursively invalidate all nodes beneath this one  | 
| 
419
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		&_invalidate_subtree for ($nodes->[-1]);  | 
| 
420
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		delete $nodes->[-1]{dir};  | 
| 
421
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
422
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
423
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
19
 | 
 	$self->_apply_overrides($nodes);  | 
| 
424
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
425
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
426
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub _apply_overrides {  | 
| 
427
 | 
9
 | 
 
 | 
 
 | 
  
9
  
 | 
 
 | 
12
 | 
 	my ($self, $nodes)= @_;  | 
| 
428
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# Ensure that each node is connected to the previous via 'subtree'.  | 
| 
429
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# When we find the first changed node, we assume the rest are connected.  | 
| 
430
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
 	my $prev;  | 
| 
431
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
14
 | 
 	for (reverse @$nodes) {  | 
| 
432
 | 
25
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
35
 | 
 		if ($prev) {  | 
| 
433
 | 
16
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
312
 | 
 			my $key= $self->case_insensitive? uc($prev->{dirent}->name) : $prev->{dirent}->name;  | 
| 
434
 | 
16
 | 
 
 | 
 
 | 
 
 | 
 
 | 
32
 | 
 			$_->{subtree}{$key}= $prev;  | 
| 
435
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		}  | 
| 
436
 | 
25
 | 
  
100
  
 | 
  
 66
  
 | 
 
 | 
 
 | 
61
 | 
 		last if $_->{changed} && !$_->{invalid};  | 
| 
437
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
22
 | 
 		delete $_->{invalid};  | 
| 
438
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
18
 | 
 		$_->{changed}= 1;  | 
| 
439
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
21
 | 
 		$prev= $_;  | 
| 
440
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
441
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# Finally, make sure the root override is set  | 
| 
442
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
13
 | 
 	$self->{_nodes}= $nodes->[0];  | 
| 
443
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
23
 | 
 	1;  | 
| 
444
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
445
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
446
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
447
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub mkdir {  | 
| 
448
 | 
4
 | 
 
 | 
 
 | 
  
4
  
 | 
  
1
  
 | 
414
 | 
 	my ($self, $path)= @_;  | 
| 
449
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
13
 | 
 	my $nodes= $self->_resolve_path(undef, $path, { follow_symlinks => 1, mkdir => 1 });  | 
| 
450
 | 
4
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
12
 | 
 	croak $nodes unless ref $nodes;  | 
| 
451
 | 
4
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
72
 | 
 	unless (defined $nodes->[-1]{dirent}->type) {  | 
| 
452
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8
 | 
 		$nodes->[-1]{dirent}= $nodes->[-1]{dirent}->clone(type => 'dir');  | 
| 
453
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
11
 | 
 		$self->_apply_overrides($nodes);  | 
| 
454
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
455
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8
 | 
 	1;  | 
| 
456
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
457
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
458
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
459
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub touch {  | 
| 
460
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
  
1
  
 | 
440
 | 
 	my ($self, $path)= @_;  | 
| 
461
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
 	$self->update_path($path, { mtime => time() });  | 
| 
462
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
463
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
464
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
465
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub unlink {  | 
| 
466
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
  
1
  
 | 
2
 | 
 	my ($self, $path)= @_;  | 
| 
467
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
 	$self->set_path($path, undef);  | 
| 
468
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
469
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 *rmdir = *unlink;  | 
| 
470
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
471
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # TODO: write copy and move and rename  | 
| 
472
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
473
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
474
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub rollback {  | 
| 
475
 | 
  
0
  
 | 
 
 | 
 
 | 
  
0
  
 | 
  
1
  
 | 
0
 | 
 	my $self= shift;  | 
| 
476
 | 
  
0
  
 | 
  
  0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
0
 | 
 	if ($self->{_nodes} && $self->{_nodes}{changed}) {  | 
| 
477
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		&invalidate_node for ($self->{_nodes});  | 
| 
478
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		$self->{_nodes}= undef;  | 
| 
479
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
480
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	1;  | 
| 
481
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
482
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
483
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
484
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub commit {  | 
| 
485
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
  
1
  
 | 
4
 | 
 	my $self= shift;  | 
| 
486
 | 
2
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
21
 | 
 	if ($self->_nodes && $self->_nodes->{changed}) {  | 
| 
487
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
 		my $root_node= $self->_nodes;  | 
| 
488
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		croak "Root override must be a directory"  | 
| 
489
 | 
2
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
51
 | 
 			unless $root_node->{dirent}->type eq 'dir';  | 
| 
490
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
 		my $hash= $self->_commit_recursive($root_node);  | 
| 
491
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
81
 | 
 		$self->{root_entry}= $root_node->{dirent}->clone(ref => $hash);  | 
| 
492
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
 		$self->{_nodes}= undef;  | 
| 
493
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
494
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8
 | 
 	1;  | 
| 
495
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
496
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
497
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Takes a subtree of the datastructure generated by apply_path and encodes it  | 
| 
498
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # as a directory, recursively encoding any subtrees first, then returns the  | 
| 
499
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # hash of that subdir.  | 
| 
500
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub _commit_recursive {  | 
| 
501
 | 
10
 | 
 
 | 
 
 | 
  
10
  
 | 
 
 | 
9
 | 
 	my ($self, $node)= @_;  | 
| 
502
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
503
 | 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10
 | 
 	my %changes;  | 
| 
504
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	my @entries;  | 
| 
505
 | 
10
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
16
 | 
 	if (my $subtree= $node->{subtree}) {  | 
| 
506
 | 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8
 | 
 		while (my ($k, $v)= each %{$node->{subtree}}) {  | 
| 
 
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
67
 | 
    | 
| 
507
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			$changes{$k}= $v  | 
| 
508
 | 
11
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
56
 | 
 				if defined $v && ($v eq 0 || $v->{changed});  | 
| 
 
 | 
 
 | 
 
 | 
  
 66
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
509
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		}  | 
| 
510
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
511
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	  | 
| 
512
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# If no changes, return original directory (if it exists)  | 
| 
513
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	return $node->{dirent}->ref  | 
| 
514
 | 
10
 | 
  
100
  
 | 
  
 66
  
 | 
 
 | 
 
 | 
37
 | 
 		if !%changes && defined $node->{dirent}->ref;  | 
| 
515
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	  | 
| 
516
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# Walk the directory entries and filter out any that have been overridden.  | 
| 
517
 | 
9
 | 
  
100
  
 | 
  
 66
  
 | 
 
 | 
 
 | 
105
 | 
 	if (defined $node->{dir} || defined $node->{dirent}->ref) {  | 
| 
518
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		($node->{dir} ||= $self->get_dir($node->{dirent}->ref))  | 
| 
519
 | 
4
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
11
 | 
 			or croak 'Failed to open directory "'.$node->{dirent}->name.' ('.$node->{dirent}->ref.')"';  | 
| 
520
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		  | 
| 
521
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
 		my ($iter, $ent);  | 
| 
522
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
 		my $caseless= $self->case_insensitive;  | 
| 
523
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8
 | 
 		for ($iter= $node->{dir}->iterator; defined ($ent= $iter->()); ) {  | 
| 
524
 | 
12
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
221
 | 
 			push @entries, $ent unless $changes{$caseless? uc($ent->name) : $ent->name};  | 
| 
 
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
525
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		}  | 
| 
526
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
527
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
528
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# Now append the modified entries.  | 
| 
529
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# Skip the "0"s, which represent files to unlink.  | 
| 
530
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
12
 | 
 	for (grep { ref $_ } values %changes) {  | 
| 
 
 | 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
18
 | 
    | 
| 
531
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		# Check if node is a dir and needs committed  | 
| 
532
 | 
10
 | 
  
 50
  
 | 
  
 66
  
 | 
 
 | 
 
 | 
167
 | 
 		if ($_->{subtree} and $_->{dirent}->type eq 'dir' and $_->{changed}) {  | 
| 
 
 | 
 
 | 
 
 | 
  
 66
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
533
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
32
 | 
 			my $hash= $self->_commit_recursive($_);  | 
| 
534
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3387
 | 
 			$_->{dirent}= $_->{dirent}->clone( ref => $hash );  | 
| 
535
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		}  | 
| 
536
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		  | 
| 
537
 | 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
22
 | 
 		push @entries, $_->{dirent};  | 
| 
538
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
539
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
540
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# Invalidate all children of this node  | 
| 
541
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
17
 | 
 	&_invalidate_subtree for ($node);  | 
| 
542
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	  | 
| 
543
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# Now re-encode the directory, using the same type as orig_dir  | 
| 
544
 | 
9
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
15
 | 
 	return $self->hash_of_empty_dir  | 
| 
545
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		unless @entries;  | 
| 
546
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	my $format= $node->{dir}->format  | 
| 
547
 | 
9
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
19
 | 
 		if $node->{dir};  | 
| 
548
 | 
9
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
19
 | 
 	$format= 'universal' unless defined $format;  | 
| 
549
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
35
 | 
 	return DataStore::CAS::FS::DirCodec->put($self->store, $format, \@entries, {});  | 
| 
550
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
551
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
552
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 package DataStore::CAS::FS::Path;  | 
| 
553
 | 
4
 | 
 
 | 
 
 | 
  
4
  
 | 
 
 | 
22
 | 
 use strict;  | 
| 
 
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
    | 
| 
 
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
78
 | 
    | 
| 
554
 | 
4
 | 
 
 | 
 
 | 
  
4
  
 | 
 
 | 
13
 | 
 use warnings;  | 
| 
 
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
    | 
| 
 
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3140
 | 
    | 
| 
555
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
556
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
557
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # main attributes  | 
| 
558
 | 
5
 | 
 
 | 
 
 | 
  
5
  
 | 
 
 | 
15
 | 
 sub path_names       { $_[0]{path_names} }  | 
| 
559
 | 
7
 | 
 
 | 
 
 | 
  
7
  
 | 
 
 | 
24
 | 
 sub filesystem       { $_[0]{filesystem} }  | 
| 
560
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 #sub _node_path       { $_[0]{_node_path} }  | 
| 
561
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
562
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # convenience accessors  | 
| 
563
 | 
  
0
  
 | 
 
 | 
 
 | 
  
0
  
 | 
 
 | 
0
 | 
 sub path_name_list   { @{$_[0]->path_names} }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
564
 | 
13
 | 
 
 | 
 
 | 
  
13
  
 | 
 
 | 
11
 | 
 sub path_dirent_list { map { $_->{dirent} } @{$_[0]->resolve} }  | 
| 
 
 | 
67
 | 
 
 | 
 
 | 
 
 | 
 
 | 
76
 | 
    | 
| 
 
 | 
13
 | 
 
 | 
 
 | 
 
 | 
 
 | 
14
 | 
    | 
| 
565
 | 
13
 | 
 
 | 
 
 | 
  
13
  
 | 
 
 | 
44
 | 
 sub path_dirents     { [ $_[0]->path_dirent_list ] }  | 
| 
566
 | 
5
 | 
 
 | 
 
 | 
  
5
  
 | 
 
 | 
12
 | 
 sub dirent           { $_[0]->resolve->[-1]{dirent} }  | 
| 
567
 | 
98
 | 
 
 | 
 
 | 
  
98
  
 | 
 
 | 
132
 | 
 sub type             { $_[0]->resolve->[-1]{dirent}->type }  | 
| 
568
 | 
  
0
  
 | 
 
 | 
 
 | 
  
0
  
 | 
 
 | 
0
 | 
 sub name             { $_[0]->resolve->[-1]{dirent}->name }  | 
| 
569
 | 
  
0
  
 | 
 
 | 
 
 | 
  
0
  
 | 
 
 | 
0
 | 
 sub depth            { -1 + @{$_[0]->resolve} }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
570
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
571
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
572
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub canonical_path {  | 
| 
573
 | 
  
0
  
 | 
 
 | 
 
 | 
  
0
  
 | 
 
 | 
0
 | 
 	my $self= shift;  | 
| 
574
 | 
  
0
  
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
0
 | 
 	$self->{canonical_path} ||= do {  | 
| 
575
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		my $name= $self->path_names;  | 
| 
576
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		my $path= '/'.join('/', grep { length && $_ ne '.' } @$name);  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
577
 | 
  
0
  
 | 
  
  0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
0
 | 
 		$path .= '/' if $name->[-1] eq '' || $name->[-1] eq '.';  | 
| 
578
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		$path =~ s|//+|/|g;  | 
| 
579
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		$path;  | 
| 
580
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	};  | 
| 
581
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
582
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
583
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
584
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub resolved_canonical_path {  | 
| 
585
 | 
92
 | 
 
 | 
 
 | 
  
92
  
 | 
 
 | 
273
 | 
 	my $x= $_[0]->resolve;  | 
| 
586
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# ignore name of root entry  | 
| 
587
 | 
92
 | 
 
 | 
 
 | 
 
 | 
 
 | 
204
 | 
 	return '/'.join('/', map { $_->{dirent}->name } @$x[1..$#$x]);  | 
| 
 
 | 
399
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7169
 | 
    | 
| 
588
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
589
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
590
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
591
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub resolve {  | 
| 
592
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# See if we can re-use the previous result...  | 
| 
593
 | 
214
 | 
 
 | 
 
 | 
  
214
  
 | 
 
 | 
228
 | 
 	my $nodes= $_[0]{_node_path};  | 
| 
594
 | 
214
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
914
 | 
 	return $nodes if $nodes && ref $nodes->[-1] && !$nodes->[-1]{invalid};  | 
| 
 
 | 
 
 | 
 
 | 
  
 66
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
595
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# Only re-resolve the nodes which have been invalidated.  | 
| 
596
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# This is part of an optimization to create half-resolved path objects.  | 
| 
597
 | 
103
 | 
 
 | 
 
 | 
 
 | 
 
 | 
75
 | 
 	my ($self, $flags)= @_;  | 
| 
598
 | 
103
 | 
 
 | 
 
 | 
 
 | 
 
 | 
78
 | 
 	my (@valid_nodes, $sub_path);  | 
| 
599
 | 
103
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
121
 | 
 	if ($nodes) {  | 
| 
600
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
 		for (@$nodes) {  | 
| 
601
 | 
4
 | 
  
100
  
 | 
  
 66
  
 | 
 
 | 
 
 | 
17
 | 
 			last if !ref $_ || $_->{invalid};  | 
| 
602
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
 			push @valid_nodes, $_;  | 
| 
603
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		}  | 
| 
604
 | 
2
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
5
 | 
 		$sub_path= [ map { ref $_? $_->{dirent}->name : $_ } @{$nodes}[ scalar(@valid_nodes) .. $#$nodes ] ];  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
13
 | 
    | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
    | 
| 
605
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	} else {  | 
| 
606
 | 
101
 | 
 
 | 
 
 | 
 
 | 
 
 | 
88
 | 
 		$sub_path= $self->{path_names};  | 
| 
607
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
608
 | 
103
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
172
 | 
 	$flags= { follow_symlinks => 1, $flags? %$flags : () };  | 
| 
609
 | 
103
 | 
 
 | 
 
 | 
 
 | 
 
 | 
191
 | 
 	$nodes= $self->{filesystem}->_resolve_path(\@valid_nodes, $sub_path, $flags);  | 
| 
610
 | 
103
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
173
 | 
 	if (ref $nodes) {  | 
| 
611
 | 
100
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2059
 | 
 		return ($self->{_node_path}= $nodes);  | 
| 
612
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	} else {  | 
| 
613
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		# else, got an error...  | 
| 
614
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		${$flags->{error_out}}= $nodes  | 
| 
615
 | 
3
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
8
 | 
 			if ref $flags->{error_out};  | 
| 
616
 | 
3
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
6
 | 
 		Carp::croak $nodes unless $flags->{no_die};  | 
| 
617
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
23
 | 
 		return undef;  | 
| 
618
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
619
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
620
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
621
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
622
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub path {  | 
| 
623
 | 
6
 | 
 
 | 
 
 | 
  
6
  
 | 
 
 | 
7
 | 
 	my $self= shift;  | 
| 
624
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
9
 | 
 	my @sub_names= map { File::Spec->splitdir($_) } @_;  | 
| 
 
 | 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
35
 | 
    | 
| 
625
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	bless {  | 
| 
626
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		filesystem => $self->{filesystem},  | 
| 
627
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
32
 | 
 		path_names => [ @{$self->{path_names}}, @sub_names ],  | 
| 
628
 | 
6
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
11
 | 
 		$self->{_node_path}? (_node_path => [ @{$self->{_node_path}}, @sub_names ]) : (),  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
19
 | 
    | 
| 
629
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}, ref $self;  | 
| 
630
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
631
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
632
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub path_if_exists {  | 
| 
633
 | 
3
 | 
 
 | 
 
 | 
  
3
  
 | 
 
 | 
17
 | 
 	my $self= shift;  | 
| 
634
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
 	my $path= $self->path(@_);  | 
| 
635
 | 
3
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
9
 | 
 	$path->resolve({no_die => 1})? $path : undef;  | 
| 
636
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
637
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
638
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
639
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub mkdir {  | 
| 
640
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
 
 | 
2
 | 
 	my $self= shift;  | 
| 
641
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
 	$self->{filesystem}->mkdir($self->path_names, @_);  | 
| 
642
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
 	$self;  | 
| 
643
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
644
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
645
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
646
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub file {  | 
| 
647
 | 
2
 | 
 
 | 
  
 33
  
 | 
  
2
  
 | 
 
 | 
8
 | 
 	$_[0]{file} ||= do {  | 
| 
648
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
 		my $ent= $_[0]->dirent;  | 
| 
649
 | 
2
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
39
 | 
 		$ent->type eq 'file' or Carp::croak "Path is not a file";  | 
| 
650
 | 
2
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
36
 | 
 		defined (my $hash= $ent->ref) or Carp::croak "File was not stored in CAS";  | 
| 
651
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
 		$_[0]->filesystem->get($hash);  | 
| 
652
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	};  | 
| 
653
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
654
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
655
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub open {  | 
| 
656
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
 
 | 
15
 | 
 	$_[0]->file->open  | 
| 
657
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
658
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
659
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
660
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub dir {  | 
| 
661
 | 
  
0
  
 | 
 
 | 
  
  0
  
 | 
  
0
  
 | 
 
 | 
0
 | 
 	$_[0]{dir} ||= do {  | 
| 
662
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		my $ent= $_[0]->dirent;  | 
| 
663
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		$ent->type eq 'dir' or Carp::croak "Path is not a directory";  | 
| 
664
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		defined (my $hash= $ent->ref) or Carp::croak "Directory was not stored in CAS";  | 
| 
665
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		$_[0]->filesystem->get_dir($hash);  | 
| 
666
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
667
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
668
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
669
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
670
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub readdir {  | 
| 
671
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
 
 | 
9
 | 
 	$_[0]{filesystem}->readdir($_[0]->path_names)  | 
| 
672
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
673
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
674
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
675
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub tree_iterator {  | 
| 
676
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
 
 | 
2
 | 
 	my $self= shift;  | 
| 
677
 | 
1
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
6
 | 
 	my %p= (@_ == 1 && ref $_[0] eq 'HASH')? %{$_[0]} : @_;  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
678
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
 	$self->filesystem->tree_iterator(%p, path => $self->path_names);  | 
| 
679
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
680
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
681
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 package DataStore::CAS::FS::TreeIterator;  | 
| 
682
 | 
4
 | 
 
 | 
 
 | 
  
4
  
 | 
 
 | 
18
 | 
 use strict;  | 
| 
 
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
21
 | 
    | 
| 
 
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
61
 | 
    | 
| 
683
 | 
4
 | 
 
 | 
 
 | 
  
4
  
 | 
 
 | 
12
 | 
 use warnings;  | 
| 
 
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
    | 
| 
 
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
76
 | 
    | 
| 
684
 | 
4
 | 
 
 | 
 
 | 
  
4
  
 | 
 
 | 
12
 | 
 use Carp;  | 
| 
 
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
    | 
| 
 
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1968
 | 
    | 
| 
685
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
686
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
687
 | 
  
0
  
 | 
 
 | 
 
 | 
  
0
  
 | 
 
 | 
0
 | 
 sub _fields { $_[0]->($_[0]) }  | 
| 
688
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
689
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub new {  | 
| 
690
 | 
3
 | 
 
 | 
 
 | 
  
3
  
 | 
 
 | 
6
 | 
 	my $class= shift;  | 
| 
691
 | 
3
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
14
 | 
 	my $self= bless { (@_ == 1 && ref $_[0] eq 'HASH')? %{$_[0]} : @_ }, $class;  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
692
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	defined $self->{$_} || croak "'$_' is required"  | 
| 
693
 | 
3
 | 
 
 | 
  
 33
  
 | 
 
 | 
 
 | 
23
 | 
 		for qw( path fs );  | 
| 
694
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
 	$self->{path_nodes}= \my @nodes;  | 
| 
695
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
 	$self->{dirstack}= \my @dirstack;  | 
| 
696
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
 	$self->{names}= \my @names;  | 
| 
697
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
 	$self->{filterref}= \my $filter;  | 
| 
698
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
 	$filter= delete $self->{filter};  | 
| 
699
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
 	my $fs= $self->{fs};  | 
| 
700
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
 	$self->_init;  | 
| 
701
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	return bless sub {  | 
| 
702
 | 
101
 | 
  
100
  
 | 
  
 66
  
 | 
  
101
  
 | 
 
 | 
430
 | 
 		return $self if @_ && ref($_[0]) eq $class;  | 
| 
703
 | 
97
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
163
 | 
 		return undef unless @dirstack;  | 
| 
704
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		# back out of a directory hierarchy that we have finished  | 
| 
705
 | 
97
 | 
 
 | 
 
 | 
 
 | 
 
 | 
76
 | 
 		while (!@{$dirstack[-1]}) {  | 
| 
 
 | 
147
 | 
 
 | 
 
 | 
 
 | 
 
 | 
229
 | 
    | 
| 
706
 | 
55
 | 
 
 | 
 
 | 
 
 | 
 
 | 
39
 | 
 			pop @dirstack; # back out of directory  | 
| 
707
 | 
55
 | 
 
 | 
 
 | 
 
 | 
 
 | 
41
 | 
 			pop @nodes;  | 
| 
708
 | 
55
 | 
 
 | 
 
 | 
 
 | 
 
 | 
62
 | 
 			pop @names;  | 
| 
709
 | 
55
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
91
 | 
 			return undef unless @dirstack;  | 
| 
710
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		}  | 
| 
711
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		# Iterate path leaf, by removing last leaf, and resolving using the  | 
| 
712
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		#  next name.  | 
| 
713
 | 
92
 | 
 
 | 
 
 | 
 
 | 
 
 | 
74
 | 
 		pop @nodes;  | 
| 
714
 | 
92
 | 
 
 | 
 
 | 
 
 | 
 
 | 
93
 | 
 		$names[-1]= shift @{$dirstack[-1]};  | 
| 
 
 | 
92
 | 
 
 | 
 
 | 
 
 | 
 
 | 
150
 | 
    | 
| 
715
 | 
92
 | 
 
 | 
 
 | 
 
 | 
 
 | 
269
 | 
 		$fs->_resolve_path(\@nodes, [ $names[-1] ]);  | 
| 
716
 | 
92
 | 
 
 | 
 
 | 
 
 | 
 
 | 
243
 | 
 		my $p= bless {  | 
| 
717
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 				path_names => \@names,  | 
| 
718
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 				path_dirents  => \@nodes,  | 
| 
719
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 				filesystem => $fs,  | 
| 
720
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			}, 'DataStore::CAS::FS::Path';  | 
| 
721
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		# If a dir, push it onto the stack  | 
| 
722
 | 
92
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
135
 | 
 		if ($p->type eq 'dir') {  | 
| 
723
 | 
42
 | 
 
 | 
 
 | 
 
 | 
 
 | 
46
 | 
 			push @dirstack, [ map { $_->name } @{ $fs->_get_dir_entries($nodes[-1]) } ];  | 
| 
 
 | 
92
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1669
 | 
    | 
| 
 
 | 
42
 | 
 
 | 
 
 | 
 
 | 
 
 | 
57
 | 
    | 
| 
724
 | 
42
 | 
 
 | 
 
 | 
 
 | 
 
 | 
69
 | 
 			push @nodes, undef;  | 
| 
725
 | 
42
 | 
 
 | 
 
 | 
 
 | 
 
 | 
48
 | 
 			push @names, undef;  | 
| 
726
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		}  | 
| 
727
 | 
92
 | 
 
 | 
 
 | 
 
 | 
 
 | 
184
 | 
 		return $p;  | 
| 
728
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
20
 | 
 	}, $class;  | 
| 
729
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
730
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
731
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub _init {  | 
| 
732
 | 
5
 | 
 
 | 
 
 | 
  
5
  
 | 
 
 | 
5
 | 
 	my $self= shift;  | 
| 
733
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# _resolve_path returns a string on failure  | 
| 
734
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
 	my $x;  | 
| 
735
 | 
5
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
10
 | 
 	ref( $x= $self->{fs}->_resolve_path(undef, $self->{path}) )  | 
| 
736
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		or croak $x;  | 
| 
737
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# maintain an array of resolved path nodes, and an array of  | 
| 
738
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	#  arrays of names-to-iterate for each directory  | 
| 
739
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
 	@{$self->{path_nodes}}= @$x;  | 
| 
 
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
9
 | 
    | 
| 
740
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
 	@{$self->{names}}= map { $_->{dirent}->name } @$x;  | 
| 
 
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
13
 | 
    | 
| 
 
 | 
13
 | 
 
 | 
 
 | 
 
 | 
 
 | 
240
 | 
    | 
| 
741
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
11
 | 
 	@{$self->{dirstack}}= ([]) x @$x;  | 
| 
 
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
    | 
| 
742
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
 	push @{$self->{dirstack}[-1]}, $self->{names}[-1];  | 
| 
 
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
16
 | 
    | 
| 
743
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
744
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
745
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub reset {  | 
| 
746
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
 
 | 
1170
 | 
 	$_[0]->($_[0])->_init;  | 
| 
747
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
 	1;  | 
| 
748
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
749
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
750
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub skip_dir {  | 
| 
751
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
 
 | 
8
 | 
 	my $self= $_[0]->($_[0]);  | 
| 
752
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
 	@{$self->{dirstack}[-1]}= ()  | 
| 
753
 | 
2
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
2
 | 
 		if @{$self->{dirstack}};  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
    | 
| 
754
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
 	1;  | 
| 
755
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
756
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
757
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 package DataStore::CAS::FS::DirCache;  | 
| 
758
 | 
4
 | 
 
 | 
 
 | 
  
4
  
 | 
 
 | 
16
 | 
 use strict;  | 
| 
 
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
    | 
| 
 
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
57
 | 
    | 
| 
759
 | 
4
 | 
 
 | 
 
 | 
  
4
  
 | 
 
 | 
12
 | 
 use warnings;  | 
| 
 
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
    | 
| 
 
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
988
 | 
    | 
| 
760
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
761
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
762
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub size {  | 
| 
763
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
  
0
  
 | 
 
 | 
0
 | 
 	if (@_ > 1) {  | 
| 
764
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		my ($self, $new_size)= @_;  | 
| 
765
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		$self->{size}= $new_size;  | 
| 
766
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		$self->{_recent}= [];  | 
| 
767
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		$self->{_recent_idx}= 0;  | 
| 
768
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
769
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	$_[0]{size};  | 
| 
770
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
771
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
772
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub new {  | 
| 
773
 | 
7
 | 
 
 | 
 
 | 
  
7
  
 | 
 
 | 
9
 | 
 	my $class= shift;  | 
| 
774
 | 
7
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
18
 | 
 	my %p= ref($_[0])? %{$_[0]} : @_;  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
775
 | 
7
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
35
 | 
 	$p{size} ||= 32;  | 
| 
776
 | 
7
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
24
 | 
 	$p{_by_hash} ||= {};  | 
| 
777
 | 
7
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
33
 | 
 	$p{_recent} ||= [];  | 
| 
778
 | 
7
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
21
 | 
 	$p{_recent_idx} ||= 0;  | 
| 
779
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
103
 | 
 	bless \%p, $class;  | 
| 
780
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
781
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
782
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub clear {  | 
| 
783
 | 
  
0
  
 | 
 
 | 
 
 | 
  
0
  
 | 
 
 | 
0
 | 
 	$_= undef for @{$_[0]{_recent}};  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
784
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	$_[0]{_by_hash}= {};  | 
| 
785
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
786
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
787
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub get {  | 
| 
788
 | 
124
 | 
 
 | 
 
 | 
  
124
  
 | 
 
 | 
173
 | 
 	return $_[0]{_by_hash}{$_[1]};  | 
| 
789
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
790
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
791
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub put {  | 
| 
792
 | 
48
 | 
 
 | 
 
 | 
  
48
  
 | 
 
 | 
53
 | 
 	my ($self, $dir)= @_;  | 
| 
793
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# Hold onto a strong reference for a while.  | 
| 
794
 | 
48
 | 
 
 | 
 
 | 
 
 | 
 
 | 
75
 | 
 	$self->{_recent}[ $self->{_recent_idx}++ ]= $dir;  | 
| 
795
 | 
48
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
42
 | 
 	$self->{_recent_idx}= 0 if $self->{_recent_idx} > @{$self->{_recent}};  | 
| 
 
 | 
48
 | 
 
 | 
 
 | 
 
 | 
 
 | 
85
 | 
    | 
| 
796
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# Index it using a weak reference.  | 
| 
797
 | 
48
 | 
 
 | 
 
 | 
 
 | 
 
 | 
107
 | 
 	Scalar::Util::weaken( $self->{_by_hash}{$dir->hash}= $dir );  | 
| 
798
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# Now, a nifty hack: we attach an object to watch for the destriction of the  | 
| 
799
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# directory.  Lazy references will get rid of the dir object, but this cleans  | 
| 
800
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# up our _by_hash index.  | 
| 
801
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	$dir->{'#DataStore::CAS::FS::DirCacheCleanup'}=  | 
| 
802
 | 
48
 | 
 
 | 
 
 | 
 
 | 
 
 | 
256
 | 
 		bless [ $self->{_by_hash}, $dir->hash ], 'DataStore::CAS::FS::DirCacheCleanup';  | 
| 
803
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
804
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
805
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 package DataStore::CAS::FS::DirCacheCleanup;  | 
| 
806
 | 
4
 | 
 
 | 
 
 | 
  
4
  
 | 
 
 | 
19
 | 
 use strict;  | 
| 
 
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
    | 
| 
 
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
59
 | 
    | 
| 
807
 | 
4
 | 
 
 | 
 
 | 
  
4
  
 | 
 
 | 
13
 | 
 use warnings;  | 
| 
 
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
    | 
| 
 
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
201
 | 
    | 
| 
808
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
809
 | 
48
 | 
 
 | 
 
 | 
  
48
  
 | 
 
 | 
4273
 | 
 sub DESTROY { delete $_[0][0]{$_[0][1]}; }  | 
| 
810
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
811
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 1;  | 
| 
812
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
813
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 __END__  |