// Copyright 2014 Google Inc. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package com.google.devtools.build.lib.actions.cache; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; import com.google.devtools.build.lib.util.Fingerprint; import com.google.devtools.build.lib.util.VarInt; import java.io.IOException; import java.io.OutputStream; import java.nio.ByteBuffer; import java.util.Arrays; import java.util.Map; /** * A value class for capturing and comparing MD5-based digests. * *
Note that this class is responsible for digesting file metadata in an * order-independent manner. Care must be taken to do this properly. The * digest must be a function of the set of (path, metadata) tuples. While the * order of these pairs must not matter, it would not be safe to make * the digest be a function of the set of paths and the set of metadata. * *
Note that the (path, metadata) tuples must be unique, otherwise the
* XOR-based approach will fail.
*/
public class Digest {
static final int MD5_SIZE = 16;
private final byte[] digest;
/**
* Construct the digest from the given bytes.
* @param digest an MD5 digest. Must be sized properly.
*/
@VisibleForTesting
Digest(byte[] digest) {
Preconditions.checkState(digest.length == MD5_SIZE);
this.digest = Arrays.copyOf(digest, digest.length);
}
/**
* @param source the byte buffer source.
* @return the digest from the given buffer.
* @throws IOException if the byte buffer is incorrectly formatted.
*/
public static Digest read(ByteBuffer source) throws IOException {
int size = VarInt.getVarInt(source);
if (size != MD5_SIZE) {
throw new IOException("Unexpected digest length: " + size);
}
byte[] bytes = new byte[size];
source.get(bytes);
return new Digest(bytes);
}
/**
* Write the digest to the output stream.
*/
public void write(OutputStream sink) throws IOException {
VarInt.putVarInt(digest.length, sink);
sink.write(digest);
}
/**
* @param mdMap A collection of (execPath, Metadata) pairs.
* Values may be null.
* @return an order-independent digest from the given "set" of
* (path, metadata) pairs.
*/
public static Digest fromMetadata(Map