# HG changeset patch # User Artem Tikhomirov # Date 1294974848 -3600 # Node ID 858d1b2458cb8bb56adee24b762de4e33f6f6d51 # Parent 21e26da142fa15977a58f61a899f8b1f09fe1b16 Check integrity for bundle changelog. Sort nodeids when calculating hash diff -r 21e26da142fa -r 858d1b2458cb design.txt --- a/design.txt Fri Jan 14 03:37:06 2011 +0100 +++ b/design.txt Fri Jan 14 04:14:08 2011 +0100 @@ -37,6 +37,9 @@ Changeset to get index (local revision number) RevisionWalker (on manifest) and WorkingCopyWalker (io.File) talking to ? and/or dirstate RevlogStream - Inflater. Perhaps, InflaterStream instead? +Implement use of fncache (use names from it - perhaps, would help for Mac issues Alex mentioned) along with 'digest'-ing long file names + + Status operation from GUI - guess, usually on a file/subfolder, hence API should allow for starting path (unlike cmdline, seems useless to implement include/exclide patterns - GUI users hardly enter them, ever) diff -r 21e26da142fa -r 858d1b2458cb src/com/tmate/hgkit/ll/DigestHelper.java --- a/src/com/tmate/hgkit/ll/DigestHelper.java Fri Jan 14 03:37:06 2011 +0100 +++ b/src/com/tmate/hgkit/ll/DigestHelper.java Fri Jan 14 04:14:08 2011 +0100 @@ -9,6 +9,7 @@ import java.security.NoSuchAlgorithmException; /** + * TODO sha1_binary to give array for Nodeid.equalsTo * * @author artem */ @@ -30,16 +31,27 @@ return sha1; } - // XXX perhaps, digest functions should throw an exception, as it's caller responsibility to deal with eof, etc + + public String sha1(Nodeid nodeid1, Nodeid nodeid2, byte[] data) { + return sha1(nodeid1.cloneData(), nodeid2.cloneData(), data); + } + + // sha1_digest(min(p1,p2) ++ max(p1,p2) ++ final_text) public String sha1(byte[] nodeidParent1, byte[] nodeidParent2, byte[] data) { MessageDigest alg = getSHA1(); - alg.update(nodeidParent1); - alg.update(nodeidParent2); + if ((nodeidParent1[0] & 0x00FF) < (nodeidParent2[0] & 0x00FF)) { + alg.update(nodeidParent1); + alg.update(nodeidParent2); + } else { + alg.update(nodeidParent2); + alg.update(nodeidParent1); + } byte[] digest = alg.digest(data); assert digest.length == 20; return toHexString(digest, 0, 20); } + // XXX perhaps, digest functions should throw an exception, as it's caller responsibility to deal with eof, etc public byte[] sha1(InputStream is /*ByteBuffer*/) throws IOException { MessageDigest alg = getSHA1(); byte[] buf = new byte[1024]; diff -r 21e26da142fa -r 858d1b2458cb src/com/tmate/hgkit/ll/HgBundle.java --- a/src/com/tmate/hgkit/ll/HgBundle.java Fri Jan 14 03:37:06 2011 +0100 +++ b/src/com/tmate/hgkit/ll/HgBundle.java Fri Jan 14 04:14:08 2011 +0100 @@ -28,6 +28,7 @@ public void changes(HgRepository hgRepo) throws IOException { DataAccess da = accessProvider.create(bundleFile); + DigestHelper dh = new DigestHelper(); try { List changelogGroup = readGroup(da); if (changelogGroup.isEmpty()) { @@ -46,6 +47,9 @@ for (GroupElement ge : changelogGroup) { int resultLen = 10000; // XXX calculate based on baseRevContent.length and ge.patches byte[] csetContent = RevlogStream.apply(baseRevContent, resultLen, ge.patches); + // wiki suggests sha1_digest(min(p1,p2) ++ max(p1,p2) ++ final_text), + String digest = dh.sha1(ge.firstParent(), ge.secondParent(), csetContent); // XXX ge may give me access to byte[] content of nodeid directly, perhaps, I don't need DH to be friend of Nodeid? + System.out.println("Node: " + ge.node() + ", digest: " + digest); Changeset cs = Changeset.parse(csetContent, 0, csetContent.length); cs.dump(); baseRevContent = csetContent; diff -r 21e26da142fa -r 858d1b2458cb src/com/tmate/hgkit/ll/Nodeid.java --- a/src/com/tmate/hgkit/ll/Nodeid.java Fri Jan 14 03:37:06 2011 +0100 +++ b/src/com/tmate/hgkit/ll/Nodeid.java Fri Jan 14 04:14:08 2011 +0100 @@ -75,6 +75,12 @@ return true; } + // primary purpose is to give DigestHelper access to internal structure. Despite it's friends-only (package visibility), it's still makes sense to + // return a copy, to avoid any accidental modification (same reason field is not made visible, nor any callback, e.g. Output.write(byte[]) was introduced) + /*package-local*/byte[] cloneData() { + return binaryData.clone(); + } + // primary difference with cons is handling of NULL id (this method returns constant) // always makes a copy of an array passed public static Nodeid fromBinary(byte[] binaryRepresentation, int offset) {