/* ************************************************************************ # # DivConq # # http://divconq.com/ # # Copyright: # Copyright 2014 eTimeline, LLC. All rights reserved. # # License: # See the license.txt file in the project's top-level directory for details. # # Authors: # * Andy White # ************************************************************************ */ package divconq.interchange.ssh; public class SftpFile { /* extends RecordStruct implements IFileStoreFile { protected SftpDriver driver = null; protected LsEntry file = null; protected FileInputStream input = null; protected long offset = 0; // TODO check for removed before doing operations requiring the file protected boolean removed = false; public SftpFile() { this.setType(Hub.instance.getSchema().getType("dciSftpFile")); } public SftpFile(SftpDriver driver, LsEntry file, String fullpath) { this(); this.driver = driver; this.file = file; SftpATTRS attrs = file.getAttrs(); this.setField("Name", file.getFilename()); this.setField("Size", attrs.getSize()); this.setField("Modified", new DateTime(((long) attrs.getMTime()) * 1000)); String cwd = driver.getFieldAsString("RootFolder"); this.setField("Path", fullpath.substring(cwd.length() + 1).replace('\\', '/')); this.setField("FullPath", fullpath); this.setField("IsFolder", file.getAttrs().isDir()); } /* public SftpFile(SftpDriver driver, RecordStruct rec) { this(); this.driver = driver; ((RecordStruct) this).copyFields(rec); String cwd = driver.getFieldAsString("RootFolder"); this.file = new File(cwd + "/" + this.getFieldAsString("Path")); if (this.file.exists()) { // ignore what the caller told us, these are the right values: this.setField("Name", this.file.getName()); this.setField("Size", this.file.length()); this.setField("Modified", new DateTime(this.file.lastModified())); this.setField("IsFolder", this.file.isDirectory()); } } * / @Override protected void doCopy(Struct n) { super.doCopy(n); SftpFile nn = (SftpFile)n; nn.driver = this.driver; } @Override public Struct deepCopy() { SftpFile cp = new SftpFile(); this.doCopy(cp); return cp; } @Override public void dispose() { // TODO support this!!! super.dispose(); } @Override public FuncResult<Struct> getOrAllocateField(String name) { if ("TextReader".equals(name) && !this.removed) { FuncResult<Struct> res = new FuncResult<Struct>(); res.setResult(new SftpTextReader(this)); return res; } return super.getOrAllocateField(name); } /* @Override public void toBuilder(ICompositeBuilder builder) throws BuilderStateException { builder.startRecord(); for (FieldStruct f : this.fields.values()) f.toBuilder(builder); // TODO add in FS specific fields builder.endRecord(); } @Override public Struct select(PathPart... path) { if (path.length > 0) { PathPart part = path[0]; if (part.isField()) { String fld = part.getField(); if ("Scanner".equals(fld)) return this.search; } } return super.select(path); } * / @Override public void operation(final StackEntry stack, XElement code) { if ("Hash".equals(code.getName())) { String meth = stack.stringFromElement(code, "Method"); final Struct var = stack.refFromElement(code, "Target"); if (var instanceof ScalarStruct) { this.hash(meth, new FuncCallback<String>() { @Override public void callback() { ((ScalarStruct)var).adaptValue(this.getResult()); stack.resume(); } }); return; } else { // TODO log } stack.resume(); return; } super.operation(stack, code); } @Override public void copyTo(final OutputStream out, final OperationCallback callback) { this.getInputStream(new FuncCallback<InputStream>() { @Override public void callback() { // TODO check for errors InputStream in = this.getResult(); try { CopyUtils.copy(in, out); } catch (IOException x) { callback.error(1, "Unable to write file"); // TODO codes } finally { IOUtils.closeQuietly(in); IOUtils.closeQuietly(out); } callback.completed(); } }); } public class DestinationDriver implements IDestinationDriver { protected FileOutputStream out = null; protected ISessionStream source = null; protected Session session = null; @Override public void setSource(ISessionStream v) { this.source = v; } public DestinationDriver(Session session) { this.session = session; /* TODO try { this.out = new FileOutputStream(SftpFile.this.file); } catch (FileNotFoundException x) { // TODO System.out.println("Error while creating consumer"); } * / } @Override public void present(Block data) { try { if (data.isAbort()) { this.session.getAdapter().releaseSource(); this.source = null; System.out.println("Error while uploading, aborted!"); // TODO this.out.close(); return; } Memory mem = data.getData(); if (mem != null) this.out.write(mem.toArray()); if (data.isDone()) { this.out.flush(); this.out.close(); } /* TODO this should be in here in some sense #NETTY Message rmsg = new Message(); rmsg.setField("Op", data.isDone() ? "Done" : "Next"); this.source.reaction(rmsg); // give me more * / if (data.isDone()) { this.session.getAdapter().releaseSource(); this.source = null; } } catch (IOException x) { // TODO System.out.println("Error while uploading"); } } } public class SourceDriver implements ISourceDriver { protected FileInputStream in = null; protected ISessionStream dest = null; protected long offset = 0; @Override public void setDestination(ISessionStream v) { this.dest = v; } public SourceDriver(Session session) { /* TODO try { this.in = new FileInputStream(SftpFile.this.file); } catch (FileNotFoundException x) { // TODO System.out.println("Error while creating consumer"); } * / } @Override public void collect(FuncCallback<Block> callback) { try { Block b = new Block(); Memory mem = new Memory(16384); // TODO config b.setData(mem); b.setOffset(this.offset); int amt = mem.copyFromStream(this.in, 16384); if (amt < 16384) { b.setDone(true); this.in.close(); } this.offset += amt; mem.setPosition(0); callback.setResult(b); } catch (IOException x) { // TODO System.out.println("Error while downloading"); } callback.completed(); } @Override public void abort() { try { this.in.close(); } catch (IOException x) { // TODO System.out.println("Error while downloading"); } } } @Override public void openRead(Session session, final FuncCallback<ISourceDriver> callback) { callback.setResult(new SourceDriver(session)); callback.completed(); } @Override public void openWrite(Session session, final FuncCallback<IDestinationDriver> callback) { // TODO this.file.getParentFile().mkdirs(); callback.setResult(new DestinationDriver(session)); callback.completed(); } @Override public void hash(String method, FuncCallback<String> callback) { /* TODO try { // TODO support something other than Sha2 - see params callback.setResult(HashUtil.getSha2(new FileInputStream(this.file))); } catch (Exception x) { // TODO log } * / callback.completed(); } @Override public void getInputStream(final FuncCallback<InputStream> callback) { if (this.removed) { // TODO log callback.completed(); return; } SftpFile.this.driver.getChannel(new FuncCallback<ChannelSftp>() { @Override public void callback() { ChannelSftp channel = this.getResult(); try { callback.setResult(channel.get(SftpFile.this.getFieldAsString("FullPath"))); } catch (Exception x) { // TODO log } finally { SftpFile.this.driver.releaseChannel(channel); } callback.completed(); } }); } @Override public String getName() { return this.getFieldAsString("Name"); } @Override public String getPath() { return this.getFieldAsString("Path"); } @Override public String getExtension() { String ext = this.getFieldAsString("Name"); int pos = ext.lastIndexOf('.'); if (pos > 0) ext = ext.substring(pos + 1); return ext; } @Override public String getFullPath() { return this.getFieldAsString("FullPath"); } @Override public DateTime getMofificationTime() { return this.getFieldAsDateTime("Modified"); } @Override public long getSize() { return this.getFieldAsInteger("Size"); } @Override public boolean isFolder() { return this.getFieldAsBoolean("IsFolder"); } // is not a move @Override public void rename(final String name, final OperationCallback callback) { if (this.removed) { // TODO log callback.completed(); return; } SftpFile.this.driver.getChannel(new FuncCallback<ChannelSftp>() { @Override public void callback() { ChannelSftp channel = this.getResult(); // TODO check for '/' or '.' or '..' - only allow a name here not a path or a move try { String newpath = SftpFile.this.getFieldAsString("FullPath"); int pos = newpath.lastIndexOf('/'); if (pos > 0) newpath = newpath.substring(0, pos); if (newpath.length() > 1) newpath += "/"; newpath += name; channel.rename(SftpFile.this.getFieldAsString("FullPath"), newpath); SftpFile.this.setField("Name", name); SftpFile.this.setField("FullPath", newpath); newpath = SftpFile.this.getFieldAsString("Path"); pos = newpath.lastIndexOf('/'); if (pos > 0) newpath = newpath.substring(0, pos); if (newpath.length() > 1) newpath += "/"; newpath += name; SftpFile.this.setField("Path", newpath); } catch (Exception x) { // TODO log } finally { SftpFile.this.driver.releaseChannel(channel); } callback.completed(); } }); } @Override public void remove(final OperationCallback callback) { if (this.removed) { // TODO log callback.completed(); return; } SftpFile.this.driver.getChannel(new FuncCallback<ChannelSftp>() { @Override public void callback() { ChannelSftp channel = this.getResult(); try { channel.rm(SftpFile.this.getFieldAsString("FullPath")); SftpFile.this.removed = true; } catch (Exception x) { // TODO log } finally { SftpFile.this.driver.releaseChannel(channel); } callback.completed(); } }); } @Override public void setModificationTime(final DateTime time, final OperationCallback callback) { if (this.removed) { // TODO log callback.completed(); return; } SftpFile.this.driver.getChannel(new FuncCallback<ChannelSftp>() { @Override public void callback() { ChannelSftp channel = this.getResult(); try { int t = (int) (time.getMillis() / 1000); SftpFile.this.file.getAttrs().setACMODTIME(t, t); channel.setStat(SftpFile.this.getFieldAsString("FullPath"), SftpFile.this.file.getAttrs()); SftpFile.this.setField("Modified", time); } catch (Exception x) { // TODO log } finally { SftpFile.this.driver.releaseChannel(channel); } callback.completed(); } }); } @Override public void getAttribute(String name, FuncCallback<Struct> callback) { if ("Modified".equals(name)) { callback.setResult(new DateTimeStruct(this.getMofificationTime())); callback.completed(); return; } /* if (this.removed) { // TODO log } else { try { callback.setResult(this.driver.channel.get(this.getFieldAsString("FullPath"))); } catch (Exception x) { // TODO log } } * / callback.completed(); } @Override public void setAttribute(String name, Struct value, OperationCallback callback) { if ("Modified".equals(name)) { this.setModificationTime(Struct.objectToDateTime(value), callback); callback.completed(); return; } /* if (this.removed) { // TODO log } else { try { callback.setResult(this.driver.channel.get(this.getFieldAsString("FullPath"))); } catch (Exception x) { // TODO log } } * / callback.completed(); } */ }