Initial commit
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..06a84e9
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+/target/
+/.classpath
+/.project
+/.settings
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..b9cbcfa
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,6 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.apache.maven.studies</groupId>
+  <artifactId>basedir-filesystem</artifactId>
+  <version>0.0.1-SNAPSHOT</version>
+</project>
\ No newline at end of file
diff --git a/src/main/java/org/apache/maven/filesystem/BasedirClassLoader.java b/src/main/java/org/apache/maven/filesystem/BasedirClassLoader.java
new file mode 100644
index 0000000..5e2ba4f
--- /dev/null
+++ b/src/main/java/org/apache/maven/filesystem/BasedirClassLoader.java
@@ -0,0 +1,77 @@
+package org.apache.maven.filesystem;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.nio.file.Path;
+import java.util.Enumeration;
+
+public class BasedirClassLoader extends ClassLoader
+{
+    private final ClassLoader classLoader;
+    
+    private final Path basedir;
+    
+    public BasedirClassLoader( ClassLoader classLoader , Path basedir )
+    {
+        this.classLoader = classLoader;
+        this.basedir = basedir;
+    }
+    
+    public final Path getBasedir()
+    {
+        return basedir;
+    }
+    
+    public int hashCode()
+    {
+        return classLoader.hashCode();
+    }
+
+    public boolean equals( Object obj )
+    {
+        return classLoader.equals( obj );
+    }
+
+    public String toString()
+    {
+        return classLoader.toString();
+    }
+
+    public Class<?> loadClass( String name )
+        throws ClassNotFoundException
+    {
+        return classLoader.loadClass( name );
+    }
+
+    public Enumeration<URL> getResources( String name )
+        throws IOException
+    {
+        return classLoader.getResources( name );
+    }
+
+    public InputStream getResourceAsStream( String name )
+    {
+        return classLoader.getResourceAsStream( name );
+    }
+
+    public void setDefaultAssertionStatus( boolean enabled )
+    {
+        classLoader.setDefaultAssertionStatus( enabled );
+    }
+
+    public void setPackageAssertionStatus( String packageName, boolean enabled )
+    {
+        classLoader.setPackageAssertionStatus( packageName, enabled );
+    }
+
+    public void setClassAssertionStatus( String className, boolean enabled )
+    {
+        classLoader.setClassAssertionStatus( className, enabled );
+    }
+
+    public void clearAssertionStatus()
+    {
+        classLoader.clearAssertionStatus();
+    }
+}
diff --git a/src/main/java/org/apache/maven/filesystem/BasedirFileSystem.java b/src/main/java/org/apache/maven/filesystem/BasedirFileSystem.java
new file mode 100644
index 0000000..77d0a62
--- /dev/null
+++ b/src/main/java/org/apache/maven/filesystem/BasedirFileSystem.java
@@ -0,0 +1,120 @@
+package org.apache.maven.filesystem;
+
+import java.io.IOException;
+import java.nio.file.FileStore;
+import java.nio.file.FileSystem;
+import java.nio.file.Path;
+import java.nio.file.PathMatcher;
+import java.nio.file.WatchService;
+import java.nio.file.attribute.UserPrincipalLookupService;
+import java.nio.file.spi.FileSystemProvider;
+import java.util.Set;
+
+public class BasedirFileSystem extends FileSystem
+{
+    private final FileSystem fileSystem;
+    
+    public BasedirFileSystem( FileSystem fileSystem )
+    {
+        this.fileSystem = fileSystem;
+    }
+    
+    @Override
+    public int hashCode()
+    {
+        return fileSystem.hashCode();
+    }
+
+    @Override
+    public boolean equals( Object obj )
+    {
+        return fileSystem.equals( obj );
+    }
+
+    @Override
+    public FileSystemProvider provider()
+    {
+        return fileSystem.provider();
+    }
+
+    @Override
+    public void close()
+        throws IOException
+    {
+        fileSystem.close();
+    }
+
+    @Override
+    public boolean isOpen()
+    {
+        return fileSystem.isOpen();
+    }
+
+    @Override
+    public boolean isReadOnly()
+    {
+        return fileSystem.isReadOnly();
+    }
+
+    @Override
+    public String getSeparator()
+    {
+        return fileSystem.getSeparator();
+    }
+
+    @Override
+    public Iterable<Path> getRootDirectories()
+    {
+        return fileSystem.getRootDirectories();
+    }
+
+    @Override
+    public Iterable<FileStore> getFileStores()
+    {
+        return fileSystem.getFileStores();
+    }
+
+    @Override
+    public String toString()
+    {
+        return fileSystem.toString();
+    }
+
+    @Override
+    public Set<String> supportedFileAttributeViews()
+    {
+        return fileSystem.supportedFileAttributeViews();
+    }
+
+    @Override
+    public Path getPath( String first, String... more )
+    {
+        Path p = fileSystem.getPath( first, more );
+
+        ClassLoader cl = Thread.currentThread().getContextClassLoader();
+        if ( cl instanceof BasedirClassLoader )
+        {
+            p = new BasedirPath( p, ( (BasedirClassLoader) cl ).getBasedir() );
+        }
+        return p;
+    }
+
+    @Override
+    public PathMatcher getPathMatcher( String syntaxAndPattern )
+    {
+        return fileSystem.getPathMatcher( syntaxAndPattern );
+    }
+
+    @Override
+    public UserPrincipalLookupService getUserPrincipalLookupService()
+    {
+        return fileSystem.getUserPrincipalLookupService();
+    }
+
+    @Override
+    public WatchService newWatchService()
+        throws IOException
+    {
+        return fileSystem.newWatchService();
+    }
+}
diff --git a/src/main/java/org/apache/maven/filesystem/BasedirFileSystemProvider.java b/src/main/java/org/apache/maven/filesystem/BasedirFileSystemProvider.java
new file mode 100644
index 0000000..e8104d6
--- /dev/null
+++ b/src/main/java/org/apache/maven/filesystem/BasedirFileSystemProvider.java
@@ -0,0 +1,244 @@
+package org.apache.maven.filesystem;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URI;
+import java.nio.channels.AsynchronousFileChannel;
+import java.nio.channels.FileChannel;
+import java.nio.channels.SeekableByteChannel;
+import java.nio.file.AccessMode;
+import java.nio.file.CopyOption;
+import java.nio.file.DirectoryStream;
+import java.nio.file.DirectoryStream.Filter;
+import java.nio.file.FileStore;
+import java.nio.file.FileSystem;
+import java.nio.file.LinkOption;
+import java.nio.file.OpenOption;
+import java.nio.file.Path;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.nio.file.attribute.FileAttribute;
+import java.nio.file.attribute.FileAttributeView;
+import java.nio.file.spi.FileSystemProvider;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+
+public class BasedirFileSystemProvider extends FileSystemProvider
+{
+    private final FileSystemProvider defaultFileSystemProvider;
+    
+    public BasedirFileSystemProvider()
+    {
+        defaultFileSystemProvider = null;
+    }
+    
+    public BasedirFileSystemProvider( FileSystemProvider fileSystemProvider )
+    {
+        this.defaultFileSystemProvider = fileSystemProvider;
+    }
+    
+    @Override
+    public void checkAccess( Path path, AccessMode... modes )
+        throws IOException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void copy( Path source, Path target, CopyOption... options )
+        throws IOException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void createDirectory( Path dir, FileAttribute<?>... attrs )
+        throws IOException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void createLink( Path link, Path existing )
+        throws IOException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void createSymbolicLink( Path link, Path target, FileAttribute<?>... attrs )
+        throws IOException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void delete( Path path )
+        throws IOException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean deleteIfExists( Path path )
+        throws IOException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean equals( Object obj )
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public <V extends FileAttributeView> V getFileAttributeView( Path path, Class<V> type, LinkOption... options )
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public FileStore getFileStore( Path path )
+        throws IOException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public FileSystem getFileSystem( URI uri )
+    {
+        return new BasedirFileSystem( defaultFileSystemProvider.getFileSystem( uri ) );
+    }
+
+    @Override
+    public Path getPath( URI uri )
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getScheme()
+    {
+        return defaultFileSystemProvider.getScheme();
+    }
+
+    @Override
+    public int hashCode()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean isHidden( Path path )
+        throws IOException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean isSameFile( Path path, Path path2 )
+        throws IOException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void move( Path source, Path target, CopyOption... options )
+        throws IOException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public AsynchronousFileChannel newAsynchronousFileChannel( Path path, Set<? extends OpenOption> options,
+                                                               ExecutorService executor, FileAttribute<?>... attrs )
+        throws IOException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public SeekableByteChannel newByteChannel( Path path, Set<? extends OpenOption> options, FileAttribute<?>... attrs )
+        throws IOException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public DirectoryStream<Path> newDirectoryStream( Path dir, Filter<? super Path> filter )
+        throws IOException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public FileChannel newFileChannel( Path path, Set<? extends OpenOption> options, FileAttribute<?>... attrs )
+        throws IOException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public FileSystem newFileSystem( Path path, Map<String, ?> env )
+        throws IOException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public FileSystem newFileSystem( URI uri, Map<String, ?> env )
+        throws IOException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public InputStream newInputStream( Path path, OpenOption... options )
+        throws IOException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public OutputStream newOutputStream( Path path, OpenOption... options )
+        throws IOException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public <A extends BasicFileAttributes> A readAttributes( Path path, Class<A> type, LinkOption... options )
+        throws IOException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Map<String, Object> readAttributes( Path path, String attributes, LinkOption... options )
+        throws IOException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Path readSymbolicLink( Path link )
+        throws IOException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setAttribute( Path path, String attribute, Object value, LinkOption... options )
+        throws IOException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String toString()
+    {
+        throw new UnsupportedOperationException();
+    }
+}
diff --git a/src/main/java/org/apache/maven/filesystem/BasedirPath.java b/src/main/java/org/apache/maven/filesystem/BasedirPath.java
new file mode 100644
index 0000000..8dcc0a3
--- /dev/null
+++ b/src/main/java/org/apache/maven/filesystem/BasedirPath.java
@@ -0,0 +1,177 @@
+package org.apache.maven.filesystem;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.nio.file.FileSystem;
+import java.nio.file.LinkOption;
+import java.nio.file.Path;
+import java.nio.file.WatchEvent.Kind;
+import java.nio.file.WatchEvent.Modifier;
+import java.nio.file.WatchKey;
+import java.nio.file.WatchService;
+import java.util.Iterator;
+
+class BasedirPath implements Path
+{
+    private final Path basedir;
+    
+    private Path path;
+    
+    BasedirPath( Path path, Path basedir ) {
+        this.path = path;
+        this.basedir = basedir;
+    }
+    
+    public FileSystem getFileSystem()
+    {
+        return path.getFileSystem();
+    }
+
+    public boolean isAbsolute()
+    {
+        return path.isAbsolute();
+    }
+
+    public Path getRoot()
+    {
+        return path.getRoot();
+    }
+
+    public Path getFileName()
+    {
+        return path.getFileName();
+    }
+
+    public Path getParent()
+    {
+        return path.getParent();
+    }
+
+    public int getNameCount()
+    {
+        return path.getNameCount();
+    }
+
+    public Path getName( int index )
+    {
+        return path.getName( index );
+    }
+
+    public Path subpath( int beginIndex, int endIndex )
+    {
+        return path.subpath( beginIndex, endIndex );
+    }
+
+    public boolean startsWith( Path other )
+    {
+        return path.startsWith( other );
+    }
+
+    public boolean startsWith( String other )
+    {
+        return path.startsWith( other );
+    }
+
+    public boolean endsWith( Path other )
+    {
+        return path.endsWith( other );
+    }
+
+    public boolean endsWith( String other )
+    {
+        return path.endsWith( other );
+    }
+
+    public Path normalize()
+    {
+        return path.normalize();
+    }
+
+    public Path resolve( Path other )
+    {
+        return path.resolve( other );
+    }
+
+    public Path resolve( String other )
+    {
+        return path.resolve( other );
+    }
+
+    public Path resolveSibling( Path other )
+    {
+        return path.resolveSibling( other );
+    }
+
+    public Path resolveSibling( String other )
+    {
+        return path.resolveSibling( other );
+    }
+
+    public Path relativize( Path other )
+    {
+        return path.relativize( other );
+    }
+
+    public URI toUri()
+    {
+        return path.toUri();
+    }
+
+    public Path toAbsolutePath()
+    {
+        if ( !path.isAbsolute() )
+        {
+            path = basedir.resolve( path );
+        }
+        return path.toAbsolutePath();
+    }
+
+    public Path toRealPath( LinkOption... options )
+        throws IOException
+    {
+        return path.toRealPath( options );
+    }
+
+    public File toFile()
+    {
+        return path.toFile();
+    }
+
+    public WatchKey register( WatchService watcher, Kind<?>[] events, Modifier... modifiers )
+        throws IOException
+    {
+        return path.register( watcher, events, modifiers );
+    }
+
+    public WatchKey register( WatchService watcher, Kind<?>... events )
+        throws IOException
+    {
+        return path.register( watcher, events );
+    }
+
+    public Iterator<Path> iterator()
+    {
+        return path.iterator();
+    }
+
+    public int compareTo( Path other )
+    {
+        return path.compareTo( other );
+    }
+
+    public boolean equals( Object other )
+    {
+        return path.equals( other );
+    }
+
+    public int hashCode()
+    {
+        return path.hashCode();
+    }
+
+    public String toString()
+    {
+        return path.toString();
+    }
+}
diff --git a/src/main/java/org/apache/maven/filesystem/Main.java b/src/main/java/org/apache/maven/filesystem/Main.java
new file mode 100644
index 0000000..09c3eab
--- /dev/null
+++ b/src/main/java/org/apache/maven/filesystem/Main.java
@@ -0,0 +1,43 @@
+package org.apache.maven.filesystem;
+
+import java.io.File;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+/**
+ * Ensure to start java with {@code -Djava.nio.file.spi.DefaultFileSystemProvider=org.apache.maven.filesystem.BasedirFilesystemProvider}
+ * 
+ * @see <a href="https://docs.oracle.com/javase/8/docs/api/index.html?java/nio/file/spi/FileSystemProvider.html">java.nio.file.spi.FileSystemProvider</a>
+ */
+public class Main
+{
+
+    public static void main( String[] args )
+    {
+        ClassLoader old = Thread.currentThread().getContextClassLoader();
+        try
+        {
+            System.out.println( "--- ORIGINAL ---" );
+            tests();
+            System.out.println();
+
+            Path basedir = Paths.get( "/a/b/c" ).toAbsolutePath();
+            ClassLoader c1 = new BasedirClassLoader( old, basedir );
+            Thread.currentThread().setContextClassLoader( c1 );
+            System.out.println( "--- With BasedirClassloader ( " + basedir + " ) ---" );
+            tests();
+        }
+        finally
+        {
+            Thread.currentThread().setContextClassLoader( old );
+        }
+    }
+
+    public static void tests() {
+        System.out.println( "Path: " + Paths.get( "src/main/java" ) ); // good
+        System.out.println( "Path.toAbsolutePath(): " + Paths.get( "src/main/java" ).toAbsolutePath() ); // good
+        System.out.println( "File.getAbsoluteFile(): " + new File( "src/main/java" ).getAbsoluteFile() ); // bad
+    }
+
+
+}
diff --git a/src/main/resources/META-INF/services/java.nio.file.spi.FileSystemProvider b/src/main/resources/META-INF/services/java.nio.file.spi.FileSystemProvider
new file mode 100644
index 0000000..3fa97be
--- /dev/null
+++ b/src/main/resources/META-INF/services/java.nio.file.spi.FileSystemProvider
@@ -0,0 +1 @@
+org.apache.maven.filesystem.BasedirFilesystemProvider
\ No newline at end of file