DataStore-CAS-FS

 view release on metacpan or  search on metacpan

lib/DataStore/CAS/FS.pm  view on Meta::CPAN

			if (ref $subnode) {
				$dirents{$_}= $subnode->{dirent}
					if $subnode->{changed};
			} else {
				delete $dirents{$_};
			}
		}
	}
	return [ map { $dirents{$_} } sort keys %dirents ];
}


sub set_path {
	my ($self, $path, $newent, $flags)= @_;
	$flags ||= {};
	my $nodes= $self->_resolve_path(undef, $path, { follow_symlinks => 1, partial => 1, %$flags });
	croak $nodes unless ref $nodes;
	# replace the final entry, after applying defaults
	if (!$newent) {
		# unlink request.  Ignore if node didn't exist.
		return if $nodes->[-1]{invalid};

		# Can't unlink the root node
		croak "Can't unlink root node"
			unless @$nodes > 1;

		$nodes->[-1]{invalid}= 1;
		# Recursively invalidate all nodes beneath this one
		&_invalidate_subtree for ($nodes->[-1]);

		# Mark in prev node that this item is gone
		my $key= $self->case_insensitive? uc $nodes->[-1]{dirent}->name : $nodes->[-1]{dirent}->name;
		pop @$nodes;
		$nodes->[-1]{subtree}{$key}= 0;
	} else {
		if (ref $newent eq 'HASH' or !defined $newent->name or !defined $newent->type) {
			my %ent_hash= %{ref $newent eq 'HASH'? $newent : $newent->as_hash};
			$ent_hash{name}= $nodes->[-1]{dirent}->name
				unless defined $ent_hash{name};
			defined $ent_hash{name} && length $ent_hash{name}
				or die "No name for new dir entry";
			$ent_hash{type}= $nodes->[-1]{dirent}->type || 'file'
				unless defined $ent_hash{type};
			$newent= DataStore::CAS::FS::DirEnt->new(\%ent_hash);
		}
		$nodes->[-1]{dirent}= $newent;
		delete $nodes->[-1]{dir};
		# Recursively invalidate all nodes beneath this one
		&_invalidate_subtree for ($nodes->[-1]);
	}
	# Now connect nodes with strong references, and mark as changed
	$self->_apply_overrides($nodes);
}
sub _invalidate_subtree {
	if ($_->{subtree}) {
		++$_->{invalid} && &_invalidate_subtree for grep { ref $_ } values %{delete $_->{subtree}};
	}
}


sub update_path {
	my ($self, $path, $changes, $flags)= @_;
	$flags ||= {};
	my $nodes= $self->_resolve_path(undef, $path, { follow_symlinks => 1, partial => 1, %$flags });
	croak $nodes unless ref $nodes;

	# update the final entry, after applying defaults
	my $entref= \$nodes->[-1]{dirent};
	my $old_dir_ref= defined $$entref->type && $$entref->type eq 'dir'? $$entref->ref : undef;
	$$entref= $$entref->clone(
		(defined $$entref->type? () : ( type => 'file' )),
		ref $changes eq 'HASH'? %$changes
			: ref $changes eq 'ARRAY'? @$changes
			: croak 'parameter "changes" must be a hashref or arrayref'
	);
	my $new_dir_ref= $$entref->type eq 'dir'? $$entref->ref : undef;

	# If we changed the type of a directory, or changed which digest_hash it
	# refers to, then we should clear the subtree under this node.
	if (($old_dir_ref || '') ne ($new_dir_ref || '') && $nodes->[-1]{subtree}) {
		# Recursively invalidate all nodes beneath this one
		&_invalidate_subtree for ($nodes->[-1]);
		delete $nodes->[-1]{dir};
	}

	$self->_apply_overrides($nodes);
}

sub _apply_overrides {
	my ($self, $nodes)= @_;
	# Ensure that each node is connected to the previous via 'subtree'.
	# When we find the first changed node, we assume the rest are connected.
	my $prev;
	for (reverse @$nodes) {
		if ($prev) {
			my $key= $self->case_insensitive? uc($prev->{dirent}->name) : $prev->{dirent}->name;
			$_->{subtree}{$key}= $prev;
		}
		last if $_->{changed} && !$_->{invalid};
		delete $_->{invalid};
		$_->{changed}= 1;
		$prev= $_;
	}
	# Finally, make sure the root override is set
	$self->{_nodes}= $nodes->[0];
	1;
}


sub mkdir {
	my ($self, $path)= @_;
	my $nodes= $self->_resolve_path(undef, $path, { follow_symlinks => 1, mkdir => 1 });
	croak $nodes unless ref $nodes;
	unless (defined $nodes->[-1]{dirent}->type) {
		$nodes->[-1]{dirent}= $nodes->[-1]{dirent}->clone(type => 'dir');
		$self->_apply_overrides($nodes);
	}
	1;
}




( run in 0.733 second using v1.01-cache-2.11-cpan-df04353d9ac )