/* * Decompiled with CFR 0.152. * * Could not load the following classes: * com.tridium.sys.transfer.TransferListener * com.tridium.sys.transfer.TransferResult * com.tridium.sys.transfer.TransferStrategy * com.tridium.util.BRestrictedFileSpace * javax.baja.file.BAbstractFileStore * javax.baja.file.BDirectory * javax.baja.file.BFileSpace * javax.baja.file.BFileSystem * javax.baja.file.BIDirectory * javax.baja.file.BIFile * javax.baja.file.BIFileStore * javax.baja.file.FilePath * javax.baja.file.FileUtil * javax.baja.nre.util.Array * javax.baja.security.BPermissions * javax.baja.security.PermissionException * javax.baja.sys.BAbsTime * javax.baja.sys.Context * javax.baja.sys.Sys * javax.baja.sys.Type */ package com.tridium.fox.sys.file; import com.tridium.fox.message.FoxMessage; import com.tridium.fox.message.FoxTuple; import com.tridium.fox.session.Fox; import com.tridium.fox.session.FoxCircuit; import com.tridium.fox.session.FoxRequest; import com.tridium.fox.session.FoxResponse; import com.tridium.fox.session.InvalidCommandException; import com.tridium.fox.sys.BFoxChannel; import com.tridium.fox.sys.BFoxClientConnection; import com.tridium.fox.sys.broker.TransferCodec; import com.tridium.fox.sys.file.BFoxFileSpace; import com.tridium.fox.sys.file.BFoxFileStore; import com.tridium.sys.transfer.TransferListener; import com.tridium.sys.transfer.TransferResult; import com.tridium.sys.transfer.TransferStrategy; import com.tridium.util.BRestrictedFileSpace; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import javax.baja.file.BAbstractFileStore; import javax.baja.file.BDirectory; import javax.baja.file.BFileSpace; import javax.baja.file.BFileSystem; import javax.baja.file.BIDirectory; import javax.baja.file.BIFile; import javax.baja.file.BIFileStore; import javax.baja.file.FilePath; import javax.baja.file.FileUtil; import javax.baja.nre.util.Array; import javax.baja.security.BPermissions; import javax.baja.security.PermissionException; import javax.baja.sys.BAbsTime; import javax.baja.sys.Context; import javax.baja.sys.Sys; import javax.baja.sys.Type; public class BFileChannel extends BFoxChannel { public static final Type TYPE = Sys.loadType((Class)(class$com$tridium$fox$sys$file$BFileChannel == null ? (class$com$tridium$fox$sys$file$BFileChannel = BFileChannel.class$("com.tridium.fox.sys.file.BFileChannel")) : class$com$tridium$fox$sys$file$BFileChannel)); public static int CHUNK_SIZE = 16384; private Array unrestrictedFilePaths = new Array(class$java$lang$String == null ? (class$java$lang$String = BFileChannel.class$("java.lang.String")) : class$java$lang$String); static /* synthetic */ Class class$com$tridium$fox$sys$file$BFileChannel; static /* synthetic */ Class class$java$lang$String; public Type getType() { return TYPE; } public BFileChannel() { super("file"); } public FoxResponse process(FoxRequest foxRequest) throws Exception { String string = foxRequest.command; if (string == "head") { return this.head(foxRequest); } if (string == "list") { return this.list(foxRequest); } if (string == "delete") { return this.delete(foxRequest); } if (string == "makeFile") { return this.makeFile(foxRequest); } if (string == "makeDir") { return this.makeDir(foxRequest); } if (string == "move") { return this.move(foxRequest); } if (string == "setLastModified") { return this.setLastModified(foxRequest); } if (string == "getCrc") { return this.getCrc(foxRequest); } throw new InvalidCommandException(string); } public void circuitOpened(FoxCircuit foxCircuit) throws Exception { String string = foxCircuit.command; if (string == "read") { this.read(foxCircuit); return; } if (string == "write") { this.write(foxCircuit); return; } if (string == "transfer") { this.transfer(foxCircuit); return; } throw new InvalidCommandException(string); } /* * WARNING - Removed try catching itself - possible behaviour change. */ public void sessionClosed(Throwable throwable) throws Exception { Array array = this.unrestrictedFilePaths; synchronized (array) { this.unrestrictedFilePaths.clear(); } } public BFoxFileStore head(BFoxFileSpace bFoxFileSpace, FilePath filePath) throws Exception { FoxResponse foxResponse; FoxRequest foxRequest = this.makeRequest("head"); foxRequest.add("path", filePath.getBody()); if (this.isTraceOn()) { this.trace("c:head \"" + filePath.getBody() + "\""); } if ((foxResponse = this.sendSync(foxRequest)) == null) { return null; } return BFileChannel.msgToStore(bFoxFileSpace, filePath, foxResponse); } public FoxResponse head(FoxRequest foxRequest) throws Exception { BIFile bIFile; FilePath filePath = new FilePath(foxRequest.getString("path")); if (this.isTraceOn()) { this.trace("s:head \"" + filePath.getBody() + "\""); } if ((bIFile = this.getFileSpaceForPath(filePath).findFile(filePath)) == null) { return null; } BPermissions bPermissions = this.getPermissionsFor(bIFile); if (!bPermissions.has(BPermissions.operatorRead)) { throw new PermissionException(); } FoxResponse foxResponse = new FoxResponse(foxRequest); BFileChannel.storeToMsg(bIFile.getStore(), bPermissions, foxResponse); return foxResponse; } public BFoxFileStore[] list(BFoxFileSpace bFoxFileSpace, FilePath filePath) throws Exception { if (this.isTraceOn()) { this.trace("c:list \"" + filePath.getBody() + "\""); } FoxRequest foxRequest = this.makeRequest("list"); foxRequest.add("path", filePath.getBody()); FoxResponse foxResponse = this.sendSync(foxRequest); FoxTuple[] foxTupleArray = foxResponse.list("file"); BFoxFileStore[] bFoxFileStoreArray = new BFoxFileStore[foxTupleArray.length]; for (int i = 0; i < bFoxFileStoreArray.length; ++i) { FoxMessage foxMessage = (FoxMessage)foxTupleArray[i]; String string = foxMessage.getString("name"); bFoxFileStoreArray[i] = BFileChannel.msgToStore(bFoxFileSpace, filePath.merge(string), foxMessage); } return bFoxFileStoreArray; } public FoxResponse list(FoxRequest foxRequest) throws Exception { FilePath filePath = new FilePath(foxRequest.getString("path")); if (this.isTraceOn()) { this.trace("s:list \"" + filePath + "\""); } FoxResponse foxResponse = new FoxResponse(foxRequest); BIFile bIFile = this.getFileSpaceForPath(filePath).resolveFile(filePath); if (!this.getPermissionsFor(bIFile).has(BPermissions.operatorRead)) { throw new PermissionException(); } if (bIFile instanceof BIDirectory) { BIDirectory bIDirectory = (BIDirectory)bIFile; BIFile[] bIFileArray = bIDirectory.listFiles(); for (int i = 0; i < bIFileArray.length; ++i) { BPermissions bPermissions = this.getPermissionsFor(bIFileArray[i]); if (!bPermissions.has(BPermissions.operatorRead) || BRestrictedFileSpace.INSTANCE.isBlacklisted(bIFileArray[i])) continue; FoxMessage foxMessage = new FoxMessage("file"); BFileChannel.storeToMsg(bIFileArray[i].getStore(), bPermissions, foxMessage); foxResponse.add(foxMessage); } } return foxResponse; } public void move(BFoxFileSpace bFoxFileSpace, FilePath filePath, FilePath filePath2) throws Exception { FoxRequest foxRequest = this.makeRequest("move"); foxRequest.add("from", filePath.getBody()); foxRequest.add("to", filePath2.getBody()); if (this.isTraceOn()) { this.trace("c:move \"" + filePath + "\" -> \"" + filePath2 + "\""); } this.sendSync(foxRequest); } public FoxResponse move(FoxRequest foxRequest) throws Exception { FilePath filePath = new FilePath(foxRequest.getString("from")); FilePath filePath2 = new FilePath(foxRequest.getString("to")); if (this.isTraceOn()) { this.trace("c:move \"" + filePath + "\" -> \"" + filePath2 + "\""); } BRestrictedFileSpace.INSTANCE.move(filePath, filePath2, this.getSessionContext()); return null; } public void delete(BFoxFileSpace bFoxFileSpace, FilePath filePath) throws Exception { FoxRequest foxRequest = this.makeRequest("delete"); foxRequest.add("path", filePath.getBody()); if (this.isTraceOn()) { this.trace("c:delete \"" + filePath.getBody() + "\""); } this.sendSync(foxRequest); } public FoxResponse delete(FoxRequest foxRequest) throws Exception { FilePath filePath = new FilePath(foxRequest.getString("path")); if (this.isTraceOn()) { this.trace("s:delete \"" + filePath.getBody() + "\""); } BRestrictedFileSpace.INSTANCE.delete(filePath, this.getSessionContext()); return null; } public BFoxFileStore makeFile(BFoxFileSpace bFoxFileSpace, FilePath filePath) throws Exception { FoxRequest foxRequest = this.makeRequest("makeFile"); foxRequest.add("path", filePath.getBody()); if (this.isTraceOn()) { this.trace("c:makeFile \"" + filePath.getBody() + "\""); } FoxResponse foxResponse = this.sendSync(foxRequest); return BFileChannel.msgToStore(bFoxFileSpace, filePath, foxResponse); } public FoxResponse makeFile(FoxRequest foxRequest) throws Exception { Context context; FilePath filePath = new FilePath(foxRequest.getString("path")); if (this.isTraceOn()) { this.trace("s:makeFile \"" + filePath.getBody() + "\""); } try { context = this.getSessionContext(); } catch (Exception exception) { context = null; } BIFile bIFile = this.getFileSpaceForPath(filePath).makeFile(filePath, context); BPermissions bPermissions = context != null ? this.getPermissionsFor(bIFile) : BPermissions.all; FoxResponse foxResponse = new FoxResponse(foxRequest); BFileChannel.storeToMsg(bIFile.getStore(), bPermissions, foxResponse); return foxResponse; } public BFoxFileStore makeDir(BFoxFileSpace bFoxFileSpace, FilePath filePath) throws Exception { FoxRequest foxRequest = this.makeRequest("makeDir"); foxRequest.add("path", filePath.getBody()); if (this.isTraceOn()) { this.trace("c:makeDir \"" + filePath.getBody() + "\""); } FoxResponse foxResponse = this.sendSync(foxRequest); return BFileChannel.msgToStore(bFoxFileSpace, filePath, foxResponse); } public FoxResponse makeDir(FoxRequest foxRequest) throws Exception { FilePath filePath = new FilePath(foxRequest.getString("path")); if (this.isTraceOn()) { this.trace("s:makeDir \"" + filePath.getBody() + "\""); } BDirectory bDirectory = this.getFileSpaceForPath(filePath).makeDir(filePath, this.getSessionContext()); BPermissions bPermissions = this.getPermissionsFor(bDirectory); FoxResponse foxResponse = new FoxResponse(foxRequest); BFileChannel.storeToMsg(bDirectory.getStore(), bPermissions, foxResponse); return foxResponse; } public TransferResult transfer(TransferStrategy transferStrategy) throws Exception { if (this.isTraceOn()) { this.trace("c:transfer"); transferStrategy.dump(); } FoxRequest foxRequest = this.makeRequest("transfer"); TransferCodec.transferToMessage(foxRequest, transferStrategy); FoxCircuit foxCircuit = this.openCircuit("transfer"); foxCircuit.writeMessage(foxRequest); while (true) { FoxMessage foxMessage = null; foxMessage = foxCircuit.readMessage(); String string = foxMessage.getString("s", null); if (string != null) { transferStrategy.updateStatus(string); continue; } if (foxMessage.getString("exception", null) != null) { throw Fox.exceptionTranslator.messageToException(foxMessage); } if (foxMessage.getBoolean("done", false)) break; } return null; } void transfer(FoxCircuit foxCircuit) throws Exception { try { Context context = this.getSessionContext(); FoxMessage foxMessage = foxCircuit.readMessage(); TransferStrategy transferStrategy = TransferCodec.messageToTransfer(foxMessage, context); if (this.isTraceOn()) { this.trace("s:transfer"); transferStrategy.dump(); } transferStrategy.setListener((TransferListener)new BFoxChannel.TransferStatusPipe(foxCircuit)); transferStrategy.transfer(); FoxMessage foxMessage2 = new FoxMessage(); foxMessage2.add("done", true); foxCircuit.writeMessage(foxMessage2); } catch (Exception exception) { exception.printStackTrace(); foxCircuit.writeMessage(Fox.exceptionTranslator.exceptionToMessage(exception)); } foxCircuit.close(); } public InputStream read(BFoxFileStore bFoxFileStore) throws Exception { FilePath filePath = bFoxFileStore.getFilePath(); if (this.isTraceOn()) { this.trace("c:read \"" + filePath.getBody() + "\""); } FoxCircuit foxCircuit = this.openCircuit("read"); FoxMessage foxMessage = new FoxMessage(); foxMessage.add("path", bFoxFileStore.getFilePath().getBody()); foxCircuit.writeMessage(foxMessage); foxCircuit.flush(); FoxMessage foxMessage2 = foxCircuit.readMessage(); long l = Long.parseLong(foxMessage2.getString("size", "-1")); if (l > -1L && l != bFoxFileStore.size) { bFoxFileStore.size = l; } return foxCircuit.getInputStream(); } /* * WARNING - Removed try catching itself - possible behaviour change. */ public void read(FoxCircuit foxCircuit) throws Exception { BIFile bIFile; FoxMessage foxMessage = foxCircuit.readMessage(); FilePath filePath = new FilePath(foxMessage.getString("path")); if (this.isTraceOn()) { this.trace("s:read \"" + filePath.getBody() + "\""); } if (!this.getPermissionsFor(bIFile = this.getFileSpaceForPath(filePath).resolveFile(filePath)).has(BPermissions.operatorRead)) { throw new PermissionException(); } long l = bIFile.getSize(); FoxMessage foxMessage2 = new FoxMessage(); foxMessage2.add("size", String.valueOf(l)); foxCircuit.writeMessage(foxMessage2); InputStream inputStream = bIFile.getInputStream(); OutputStream outputStream = foxCircuit.getOutputStream(); try { FileUtil.pipe((InputStream)inputStream, (long)l, (OutputStream)outputStream); } finally { inputStream.close(); foxCircuit.close(); } } public OutputStream write(BFoxFileStore bFoxFileStore) throws Exception { FilePath filePath = bFoxFileStore.getFilePath(); if (this.isTraceOn()) { this.trace("c:write \"" + filePath.getBody() + "\""); } FoxCircuit foxCircuit = this.openCircuit("write"); FoxMessage foxMessage = new FoxMessage(); foxMessage.add("path", bFoxFileStore.getFilePath().getBody()); foxCircuit.writeMessage(foxMessage); foxCircuit.flush(); return new ChunckedOutputStream(this, bFoxFileStore, foxCircuit); } /* * WARNING - Removed try catching itself - possible behaviour change. */ public void write(FoxCircuit foxCircuit) throws Exception { FoxMessage foxMessage = foxCircuit.readMessage(); FilePath filePath = new FilePath(foxMessage.getString("path")); if (this.isTraceOn()) { this.trace("s:write \"" + filePath.getBody() + "\""); } BIFile bIFile = this.getFileSpaceForPath(filePath).resolveFile(filePath); FoxMessage foxMessage2 = new FoxMessage(); if (!this.getPermissionsFor(bIFile, false).has(BPermissions.operatorWrite)) { foxMessage2.add("error", "No Permission"); foxCircuit.writeMessage(foxMessage2); return; } OutputStream outputStream = bIFile.getOutputStream(); boolean bl = true; try { FoxMessage foxMessage3; byte[] byArray; while ((byArray = (foxMessage3 = foxCircuit.readMessage()).getBlob("chunk")).length != 0) { outputStream.write(byArray); } bl = false; outputStream.close(); foxMessage2.add("size", String.valueOf(bIFile.getSize())); foxMessage2.add("modified", bIFile.getLastModified().getMillis()); foxCircuit.writeMessage(foxMessage2); } finally { if (bl) { outputStream.close(); } foxCircuit.close(); } } public boolean setLastModified(FilePath filePath, BAbsTime bAbsTime) throws Exception { Object object; FoxRequest foxRequest = this.makeRequest("setLastModified"); foxRequest.add("path", filePath.getBody()); foxRequest.add("lastModified", bAbsTime.getMillis()); if (this.isTraceOn()) { object = new StringBuffer(); ((StringBuffer)object).append("c:setLastModified \""); ((StringBuffer)object).append(filePath.getBody()); ((StringBuffer)object).append("\" ("); ((StringBuffer)object).append(bAbsTime); ((StringBuffer)object).append(")"); this.trace(((StringBuffer)object).toString()); } object = this.sendSync(foxRequest); return ((FoxMessage)object).getBoolean("done"); } public FoxResponse setLastModified(FoxRequest foxRequest) throws IOException { StringBuffer stringBuffer; FilePath filePath = new FilePath(foxRequest.getString("path")); BAbsTime bAbsTime = BAbsTime.make((long)foxRequest.getTime("lastModified")); if (this.isTraceOn()) { stringBuffer = new StringBuffer(); stringBuffer.append("s:setLastModified \""); stringBuffer.append(filePath.getBody()); stringBuffer.append("\" ("); stringBuffer.append(bAbsTime); stringBuffer.append(")"); this.trace(stringBuffer.toString()); } if ((stringBuffer = this.getFileSpaceForPath(filePath).resolveFile(filePath)).getStore().isReadonly()) { throw new IOException("File Store is readonly"); } if (!this.getPermissionsFor(stringBuffer).hasOperatorWrite()) { throw new PermissionException(); } boolean bl = false; if (!(stringBuffer.getStore() instanceof BAbstractFileStore)) { throw new IOException("Unsupported File Store"); } Object object = (BAbstractFileStore)stringBuffer.getStore(); bl = object.setLastModified(bAbsTime); object = new FoxResponse(foxRequest); ((FoxMessage)object).add("done", bl); return object; } public long getCrc(FilePath filePath) throws Exception { Object object; FoxRequest foxRequest = this.makeRequest("getCrc"); foxRequest.add("path", filePath.getBody()); if (this.isTraceOn()) { object = new StringBuffer(); ((StringBuffer)object).append("c:getCrc \""); ((StringBuffer)object).append(filePath.getBody()); ((StringBuffer)object).append("\""); this.trace(((StringBuffer)object).toString()); } object = this.sendSync(foxRequest); return ((FoxMessage)object).getTime("crc"); } public FoxResponse getCrc(FoxRequest foxRequest) throws IOException { StringBuffer stringBuffer; FilePath filePath = new FilePath(foxRequest.getString("path")); if (this.isTraceOn()) { stringBuffer = new StringBuffer(); stringBuffer.append("s:getCrc \""); stringBuffer.append(filePath.getBody()); stringBuffer.append("\""); this.trace(stringBuffer.toString()); } if (!this.getPermissionsFor(stringBuffer = this.getFileSpaceForPath(filePath).resolveFile(filePath)).hasOperatorRead()) { throw new PermissionException(); } long l = -1L; if (!(stringBuffer.getStore() instanceof BAbstractFileStore)) { throw new IOException("Unsupported File Store"); } Object object = (BAbstractFileStore)stringBuffer.getStore(); l = object.getCrc(); object = new FoxResponse(foxRequest); ((FoxMessage)object).add("crc", l); return object; } public static BFoxFileStore msgToStore(BFoxFileSpace bFoxFileSpace, FilePath filePath, FoxMessage foxMessage) throws IOException { BFoxFileStore bFoxFileStore = new BFoxFileStore(bFoxFileSpace, filePath); bFoxFileStore.isDirectory = foxMessage.getBoolean("dir"); bFoxFileStore.isReadonly = foxMessage.getBoolean("readonly"); bFoxFileStore.modified = BAbsTime.make((long)foxMessage.getTime("modified")); bFoxFileStore.size = Long.parseLong(foxMessage.getString("size")); bFoxFileStore.permissions = BPermissions.make((String)foxMessage.getString("permissions", "rw")); return bFoxFileStore; } public static void storeToMsg(BIFileStore bIFileStore, BPermissions bPermissions, FoxMessage foxMessage) { foxMessage.add("name", bIFileStore.getFileName()); foxMessage.add("dir", bIFileStore.isDirectory()); foxMessage.add("readonly", bIFileStore.isReadonly() || !bPermissions.has(BPermissions.operatorWrite)); foxMessage.add("modified", bIFileStore.getLastModified().getMillis()); foxMessage.add("size", String.valueOf(bIFileStore.getSize())); foxMessage.add("permissions", bPermissions.encodeToString()); } /* * WARNING - Removed try catching itself - possible behaviour change. */ public final Object fw(int n, Object object, Object object2, Object object3, Object object4) { if (n == 901) { String string = null; FilePath filePath = null; if (object instanceof String) { string = (String)object; filePath = new FilePath(string); } else if (object instanceof FilePath) { filePath = (FilePath)object; string = filePath.getBody(); } if (string != null && !BRestrictedFileSpace.INSTANCE.inScope(filePath)) { Array array = this.unrestrictedFilePaths; synchronized (array) { if (!this.unrestrictedFilePaths.contains((Object)string) && this.getConnection().isConnected()) { this.unrestrictedFilePaths.add((Object)string); } } } } else if (n == 902) { String string = null; if (object instanceof String) { string = (String)object; } else if (object instanceof FilePath) { string = ((FilePath)object).getBody(); } if (string != null) { Array array = this.unrestrictedFilePaths; synchronized (array) { this.unrestrictedFilePaths.remove((Object)string); } } } return super.fw(n, object, object2, object3, object4); } /* * WARNING - Removed try catching itself - possible behaviour change. */ private BFileSpace getFileSpaceForPath(FilePath filePath) { Array array = this.unrestrictedFilePaths; synchronized (array) { if (this.unrestrictedFilePaths.contains((Object)filePath.getBody())) { return BFileSystem.INSTANCE; } if (this.getConnection() instanceof BFoxClientConnection) { throw new PermissionException("Illegal file operation (server cannot make file request to client)"); } return BRestrictedFileSpace.INSTANCE; } } static /* synthetic */ Class class$(String string) { try { return Class.forName(string); } catch (ClassNotFoundException classNotFoundException) { throw new NoClassDefFoundError(classNotFoundException.getMessage()); } } static class ChunckedOutputStream extends OutputStream { BFileChannel channel; BFoxFileStore store; FoxCircuit circuit; byte[] buf = new byte[Fox.circuitChunkSize - 256]; int n; ChunckedOutputStream(BFileChannel bFileChannel, BFoxFileStore bFoxFileStore, FoxCircuit foxCircuit) { this.channel = bFileChannel; this.store = bFoxFileStore; this.circuit = foxCircuit; } public void write(int n) throws IOException { this.buf[this.n++] = (byte)(0xFF & n); if (this.n >= this.buf.length) { this.flush(); } } public void flush() throws IOException { if (this.n > 0) { FoxMessage foxMessage = new FoxMessage(); foxMessage.add("chunk", this.buf, this.n); this.writeMessage(foxMessage); this.n = 0; } } public void close() throws IOException { block7: { this.flush(); FoxMessage foxMessage = new FoxMessage(); foxMessage.add("chunk", this.buf, 0); this.writeMessage(foxMessage); FoxMessage foxMessage2 = this.readMessage(); this.circuit.close(); String string = foxMessage2.getString("error", null); if (string != null) { throw new IOException(string); } String string2 = foxMessage2.getString("size", null); if (string2 != null) { this.store.size = Long.parseLong(string2); this.store.modified = BAbsTime.make((long)foxMessage2.getTime("modified")); } else { try { FoxResponse foxResponse; FoxRequest foxRequest = this.channel.makeRequest("head"); foxRequest.add("path", this.store.getFilePath().getBody()); if (this.channel.isTraceOn()) { this.channel.trace("c:head \"" + this.store.getFilePath().getBody() + "\""); } if ((foxResponse = this.channel.sendSync(foxRequest)) != null && (string2 = foxResponse.getString("size", null)) != null) { this.store.size = Long.parseLong(string2); this.store.modified = BAbsTime.make((long)foxResponse.getTime("modified")); } } catch (Exception exception) { if (!this.channel.isTraceOn()) break block7; this.channel.trace("Error retrieving file info for \"" + this.store.getFilePath().getBody() + "\" " + exception.getMessage()); } } } } private FoxMessage readMessage() throws IOException { try { return this.circuit.readMessage(); } catch (IOException iOException) { throw iOException; } catch (Exception exception) { throw new IOException(exception.toString()); } } private void writeMessage(FoxMessage foxMessage) throws IOException { try { this.circuit.writeMessage(foxMessage); } catch (IOException iOException) { throw iOException; } catch (Exception exception) { throw new IOException(exception.toString()); } } } }