/*
* Copyright 2015 Shashank Tulsyan <shashaank at neembuu.com>.
*
* 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 spyfs;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.FileVisitResult;
import java.nio.file.FileVisitor;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Stack;
import java.util.function.Consumer;
import jpfm.FileAttributesProvider;
import jpfm.MountListener;
import jpfm.fs.SimpleReadOnlyFileSystem;
import jpfm.mount.Mount;
import jpfm.mount.MountParams;
import jpfm.mount.MountParamsBuilder;
import jpfm.mount.Mounts;
import jpfm.volume.RealFile;
import jpfm.volume.vector.VectorDirectory;
import jpfm.volume.vector.VectorNode;
import jpfm.volume.vector.VectorRootDirectory;
/**
*
* @author Shashank
*/
public class SpyFS{
private final VectorRootDirectory vrd = new VectorRootDirectory();
private final SimpleReadOnlyFileSystem sfs = new SimpleReadOnlyFileSystem(vrd);
private final Path storeTo;
private long totalFiles = 0, totalDirectories = 0;
public SpyFS(Path storeTo) {
this.storeTo = storeTo;
}
public static SpyFSController work(final Settings s,Consumer<String> cntr)throws Exception{
final SpyFS fs = new SpyFS(Paths.get(s.destinationPath()));
deleteC(Paths.get(s.destinationPath()));
fs.fill(Paths.get(s.sourcePath()),cntr);
MountListener.WaitingMountListener l = new MountListener.WaitingMountListener();
final Mount mount = Mounts.mount(new MountParamsBuilder()
.set(MountParams.ParamType.LISTENER, l)
.set(MountParams.ParamType.EXIT_ON_UNMOUNT, false)
.set(MountParams.ParamType.FILE_SYSTEM, fs.sfs)
.set(MountParams.ParamType.MOUNT_LOCATION,s.virtualLocation())
.build()
);
return new SpyFSController() {
@Override public void unmount(Consumer<String> status) {
try{mount.unMount();}catch(Exception a){
status.accept(a.getLocalizedMessage());
a.printStackTrace();
}
}
@Override public void ejectCopy(Consumer<String> status) {
try{
final PrintWriter pw = new PrintWriter(s.reportPath());
walkNode(fs.vrd,status, (s)->{
try{pw.println(s);}
catch(Exception a){
System.out.println("err in writing -> "+s);
}});
pw.close();
}
catch(Exception a){
a.printStackTrace();
}
}
@Override public long totalFiles() {return fs.totalFiles;}
@Override public long totalFilesAndDirectories() {return totalFiles()+totalDirectories();}
@Override public long totalDirectories() {return fs.totalDirectories;}
};
}
private static void deleteC(Path c){
System.out.println("Clearing "+c);
try{
Files.walkFileTree(c, new FileVisitor<Path>() {
@Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {return FileVisitResult.CONTINUE;}
@Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
Files.delete(file);
return FileVisitResult.CONTINUE;
}
@Override public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
return FileVisitResult.CONTINUE;
}
@Override public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
if(dir!=c) // don't delete root
Files.delete(dir);
return FileVisitResult.CONTINUE;
}
});
}catch(Exception a){
a.printStackTrace();
}
}
private void fill(final Path p,final Consumer<String> cx) throws IOException {
Files.walkFileTree(p, new FileVisitor<Path>() {
private VectorNode currentDir = vrd;
private final Stack<VectorNode> directoryStack = new Stack<>();
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
if (dir.equals(p)) {
return FileVisitResult.CONTINUE;
}
cx.accept(p.relativize(dir).toString());
totalDirectories++;
VectorDirectory vd = new VectorDirectory(dir.getFileName().toString(), currentDir);
currentDir.add(vd);
directoryStack.add(currentDir);
currentDir = vd;
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
if (Files.isDirectory(file)) {
return FileVisitResult.CONTINUE;
}
cx.accept(p.relativize(file).toString());
totalFiles++;
RealFile rf = new SpiedFile(file, currentDir, storeTo.resolve(p.relativize(file)) );
currentDir.add(rf);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
System.out.println("failed to visit " + file);
exc.printStackTrace();
return FileVisitResult.TERMINATE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
if (dir.equals(p)) {
return FileVisitResult.CONTINUE;
}
currentDir = directoryStack.pop();
return FileVisitResult.CONTINUE;
}
});
}
private static void walkNode(VectorNode vn,Consumer<String> status,Consumer<String> writer) throws IOException {
printNode(vn,writer);
for (FileAttributesProvider fap : vn) {
if (fap instanceof SpiedFile) {
SpiedFile sf = (SpiedFile) fap;
sf.export();
} else if (fap instanceof VectorNode) {
walkNode(((VectorNode) fap),status,writer);
}
}
}
private static void printNode(VectorNode vn,Consumer<String> writer) throws IOException {
for (FileAttributesProvider fap : vn) {
if (fap instanceof SpiedFile) {
SpiedFile sf = (SpiedFile) fap;
writer.accept(
sf.getDest() + "\t" + sf.getFileSize() + "\t" + sf.p() + "\t"
+ (sf.opened() ? "opened" : "untouched")
);
} else if (fap instanceof VectorNode) {
printNode(((VectorNode) fap),writer);
}
}
}
}