/* * Copyright (C) 2010-2016 Martin Goellnitz * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301, USA */ package jfs.sync.meta; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Map; import javax.crypto.Cipher; import jfs.sync.encryption.AbstractMetaStorageAccess; import jfs.sync.encryption.FileInfo; import jfs.sync.encryption.JFSEncryptedStream; import jfs.sync.util.SecurityUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class MetaFileStorageAccess extends AbstractMetaStorageAccess { private static final Logger LOG = LoggerFactory.getLogger(MetaFileStorageAccess.class); private static long outputStreams; private static long inputStreams; public MetaFileStorageAccess(String cipher, boolean sixBits) { super(cipher, sixBits); } // MetaFileStorageAccess() /** * create non existent files * * @param file * @param pathAndName * @return */ private FileInfo createFileInfo(File file, String[] pathAndName) { FileInfo result = new FileInfo(); result.setCanRead(true); result.setCanWrite(true); result.setDirectory(file.isDirectory()); result.setExists(file.exists()); result.setModificationDate(file.lastModified()); result.setName(pathAndName[1]); result.setPath(pathAndName[0]); result.setSize(result.isDirectory() ? 0 : file.length()); if (LOG.isDebugEnabled()) { LOG.debug("createFileInfo("+pathAndName[0]+"/"+pathAndName[1]+") "+result); } // if return result; } // createFileInfo() @Override public FileInfo getFileInfo(String rootPath, String relativePath) { String[] pathAndName = getPathAndName(relativePath); FileInfo result = getParentListing(rootPath, pathAndName).get(pathAndName[1]); if (result==null) { result = createFileInfo(getFile(rootPath, relativePath), pathAndName); } // if return result; } // getFileInfo() @Override public boolean createDirectory(String rootPath, String relativePath) { File file = getFile(rootPath, relativePath); boolean success = file.mkdir(); if (success) { String[] pathAndName = getPathAndName(relativePath); Map<String, FileInfo> listing = getParentListing(rootPath, pathAndName); LOG.debug("createDirectory() {}", relativePath); LOG.debug("createDirectory() listing={}", listing); FileInfo info = createFileInfo(file, pathAndName); listing.put(pathAndName[1], info); LOG.debug("createDirectory() listing={}", listing); LOG.info("createDirectory() flushing {}/{}", pathAndName[0], pathAndName[1]); flushMetaData(rootPath, pathAndName, listing); } // if LOG.debug("createDirectory() {}", success); return success; } // createDirectory() @Override public boolean setLastModified(String rootPath, String relativePath, long modificationDate) { boolean success = getFile(rootPath, relativePath).setLastModified(modificationDate); if (success) { String[] pathAndName = getPathAndName(relativePath); Map<String, FileInfo> listing = getParentListing(rootPath, pathAndName); FileInfo info = listing.get(pathAndName[1]); LOG.info("setLastModified() flushing {}/{}", pathAndName[0], pathAndName[1]); info.setModificationDate(modificationDate); flushMetaData(rootPath, pathAndName, listing); } // if return success; } // setLastModified() @Override public boolean setReadOnly(String rootPath, String relativePath) { LOG.info("setReadOnly() not flushing {}", relativePath); return getFile(rootPath, relativePath).setReadOnly(); } // setReadOnly() @Override public boolean delete(String rootPath, String relativePath) { String[] pathAndName = getPathAndName(relativePath); Map<String, FileInfo> listing = getParentListing(rootPath, pathAndName); LOG.debug("delete() {}", relativePath); LOG.debug("delete() listing={}", listing); // remove named item File file = getFile(rootPath, relativePath); if (listing.containsKey(pathAndName[1])) { listing.remove(pathAndName[1]); LOG.info("delete() flushing {}/{}", pathAndName[0], pathAndName[1]); flushMetaData(rootPath, pathAndName, listing); LOG.info("delete() listing={}", listing); if (file.isDirectory()) { String metaDataPath = getMetaDataPath(relativePath); File metaDataFile = getFile(rootPath, metaDataPath); if (metaDataFile.exists()) { metaDataFile.delete(); } // if } // if file.delete(); } // if return !file.exists(); } // delete() @Override public InputStream getInputStream(String rootPath, String relativePath) throws IOException { File file = getFile(rootPath, relativePath); LOG.debug("getInputStream() getting input stream for {}", file.getPath()); inputStreams++; LOG.debug("getInputStream({}) inputStreams={}", relativePath, inputStreams); return new FileInputStream(file); } // getInputStream() @Override protected OutputStream getOutputStream(String rootPath, String relativePath, boolean forPayload) throws IOException { File file = getFile(rootPath, relativePath); file.setWritable(true); // at least try... String[] pathAndName = getPathAndName(relativePath); Map<String, FileInfo> listing = getParentListing(rootPath, pathAndName); if (forPayload&&(listing.get(pathAndName[1])==null||!file.exists())) { FileInfo info = createFileInfo(file, pathAndName); listing.put(info.getName(), info); LOG.info("getOutputStream() flushing {}/{}", pathAndName[0], pathAndName[1]); flushMetaData(rootPath, pathAndName, listing); LOG.debug("getOutputStream() getting output stream for {} {}", file.getPath(), info); } // if LOG.debug("getOutputStream() getting outpult stream for {}", file.getPath()); outputStreams++; if (LOG.isInfoEnabled()) { LOG.info("getOutputStream("+relativePath+") outputStreams="+outputStreams); } // if OutputStream result = new FileOutputStream(file); FileInfo info = createFileInfo(file, pathAndName); if (LOG.isDebugEnabled()) { LOG.debug("getOutputStream() have output stream for "+file.getPath()+" "+info+" "+result); } // if return result; } // getOutputStream() /** * * Extract one file from encrypted repository. * * TODO: list directories * */ public static void main(String[] args) throws Exception { final String password = args[0]; MetaFileStorageAccess storage = new MetaFileStorageAccess("Twofish", false) { protected String getPassword(String relativePath) { String result = ""; String pwd = password; int i = 0; int j = relativePath.length()-1; while ((i<pwd.length())||(j>=0)) { if (i<pwd.length()) { result += pwd.charAt(i++); } // if if (j>=0) { result += relativePath.charAt(j--); } // if } // while return result; } // getPassword() }; String encryptedPath = args[2]; String[] elements = encryptedPath.split("\\\\"); String path = ""; for (int i = 0; i<elements.length; i++) { String encryptedName = elements[i]; String plain = storage.getDecryptedFileName(path, encryptedName); path += storage.getSeparator(); path += plain; System.out.println(path); } // for String cipherSpec = storage.getCipherSpec(); byte[] credentials = storage.getFileCredentials(path); Cipher cipher = SecurityUtils.getCipher(cipherSpec, Cipher.DECRYPT_MODE, credentials); InputStream is = storage.getInputStream(args[1], path); is = JFSEncryptedStream.createInputStream(is, JFSEncryptedStream.DONT_CHECK_LENGTH, cipher); int b = 0; while (b>=0) { b = is.read(); System.out.print((char) b); } // while is.close(); } // main() } // MetaFileStorageAccess