Package jenkins.util

Class VirtualFile

  • All Implemented Interfaces:
    Serializable, Comparable<VirtualFile>

    public abstract class VirtualFile
    extends Object
    implements Comparable<VirtualFile>, Serializable
    Abstraction over File, FilePath, or other items such as network resources or ZIP entries. Assumed to be read-only and makes very limited assumptions, just enough to display content and traverse directories.

    To obtain a VirtualFile representation for an existing file, use forFile(File) or FilePath.toVirtualFile()

    How are VirtualFile and FilePath different?

    FilePath abstracts away Files on machines that are connected over Channel, whereas VirtualFile makes no assumption about where the actual files are, or whether there really exists Files somewhere. This makes VirtualFile more abstract.

    Opening files from other machines

    While VirtualFile is marked Serializable, it is not safe in general to transfer over a Remoting channel. (For example, an implementation from forFilePath(hudson.FilePath) could be sent on the same channel, but an implementation from forFile(java.io.File) will not.) Thus callers should assume that methods such as open() will work only on the node on which the object was created.

    Since some implementations may in fact use external file storage, callers may request optional APIs to access those services more efficiently. Otherwise, for example, a plugin copying a file previously saved by ArtifactManager to an external storage service which tunneled a stream from open() using RemoteInputStream would wind up transferring the file from the service to the Jenkins master and then on to an agent. Similarly, if DirectoryBrowserSupport rendered a link to an in-Jenkins URL, a large file could be transferred from the service to the Jenkins master and then on to the browser. To avoid this overhead, callers may check whether an implementation supports toExternalURL().

    Since:
    1.532
    See Also:
    DirectoryBrowserSupport, FilePath, Serialized Form
    • Constructor Detail

      • VirtualFile

        public VirtualFile()
    • Method Detail

      • getName

        @NonNull
        public abstract String getName()
        Gets the base name, meaning just the last portion of the path name without any directories. For a “root directory” this may be the empty string.
        Returns:
        a simple name (no slashes)
      • toURI

        @NonNull
        public abstract URI toURI()
        Gets a URI. Should at least uniquely identify this virtual file within its root, but not necessarily globally.

        When toExternalURL() is implemented, that same value could be used here, unless some sort of authentication is also embedded.

        Returns:
        a URI (need not be absolute)
      • getParent

        public abstract VirtualFile getParent()
        Gets the parent file. Need only operate within the originally given root.
        Returns:
        the parent
      • isDirectory

        public abstract boolean isDirectory()
                                     throws IOException
        Checks whether this file exists and is a directory.
        Returns:
        true if it is a directory, false if a file or nonexistent
        Throws:
        IOException - in case checking status failed
      • isFile

        public abstract boolean isFile()
                                throws IOException
        Checks whether this file exists and is a plain file.
        Returns:
        true if it is a file, false if a directory or nonexistent
        Throws:
        IOException - in case checking status failed
      • readLink

        @CheckForNull
        public String readLink()
                        throws IOException
        If this file is a symlink, returns the link target.

        The default implementation always returns null. Some implementations may not support symlinks under any conditions.

        Returns:
        a target (typically a relative path in some format), or null if this is not a link
        Throws:
        IOException - if reading the link, or even determining whether this file is a link, failed
        Since:
        2.118
      • exists

        public abstract boolean exists()
                                throws IOException
        Checks whether this file exists. The behavior is undefined for symlinks; if in doubt, check readLink() first.
        Returns:
        true if it is a plain file or directory, false if nonexistent
        Throws:
        IOException - in case checking status failed
      • list

        @NonNull
        public abstract VirtualFile[] list()
                                    throws IOException
        Lists children of this directory. Only one level deep.
        Returns:
        a list of children (files and subdirectories); empty for a file or nonexistent directory
        Throws:
        IOException - if this directory exists but listing was not possible for some other reason
      • list

        @Restricted(org.kohsuke.accmod.restrictions.NoExternalUse.class)
        @NonNull
        public VirtualFile[] list​(OpenOption... openOptions)
                           throws IOException
        Lists children of this directory. Only one level deep. This is intended to allow the caller to provide LinkOption.NOFOLLOW_LINKS to ignore symlinks. However, this cannot be enforced. The base implementation here in VirtualFile ignores the openOptions. Some VirtualFile subclasses may not be able to provide an implementation in which NOFOLLOW_LINKS is used or makes sense. Implementations are free to ignore openOptions. Some subclasses of VirtualFile may not have a concept of symlinks.
        Parameters:
        openOptions - the options to apply when opening.
        Returns:
        a list of children (files and subdirectories); empty for a file or nonexistent directory
        Throws:
        IOException - if it could not be opened
      • supportsQuickRecursiveListing

        @Restricted(org.kohsuke.accmod.restrictions.NoExternalUse.class)
        public boolean supportsQuickRecursiveListing()
      • hasSymlink

        @Restricted(org.kohsuke.accmod.restrictions.NoExternalUse.class)
        public boolean hasSymlink​(OpenOption... openOptions)
                           throws IOException
        Determines when a VirtualFile has a recognized symlink. A recognized symlink can be the file itself or any containing directory between it and the optional root directory. If there is no provided root directory then only the file itself is considered. This base implementation ignores the existence of symlinks.
        Parameters:
        openOptions - the various open options to apply to the operation.
        Returns:
        True if the file is a symlink or is referenced within a containing symlink. directory before reaching the root directory.
        Throws:
        IOException - If there is a problem accessing the file.
      • listOnlyDescendants

        @Restricted(org.kohsuke.accmod.restrictions.NoExternalUse.class)
        @NonNull
        public List<VirtualFile> listOnlyDescendants()
                                              throws IOException
        Lists only the children that are descendant of the root directory (not necessarily the current VirtualFile). Only one level deep.
        Returns:
        a list of descendant children (files and subdirectories); empty for a file or nonexistent directory
        Throws:
        IOException - if this directory exists but listing was not possible for some other reason
      • list

        @NonNull
        public Collection<String> list​(@NonNull
                                       String includes,
                                       @CheckForNull
                                       String excludes,
                                       boolean useDefaultExcludes)
                                throws IOException
        Lists recursive files of this directory with pattern matching.

        The default implementation calls list() recursively inside run(hudson.remoting.Callable<V, java.io.IOException>) and applies filtering to the result. Implementations may wish to override this more efficiently.

        Parameters:
        includes - comma-separated Ant-style globs as per Util.createFileSet(File, String, String) using / as a path separator; the empty string means no matches (use SelectorUtils.DEEP_TREE_MATCH if you want to match everything except some excludes)
        excludes - optional excludes in similar format to includes
        useDefaultExcludes - as per AbstractFileSet.setDefaultexcludes(boolean)
        Returns:
        a list of /-separated relative names of children (files directly inside or in subdirectories)
        Throws:
        IOException - if this is not a directory, or listing was not possible for some other reason
        Since:
        2.118
      • list

        @Restricted(org.kohsuke.accmod.restrictions.NoExternalUse.class)
        @NonNull
        public Collection<String> list​(@NonNull
                                       String includes,
                                       @CheckForNull
                                       String excludes,
                                       boolean useDefaultExcludes,
                                       OpenOption... openOptions)
                                throws IOException
        Lists recursive files of this directory with pattern matching.

        The default implementation calls list() recursively inside run(hudson.remoting.Callable<V, java.io.IOException>) and applies filtering to the result. Implementations may wish to override this more efficiently. This method allows the user to specify that symlinks should not be followed by passing LinkOption.NOFOLLOW_LINKS as true. However, some implementations may not be able to reliably prevent link following. The base implementation here in VirtualFile ignores this parameter.

        Parameters:
        includes - comma-separated Ant-style globs as per Util.createFileSet(File, String, String) using / as a path separator; the empty string means no matches (use SelectorUtils.DEEP_TREE_MATCH if you want to match everything except some excludes)
        excludes - optional excludes in similar format to includes
        useDefaultExcludes - as per AbstractFileSet.setDefaultexcludes(boolean)
        openOptions - the options to apply when opening.
        Returns:
        a list of /-separated relative names of children (files directly inside or in subdirectories)
        Throws:
        IOException - if this is not a directory, or listing was not possible for some other reason
        Since:
        2.275 and 2.263.2
      • containsSymLinkChild

        @Restricted(org.kohsuke.accmod.restrictions.NoExternalUse.class)
        public boolean containsSymLinkChild​(OpenOption... openOptions)
                                     throws IOException
        Throws:
        IOException
      • containsTmpDirChild

        @Restricted(org.kohsuke.accmod.restrictions.NoExternalUse.class)
        public boolean containsTmpDirChild​(OpenOption... openOptions)
                                    throws IOException
        Throws:
        IOException
      • zip

        public int zip​(OutputStream outputStream,
                       String includes,
                       String excludes,
                       boolean useDefaultExcludes,
                       String prefix,
                       OpenOption... openOptions)
                throws IOException
        Create a ZIP archive from the list of folders/files using the includes and excludes to filter them.

        The default implementation calls other existing methods to list the folders/files, then retrieve them and zip them all.

        Parameters:
        includes - comma-separated Ant-style globs as per Util.createFileSet(File, String, String) using / as a path separator; the empty string means no matches (use SelectorUtils.DEEP_TREE_MATCH if you want to match everything except some excludes)
        excludes - optional excludes in similar format to includes
        useDefaultExcludes - as per AbstractFileSet.setDefaultexcludes(boolean)
        prefix - the partial path that will be added before each entry inside the archive. If non-empty, a trailing slash will be enforced.
        openOptions - the options to apply when opening.
        Returns:
        the number of files inside the archive (not the folders)
        Throws:
        IOException - if this is not a directory, or listing was not possible for some other reason
        Since:
        2.275 and 2.263.2
      • child

        @NonNull
        public abstract VirtualFile child​(@NonNull
                                          String name)
        Obtains a child file.
        Parameters:
        name - a relative path, possibly including / (but not ..)
        Returns:
        a representation of that child, whether it actually exists or not
      • length

        public abstract long length()
                             throws IOException
        Gets the file length.
        Returns:
        a length, or 0 if inapplicable (e.g. a directory)
        Throws:
        IOException - if checking the length failed
      • lastModified

        public abstract long lastModified()
                                   throws IOException
        Gets the file timestamp.
        Returns:
        a length, or 0 if inapplicable
        Throws:
        IOException - if checking the timestamp failed
      • mode

        public int mode()
                 throws IOException
        Gets the file’s Unix mode, if meaningful. If the file is symlink (see readLink()), the mode is that of the link target, not the link itself.
        Returns:
        for example, 0644 ~ rw-r--r--; -1 by default, meaning unknown or inapplicable
        Throws:
        IOException - if checking the mode failed
        Since:
        2.118
      • canRead

        public abstract boolean canRead()
                                 throws IOException
        Checks whether this file can be read.
        Returns:
        true normally
        Throws:
        IOException - if checking status failed
      • open

        public abstract InputStream open()
                                  throws IOException
        Opens an input stream on the file so its contents can be read.
        Returns:
        an open stream
        Throws:
        IOException - if it could not be opened
      • open

        @Restricted(org.kohsuke.accmod.restrictions.NoExternalUse.class)
        public InputStream open​(OpenOption... openOptions)
                         throws IOException
        Opens an input stream on the file so its contents can be read.
        Parameters:
        openOptions - the options to apply when opening.
        Returns:
        an open stream
        Throws:
        IOException - if it could not be opened
      • hashCode

        public final int hashCode()
        Hashes according to toURI().
        Overrides:
        hashCode in class Object
      • run

        public <V> V run​(hudson.remoting.Callable<V,​IOException> callable)
                  throws IOException
        Does some calculations in batch. For a remote file, this can be much faster than doing the corresponding operations one by one as separate requests. The default implementation just calls the block directly.
        Type Parameters:
        V - a value type
        Parameters:
        callable - something to run all at once (only helpful if any mentioned files are on the same system)
        Returns:
        the callable result
        Throws:
        IOException - if remote communication failed
        Since:
        1.554
      • toExternalURL

        @CheckForNull
        public URL toExternalURL()
                          throws IOException
        Optionally obtains a URL which may be used to retrieve file contents from any process on any node. For example, given cloud storage this might produce a permalink to the file.

        Only http and https protocols are permitted. It is recommended to use RobustHTTPClient.downloadFile to work with these URLs.

        This is only meaningful for isFile(): no ZIP etc. archiving protocol is defined to allow bulk access to directory trees.

        Any necessary authentication must be encoded somehow into the URL itself; do not include any tokens or other authentication which might allow access to unrelated files (for example ArtifactManager builds from a different job). Authentication should be limited to download, not upload or any other modifications.

        The URL might be valid for only a limited amount of time or even only a single use; this method should be called anew every time an external URL is required.

        Returns:
        an externally usable URL like https://gist.githubusercontent.com/ACCT/GISTID/raw/COMMITHASH/FILE, or null if there is no such support
        Throws:
        IOException
        Since:
        2.118
        See Also:
        toURI()
      • supportIsDescendant

        @Restricted(org.kohsuke.accmod.restrictions.NoExternalUse.class)
        public boolean supportIsDescendant()
        Determine if the implementation supports the isDescendant(String) method TODO un-restrict it in a weekly after the patch
      • isDescendant

        @Restricted(org.kohsuke.accmod.restrictions.NoExternalUse.class)
        public boolean isDescendant​(String childRelativePath)
                             throws IOException
        Check if the relative path is really a descendant of this folder, following the symbolic links. Meant to be used in coordination with child(String). TODO un-restrict it in a weekly after the patch
        Throws:
        IOException
      • forFile

        public static VirtualFile forFile​(File f)
        Creates a virtual file wrapper for a local file.
        Parameters:
        f - a disk file (need not exist)
        Returns:
        a wrapper
      • forFilePath

        public static VirtualFile forFilePath​(FilePath f)
        Creates a virtual file wrapper for a remotable file.
        Parameters:
        f - a local or remote file (need not exist)
        Returns:
        a wrapper