1 package org
.argeo
.cms
.util
;
3 import java
.io
.IOException
;
4 import java
.io
.PrintStream
;
5 import java
.nio
.charset
.Charset
;
6 import java
.nio
.file
.DirectoryStream
;
7 import java
.nio
.file
.Files
;
8 import java
.nio
.file
.Path
;
9 import java
.nio
.file
.Paths
;
10 import java
.security
.MessageDigest
;
11 import java
.security
.NoSuchAlgorithmException
;
12 import java
.util
.ArrayList
;
13 import java
.util
.Arrays
;
14 import java
.util
.List
;
16 /** Hashes the hashes of the files in a directory. */
19 private final static Charset charset
= Charset
.forName("UTF-16");
20 private final static long bufferSize
= 200 * 1024 * 1024;
21 private final static String algorithm
= "SHA";
23 private final static byte EOL
= (byte) '\n';
24 private final static byte SPACE
= (byte) ' ';
26 private final int hashSize
;
28 private final byte[][] hashes
;
29 private final byte[][] fileNames
;
30 private final byte[] digest
;
31 private final byte[] dirName
;
34 * @param dirName can be null or empty
36 private DirH(byte[][] hashes
, byte[][] fileNames
, byte[] dirName
) {
37 if (hashes
.length
!= fileNames
.length
)
38 throw new IllegalArgumentException(hashes
.length
+ " hashes and " + fileNames
.length
+ " file names");
40 this.fileNames
= fileNames
;
41 this.dirName
= dirName
== null ?
new byte[0] : dirName
;
42 if (hashes
.length
== 0) {// empty dir
44 // FIXME what is the digest of an empty dir?
45 digest
= new byte[hashSize
];
46 Arrays
.fill(digest
, SPACE
);
49 hashSize
= hashes
[0].length
;
50 for (int i
= 0; i
< hashes
.length
; i
++) {
51 if (hashes
[i
].length
!= hashSize
)
52 throw new IllegalArgumentException(
53 "Hash size for " + new String(fileNames
[i
], charset
) + " is " + hashes
[i
].length
);
57 MessageDigest md
= MessageDigest
.getInstance(algorithm
);
58 for (int i
= 0; i
< hashes
.length
; i
++) {
59 md
.update(this.hashes
[i
]);
61 md
.update(this.fileNames
[i
]);
65 } catch (NoSuchAlgorithmException e
) {
66 throw new IllegalArgumentException("Cannot digest", e
);
70 public void print(PrintStream out
) {
71 out
.print(DigestUtils
.toHexString(digest
));
72 if (dirName
.length
> 0) {
74 out
.print(new String(dirName
, charset
));
77 for (int i
= 0; i
< hashes
.length
; i
++) {
78 out
.print(DigestUtils
.toHexString(hashes
[i
]));
80 out
.print(new String(fileNames
[i
], charset
));
85 public static DirH
digest(Path dir
) {
86 try (DirectoryStream
<Path
> files
= Files
.newDirectoryStream(dir
)) {
87 List
<byte[]> hs
= new ArrayList
<byte[]>();
88 List
<String
> fNames
= new ArrayList
<>();
89 for (Path file
: files
) {
90 if (!Files
.isDirectory(file
)) {
91 byte[] digest
= DigestUtils
.digestAsBytes(algorithm
, file
, bufferSize
);
93 fNames
.add(file
.getFileName().toString());
97 byte[][] fileNames
= new byte[fNames
.size()][];
98 for (int i
= 0; i
< fNames
.size(); i
++) {
99 fileNames
[i
] = fNames
.get(i
).getBytes(charset
);
101 byte[][] hashes
= hs
.toArray(new byte[hs
.size()][]);
102 return new DirH(hashes
, fileNames
, dir
.toString().getBytes(charset
));
103 } catch (IOException e
) {
104 throw new RuntimeException("Cannot digest " + dir
, e
);
108 public static void main(String
[] args
) {
110 DirH dirH
= DirH
.digest(Paths
.get("/home/mbaudier/tmp/"));
111 dirH
.print(System
.out
);
112 } catch (Exception e
) {