You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by gg...@apache.org on 2020/12/17 19:18:12 UTC

[commons-vfs] 02/02: Better internal name and sort methods in AB order.

This is an automated email from the ASF dual-hosted git repository.

ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-vfs.git

commit 3de2f64d0b81620c30d475108de1273b61460063
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Thu Dec 17 14:18:05 2020 -0500

    Better internal name and sort methods in AB order.
---
 .../commons/vfs2/provider/ftp/FtpFileObject.java   | 644 ++++++++++-----------
 1 file changed, 322 insertions(+), 322 deletions(-)

diff --git a/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/ftp/FtpFileObject.java b/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/ftp/FtpFileObject.java
index d2dd004..c141789 100644
--- a/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/ftp/FtpFileObject.java
+++ b/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/ftp/FtpFileObject.java
@@ -50,18 +50,93 @@ import org.apache.commons.vfs2.util.RandomAccessMode;
  */
 public class FtpFileObject extends AbstractFileObject<FtpFileSystem> {
 
+    /**
+     * An InputStream that monitors for end-of-file.
+     */
+    class FtpInputStream extends MonitorInputStream {
+        private final FtpClient client;
+
+        public FtpInputStream(final FtpClient client, final InputStream in) {
+            super(in);
+            this.client = client;
+        }
+
+        public FtpInputStream(final FtpClient client, final InputStream in, final int bufferSize) {
+            super(in, bufferSize);
+            this.client = client;
+        }
+
+        void abort() throws IOException {
+            client.abort();
+            close();
+        }
+
+        private boolean isTransferAbortedOkReplyCode() throws IOException {
+            final List<Integer> transferAbortedOkReplyCodes = FtpFileSystemConfigBuilder
+                .getInstance()
+                .getTransferAbortedOkReplyCodes(getAbstractFileSystem().getFileSystemOptions());
+            return transferAbortedOkReplyCodes != null && transferAbortedOkReplyCodes.contains(client.getReplyCode());
+        }
+
+        /**
+         * Called after the stream has been closed.
+         */
+        @Override
+        protected void onClose() throws IOException {
+            final boolean ok;
+            try {
+                ok = client.completePendingCommand() || isTransferAbortedOkReplyCode();
+            } finally {
+                getAbstractFileSystem().putClient(client);
+            }
+
+            if (!ok) {
+                throw new FileSystemException("vfs.provider.ftp/finish-get.error", getName());
+            }
+        }
+    }
+    /**
+     * An OutputStream that monitors for end-of-file.
+     */
+    private class FtpOutputStream extends MonitorOutputStream {
+        private final FtpClient client;
+
+        public FtpOutputStream(final FtpClient client, final OutputStream outstr) {
+            super(outstr);
+            this.client = client;
+        }
+
+        /**
+         * Called after this stream is closed.
+         */
+        @Override
+        protected void onClose() throws IOException {
+            final boolean ok;
+            try {
+                ok = client.completePendingCommand();
+            } finally {
+                getAbstractFileSystem().putClient(client);
+            }
+
+            if (!ok) {
+                throw new FileSystemException("vfs.provider.ftp/finish-put.error", getName());
+            }
+        }
+    }
     private static final long DEFAULT_TIMESTAMP = 0L;
     private static final Map<String, FTPFile> EMPTY_FTP_FILE_MAP = Collections
             .unmodifiableMap(new TreeMap<String, FTPFile>());
+
     private static final FTPFile UNKNOWN = new FTPFile();
-    private static final Log log = LogFactory.getLog(FtpFileObject.class);
 
+    private static final Log log = LogFactory.getLog(FtpFileObject.class);
     private final String relPath;
-
     // Cached info
     private volatile FTPFile ftpFile;
     private volatile Map<String, FTPFile> children;
+
     private volatile FileObject linkDestination;
+
     private final AtomicBoolean inRefresh = new AtomicBoolean();
 
     protected FtpFileObject(final AbstractFileName name, final FtpFileSystem fileSystem, final FileName rootName)
@@ -80,27 +155,69 @@ public class FtpFileObject extends AbstractFileObject<FtpFileSystem> {
     }
 
     /**
-     * Called by child file objects, to locate their ftp file info.
-     *
-     * @param name the file name in its native form ie. without URI stuff (%nn)
-     * @param flush recreate children cache
+     * Attaches this file object to its file resource.
      */
-    private FTPFile getChildFile(final String name, final boolean flush) throws IOException {
-        /*
-         * If we should flush cached children, clear our children map unless we're in the middle of a refresh in which
-         * case we've just recently refreshed our children. No need to do it again when our children are refresh()ed,
-         * calling getChildFile() for themselves from within getInfo(). See getChildren().
-         */
-        if (flush && !inRefresh.get()) {
-            children = null;
+    @Override
+    protected void doAttach() throws IOException {
+        // Get the parent folder to find the info for this file
+        // VFS-210 getInfo(false);
+    }
+
+    /**
+     * Creates this file as a folder.
+     */
+    @Override
+    protected void doCreateFolder() throws Exception {
+        final boolean ok;
+        final FtpClient client = getAbstractFileSystem().getClient();
+        try {
+            ok = client.makeDirectory(relPath);
+        } finally {
+            getAbstractFileSystem().putClient(client);
         }
 
-        // List the children of this file
-        doGetChildren();
+        if (!ok) {
+            throw new FileSystemException("vfs.provider.ftp/create-folder.error", getName());
+        }
+    }
 
-        // Look for the requested child
-        // VFS-210 adds the null check.
-        return children != null ? children.get(name) : null;
+    /**
+     * Deletes the file.
+     */
+    @Override
+    protected void doDelete() throws Exception {
+        synchronized (getFileSystem()) {
+            if (this.ftpFile != null) {
+                final boolean ok;
+                final FtpClient ftpClient = getAbstractFileSystem().getClient();
+                try {
+                    if (this.ftpFile.isDirectory()) {
+                        ok = ftpClient.removeDirectory(relPath);
+                    } else {
+                        ok = ftpClient.deleteFile(relPath);
+                    }
+                } finally {
+                    getAbstractFileSystem().putClient(ftpClient);
+                }
+
+                if (!ok) {
+                    throw new FileSystemException("vfs.provider.ftp/delete-file.error", getName());
+                }
+                this.ftpFile = null;
+            }
+            this.children = EMPTY_FTP_FILE_MAP;
+        }
+    }
+
+    /**
+     * Detaches this file object from its file resource.
+     */
+    @Override
+    protected void doDetach() {
+        synchronized (getFileSystem()) {
+            this.ftpFile = null;
+            this.children = null;
+        }
     }
 
     /**
@@ -144,102 +261,95 @@ public class FtpFileObject extends AbstractFileObject<FtpFileSystem> {
     }
 
     /**
-     * Attaches this file object to its file resource.
+     * Returns the size of the file content (in bytes).
      */
     @Override
-    protected void doAttach() throws IOException {
-        // Get the parent folder to find the info for this file
-        // VFS-210 getInfo(false);
-    }
-
-    /**
-     * Fetches the info for this file.
-     */
-    private void getInfo(final boolean flush) throws IOException {
+    protected long doGetContentSize() throws Exception {
         synchronized (getFileSystem()) {
-            final FtpFileObject parent = (FtpFileObject) FileObjectUtils.getAbstractFileObject(getParent());
-            FTPFile newFileInfo;
-            if (parent != null) {
-                newFileInfo = parent.getChildFile(UriParser.decode(getName().getBaseName()), flush);
-            } else {
-                // Assume the root is a directory and exists
-                newFileInfo = new FTPFile();
-                newFileInfo.setType(FTPFile.DIRECTORY_TYPE);
-            }
-
-            if (newFileInfo == null) {
-                this.ftpFile = UNKNOWN;
-            } else {
-                this.ftpFile = newFileInfo;
+            if (this.ftpFile == null) {
+                return 0;
             }
-        }}
-
-    /**
-     * @throws FileSystemException if an error occurs.
-     */
-    @Override
-    public void refresh() throws FileSystemException {
-        if (inRefresh.compareAndSet(false, true)) {
-            try {
-                super.refresh();
-                synchronized (getFileSystem()) {
-                    this.ftpFile = null;
+            if (this.ftpFile.isSymbolicLink()) {
+                final FileObject linkDest = getLinkDestination();
+                // VFS-437: Try to avoid a recursion loop.
+                if (this.isCircular(linkDest)) {
+                    return this.ftpFile.getSize();
                 }
-                /*
-                 * VFS-210 try { // this will tell the parent to recreate its children collection getInfo(true); } catch
-                 * (IOException e) { throw new FileSystemException(e); }
-                 */
-            } finally {
-                inRefresh.set(false);
+                return linkDest.getContent().getSize();
             }
+            return this.ftpFile.getSize();
         }
     }
 
     /**
-     * Detaches this file object from its file resource.
+     * Creates an input stream to read the file content from.
      */
     @Override
-    protected void doDetach() {
-        synchronized (getFileSystem()) {
-            this.ftpFile = null;
-            this.children = null;
+    protected InputStream doGetInputStream(final int bufferSize) throws Exception {
+        final FtpClient client = getAbstractFileSystem().getClient();
+        try {
+            final InputStream inputStream = client.retrieveFileStream(relPath, 0);
+            // VFS-210
+            if (inputStream == null) {
+                throw new FileNotFoundException(getName().toString());
+            }
+            return new FtpInputStream(client, inputStream, bufferSize);
+        } catch (final Exception e) {
+            getAbstractFileSystem().putClient(client);
+            throw e;
         }
     }
 
     /**
-     * Called when the children of this file change.
+     * get the last modified time on an ftp file
+     *
+     * @see org.apache.commons.vfs2.provider.AbstractFileObject#doGetLastModifiedTime()
      */
     @Override
-    protected void onChildrenChanged(final FileName child, final FileType newType) {
-        if (children != null && newType.equals(FileType.IMAGINARY)) {
-            try {
-                children.remove(UriParser.decode(child.getBaseName()));
-            } catch (final FileSystemException e) {
-                throw new RuntimeException(e.getMessage());
+    protected long doGetLastModifiedTime() throws Exception {
+        synchronized (getFileSystem()) {
+            if (this.ftpFile == null) {
+                return DEFAULT_TIMESTAMP;
             }
-        } else {
-            // if child was added we have to rescan the children
-            // TODO - get rid of this
-            children = null;
+            if (this.ftpFile.isSymbolicLink()) {
+                final FileObject linkDest = getLinkDestination();
+                // VFS-437: Try to avoid a recursion loop.
+                if (this.isCircular(linkDest)) {
+                    return getTimestamp();
+                }
+                return linkDest.getContent().getLastModifiedTime();
+            }
+            return getTimestamp();
         }
     }
 
     /**
-     * Called when the type or content of this file changes.
+     * Creates an output stream to write the file content to.
      */
     @Override
-    protected void onChange() throws IOException {
-        children = null;
-
-        if (getType().equals(FileType.IMAGINARY)) {
-            // file is deleted, avoid server lookup
-            synchronized (getFileSystem()) {
-                this.ftpFile = UNKNOWN;
+    protected OutputStream doGetOutputStream(final boolean bAppend) throws Exception {
+        final FtpClient client = getAbstractFileSystem().getClient();
+        try {
+            OutputStream out = null;
+            if (bAppend) {
+                out = client.appendFileStream(relPath);
+            } else {
+                out = client.storeFileStream(relPath);
             }
-            return;
+
+            FileSystemException.requireNonNull(out, "vfs.provider.ftp/output-error.debug", this.getName(),
+                    client.getReplyString());
+
+            return new FtpOutputStream(client, out);
+        } catch (final Exception e) {
+            getAbstractFileSystem().putClient(client);
+            throw e;
         }
+    }
 
-        getInfo(true);
+    @Override
+    protected RandomAccessContent doGetRandomAccessContent(final RandomAccessMode mode) throws Exception {
+        return new FtpRandomAccessContent(this, mode);
     }
 
     /**
@@ -250,7 +360,7 @@ public class FtpFileObject extends AbstractFileObject<FtpFileSystem> {
         // VFS-210
         synchronized (getFileSystem()) {
             if (this.ftpFile == null) {
-                getInfo(false);
+                setFTPFile(false);
             }
 
             if (this.ftpFile == UNKNOWN) {
@@ -276,67 +386,6 @@ public class FtpFileObject extends AbstractFileObject<FtpFileSystem> {
         throw new FileSystemException("vfs.provider.ftp/get-type.error", getName());
     }
 
-    private FileObject getLinkDestination() throws FileSystemException {
-        if (linkDestination == null) {
-            final String path;
-            synchronized (getFileSystem()) {
-                path = this.ftpFile == null ? null : this.ftpFile.getLink();
-            }
-            final FileName parent = getName().getParent();
-            final FileName relativeTo = parent == null ? getName() : parent;
-            final FileName linkDestinationName = getFileSystem().getFileSystemManager().resolveName(relativeTo, path);
-            linkDestination = getFileSystem().resolveFile(linkDestinationName);
-        }
-        return linkDestination;
-    }
-
-    @Override
-    protected FileObject[] doListChildrenResolved() throws Exception {
-        synchronized (getFileSystem()) {
-            if (this.ftpFile != null && this.ftpFile.isSymbolicLink()) {
-                final FileObject linkDest = getLinkDestination();
-                // VFS-437: Try to avoid a recursion loop.
-                if (this.isCircular(linkDest)) {
-                    return null;
-                }
-                return linkDest.getChildren();
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Returns the file's list of children.
-     *
-     * @return The list of children
-     * @throws FileSystemException If there was a problem listing children
-     * @see AbstractFileObject#getChildren()
-     * @since 2.0
-     */
-    @Override
-    public FileObject[] getChildren() throws FileSystemException {
-        try {
-            if (doGetType() != FileType.FOLDER) {
-                throw new FileNotFolderException(getName());
-            }
-        } catch (final Exception ex) {
-            throw new FileNotFolderException(getName(), ex);
-        }
-
-        try {
-            /*
-             * Wrap our parent implementation, noting that we're refreshing so that we don't refresh() ourselves and
-             * each of our parents for each children. Note that refresh() will list children. Meaning, if if this file
-             * has C children, P parents, there will be (C * P) listings made with (C * (P + 1)) refreshes, when there
-             * should really only be 1 listing and C refreshes.
-             */
-            this.inRefresh.set(true);
-            return super.getChildren();
-        } finally {
-            this.inRefresh.set(false);
-        }
-    }
-
     /**
      * Lists the children of the file.
      */
@@ -356,32 +405,19 @@ public class FtpFileObject extends AbstractFileObject<FtpFileSystem> {
         return UriParser.encode(childNames);
     }
 
-    /**
-     * Deletes the file.
-     */
     @Override
-    protected void doDelete() throws Exception {
+    protected FileObject[] doListChildrenResolved() throws Exception {
         synchronized (getFileSystem()) {
-            if (this.ftpFile != null) {
-                final boolean ok;
-                final FtpClient ftpClient = getAbstractFileSystem().getClient();
-                try {
-                    if (this.ftpFile.isDirectory()) {
-                        ok = ftpClient.removeDirectory(relPath);
-                    } else {
-                        ok = ftpClient.deleteFile(relPath);
-                    }
-                } finally {
-                    getAbstractFileSystem().putClient(ftpClient);
-                }
-
-                if (!ok) {
-                    throw new FileSystemException("vfs.provider.ftp/delete-file.error", getName());
+            if (this.ftpFile != null && this.ftpFile.isSymbolicLink()) {
+                final FileObject linkDest = getLinkDestination();
+                // VFS-437: Try to avoid a recursion loop.
+                if (this.isCircular(linkDest)) {
+                    return null;
                 }
-                this.ftpFile = null;
+                return linkDest.getChildren();
             }
-            this.children = EMPTY_FTP_FILE_MAP;
         }
+        return null;
     }
 
     /**
@@ -409,115 +445,88 @@ public class FtpFileObject extends AbstractFileObject<FtpFileSystem> {
     }
 
     /**
-     * Creates this file as a folder.
+     * Called by child file objects, to locate their ftp file info.
+     *
+     * @param name the file name in its native form ie. without URI stuff (%nn)
+     * @param flush recreate children cache
      */
-    @Override
-    protected void doCreateFolder() throws Exception {
-        final boolean ok;
-        final FtpClient client = getAbstractFileSystem().getClient();
-        try {
-            ok = client.makeDirectory(relPath);
-        } finally {
-            getAbstractFileSystem().putClient(client);
+    private FTPFile getChildFile(final String name, final boolean flush) throws IOException {
+        /*
+         * If we should flush cached children, clear our children map unless we're in the middle of a refresh in which
+         * case we've just recently refreshed our children. No need to do it again when our children are refresh()ed,
+         * calling getChildFile() for themselves from within getInfo(). See getChildren().
+         */
+        if (flush && !inRefresh.get()) {
+            children = null;
         }
 
-        if (!ok) {
-            throw new FileSystemException("vfs.provider.ftp/create-folder.error", getName());
-        }
-    }
+        // List the children of this file
+        doGetChildren();
 
-    /**
-     * Returns the size of the file content (in bytes).
-     */
-    @Override
-    protected long doGetContentSize() throws Exception {
-        synchronized (getFileSystem()) {
-            if (this.ftpFile == null) {
-                return 0;
-            }
-            if (this.ftpFile.isSymbolicLink()) {
-                final FileObject linkDest = getLinkDestination();
-                // VFS-437: Try to avoid a recursion loop.
-                if (this.isCircular(linkDest)) {
-                    return this.ftpFile.getSize();
-                }
-                return linkDest.getContent().getSize();
-            }
-            return this.ftpFile.getSize();
-        }
+        // Look for the requested child
+        // VFS-210 adds the null check.
+        return children != null ? children.get(name) : null;
     }
 
     /**
-     * get the last modified time on an ftp file
+     * Returns the file's list of children.
      *
-     * @see org.apache.commons.vfs2.provider.AbstractFileObject#doGetLastModifiedTime()
+     * @return The list of children
+     * @throws FileSystemException If there was a problem listing children
+     * @see AbstractFileObject#getChildren()
+     * @since 2.0
      */
     @Override
-    protected long doGetLastModifiedTime() throws Exception {
-        synchronized (getFileSystem()) {
-            if (this.ftpFile == null) {
-                return DEFAULT_TIMESTAMP;
-            }
-            if (this.ftpFile.isSymbolicLink()) {
-                final FileObject linkDest = getLinkDestination();
-                // VFS-437: Try to avoid a recursion loop.
-                if (this.isCircular(linkDest)) {
-                    return getTimestamp();
-                }
-                return linkDest.getContent().getLastModifiedTime();
+    public FileObject[] getChildren() throws FileSystemException {
+        try {
+            if (doGetType() != FileType.FOLDER) {
+                throw new FileNotFolderException(getName());
             }
-            return getTimestamp();
+        } catch (final Exception ex) {
+            throw new FileNotFolderException(getName(), ex);
         }
-    }
 
-    /**
-     * Creates an input stream to read the file content from.
-     */
-    @Override
-    protected InputStream doGetInputStream(final int bufferSize) throws Exception {
-        final FtpClient client = getAbstractFileSystem().getClient();
         try {
-            final InputStream inputStream = client.retrieveFileStream(relPath, 0);
-            // VFS-210
-            if (inputStream == null) {
-                throw new FileNotFoundException(getName().toString());
-            }
-            return new FtpInputStream(client, inputStream, bufferSize);
-        } catch (final Exception e) {
-            getAbstractFileSystem().putClient(client);
-            throw e;
+            /*
+             * Wrap our parent implementation, noting that we're refreshing so that we don't refresh() ourselves and
+             * each of our parents for each children. Note that refresh() will list children. Meaning, if if this file
+             * has C children, P parents, there will be (C * P) listings made with (C * (P + 1)) refreshes, when there
+             * should really only be 1 listing and C refreshes.
+             */
+            this.inRefresh.set(true);
+            return super.getChildren();
+        } finally {
+            this.inRefresh.set(false);
         }
     }
 
-    @Override
-    protected RandomAccessContent doGetRandomAccessContent(final RandomAccessMode mode) throws Exception {
-        return new FtpRandomAccessContent(this, mode);
-    }
-
-    /**
-     * Creates an output stream to write the file content to.
-     */
-    @Override
-    protected OutputStream doGetOutputStream(final boolean bAppend) throws Exception {
+    FtpInputStream getInputStream(final long filePointer) throws IOException {
         final FtpClient client = getAbstractFileSystem().getClient();
         try {
-            OutputStream out = null;
-            if (bAppend) {
-                out = client.appendFileStream(relPath);
-            } else {
-                out = client.storeFileStream(relPath);
-            }
-
-            FileSystemException.requireNonNull(out, "vfs.provider.ftp/output-error.debug", this.getName(),
+            final InputStream instr = client.retrieveFileStream(relPath, filePointer);
+            FileSystemException.requireNonNull(instr, "vfs.provider.ftp/input-error.debug", this.getName(),
                     client.getReplyString());
-
-            return new FtpOutputStream(client, out);
-        } catch (final Exception e) {
+            return new FtpInputStream(client, instr);
+        } catch (final IOException e) {
             getAbstractFileSystem().putClient(client);
             throw e;
         }
     }
 
+    private FileObject getLinkDestination() throws FileSystemException {
+        if (linkDestination == null) {
+            final String path;
+            synchronized (getFileSystem()) {
+                path = this.ftpFile == null ? null : this.ftpFile.getLink();
+            }
+            final FileName parent = getName().getParent();
+            final FileName relativeTo = parent == null ? getName() : parent;
+            final FileName linkDestinationName = getFileSystem().getFileSystemManager().resolveName(relativeTo, path);
+            linkDestination = getFileSystem().resolveFile(linkDestinationName);
+        }
+        return linkDestination;
+    }
+
     String getRelPath() {
         return relPath;
     }
@@ -534,91 +543,82 @@ public class FtpFileObject extends AbstractFileObject<FtpFileSystem> {
         return linkDest.getName().getPathDecoded().equals(this.getName().getPathDecoded());
     }
 
-    FtpInputStream getInputStream(final long filePointer) throws IOException {
-        final FtpClient client = getAbstractFileSystem().getClient();
-        try {
-            final InputStream instr = client.retrieveFileStream(relPath, filePointer);
-            FileSystemException.requireNonNull(instr, "vfs.provider.ftp/input-error.debug", this.getName(),
-                    client.getReplyString());
-            return new FtpInputStream(client, instr);
-        } catch (final IOException e) {
-            getAbstractFileSystem().putClient(client);
-            throw e;
-        }
-    }
-
     /**
-     * An InputStream that monitors for end-of-file.
+     * Called when the type or content of this file changes.
      */
-    class FtpInputStream extends MonitorInputStream {
-        private final FtpClient client;
+    @Override
+    protected void onChange() throws IOException {
+        children = null;
 
-        public FtpInputStream(final FtpClient client, final InputStream in) {
-            super(in);
-            this.client = client;
+        if (getType().equals(FileType.IMAGINARY)) {
+            // file is deleted, avoid server lookup
+            synchronized (getFileSystem()) {
+                this.ftpFile = UNKNOWN;
+            }
+            return;
         }
 
-        public FtpInputStream(final FtpClient client, final InputStream in, final int bufferSize) {
-            super(in, bufferSize);
-            this.client = client;
-        }
+        setFTPFile(true);
+    }
 
-        void abort() throws IOException {
-            client.abort();
-            close();
+    /**
+     * Called when the children of this file change.
+     */
+    @Override
+    protected void onChildrenChanged(final FileName child, final FileType newType) {
+        if (children != null && newType.equals(FileType.IMAGINARY)) {
+            try {
+                children.remove(UriParser.decode(child.getBaseName()));
+            } catch (final FileSystemException e) {
+                throw new RuntimeException(e.getMessage());
+            }
+        } else {
+            // if child was added we have to rescan the children
+            // TODO - get rid of this
+            children = null;
         }
+    }
 
-        /**
-         * Called after the stream has been closed.
-         */
-        @Override
-        protected void onClose() throws IOException {
-            final boolean ok;
+    /**
+     * @throws FileSystemException if an error occurs.
+     */
+    @Override
+    public void refresh() throws FileSystemException {
+        if (inRefresh.compareAndSet(false, true)) {
             try {
-                ok = client.completePendingCommand() || isTransferAbortedOkReplyCode();
+                super.refresh();
+                synchronized (getFileSystem()) {
+                    this.ftpFile = null;
+                }
+                /*
+                 * VFS-210 try { // this will tell the parent to recreate its children collection getInfo(true); } catch
+                 * (IOException e) { throw new FileSystemException(e); }
+                 */
             } finally {
-                getAbstractFileSystem().putClient(client);
-            }
-
-            if (!ok) {
-                throw new FileSystemException("vfs.provider.ftp/finish-get.error", getName());
+                inRefresh.set(false);
             }
         }
-
-        private boolean isTransferAbortedOkReplyCode() throws IOException {
-            final List<Integer> transferAbortedOkReplyCodes = FtpFileSystemConfigBuilder
-                .getInstance()
-                .getTransferAbortedOkReplyCodes(getAbstractFileSystem().getFileSystemOptions());
-            return transferAbortedOkReplyCodes != null && transferAbortedOkReplyCodes.contains(client.getReplyCode());
-        }
     }
 
     /**
-     * An OutputStream that monitors for end-of-file.
+     * Sets the internal FTPFile for this instance.
      */
-    private class FtpOutputStream extends MonitorOutputStream {
-        private final FtpClient client;
-
-        public FtpOutputStream(final FtpClient client, final OutputStream outstr) {
-            super(outstr);
-            this.client = client;
-        }
-
-        /**
-         * Called after this stream is closed.
-         */
-        @Override
-        protected void onClose() throws IOException {
-            final boolean ok;
-            try {
-                ok = client.completePendingCommand();
-            } finally {
-                getAbstractFileSystem().putClient(client);
+    private void setFTPFile(final boolean flush) throws IOException {
+        synchronized (getFileSystem()) {
+            final FtpFileObject parent = (FtpFileObject) FileObjectUtils.getAbstractFileObject(getParent());
+            FTPFile newFileInfo;
+            if (parent != null) {
+                newFileInfo = parent.getChildFile(UriParser.decode(getName().getBaseName()), flush);
+            } else {
+                // Assume the root is a directory and exists
+                newFileInfo = new FTPFile();
+                newFileInfo.setType(FTPFile.DIRECTORY_TYPE);
             }
 
-            if (!ok) {
-                throw new FileSystemException("vfs.provider.ftp/finish-put.error", getName());
+            if (newFileInfo == null) {
+                this.ftpFile = UNKNOWN;
+            } else {
+                this.ftpFile = newFileInfo;
             }
-        }
-    }
+        }}
 }