Lucio Lelii 5 years ago
commit cefc28fda5

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/classes" path="src/main/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources">
<attributes>
<attribute name="maven.pomderived" value="true"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>sh-fuse-integration</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
</natures>
</projectDescription>

@ -0,0 +1,6 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.release=disabled
org.eclipse.jdt.core.compiler.source=1.8

@ -0,0 +1,4 @@
activeProfiles=
eclipse.preferences.version=1
resolveWorkspaceProjects=true
version=1

@ -0,0 +1,117 @@
<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.gcube.data-access</groupId>
<artifactId>sh-fuse-integration</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>SHFuseIntegration</name>
<parent>
<artifactId>maven-parent</artifactId>
<groupId>org.gcube.tools</groupId>
<version>1.0.0</version>
<relativePath />
</parent>
<repositories>
<repository>
<id>central</id>
<name>bintray</name>
<url>http://jcenter.bintray.com</url>
</repository>
</repositories>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.gcube.distribution</groupId>
<artifactId>gcube-bom</artifactId>
<version>LATEST</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.github.serceman</groupId>
<artifactId>jnr-fuse</artifactId>
<version>0.5.2.1</version>
</dependency>
<dependency>
<groupId>org.gcube.common</groupId>
<artifactId>gxJRS</artifactId>
</dependency>
<dependency>
<groupId>org.gcube.common</groupId>
<artifactId>storagehub-client-library</artifactId>
<version>[1.0.0-SNAPSHOT, 2.0.0-SNAPSHOT)</version>
</dependency>
<dependency>
<groupId>org.gcube.common</groupId>
<artifactId>storagehub-model</artifactId>
<version>[1.0.0-SNAPSHOT, 2.0.0-SNAPSHOT)</version>
</dependency>
<dependency>
<groupId>org.cache2k</groupId>
<artifactId>cache2k-jcache</artifactId>
<version>1.2.0.Final</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.0.13</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<archive>
<manifest>
<mainClass>org.gcube.data.access.storagehub.fs.StorageHubFuseLauncher
</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<target>1.8</target>
<source>1.8</source>
</configuration>
</plugin>
</plugins>
</build>
</project>

@ -0,0 +1,68 @@
package org.gcube.data.access.storagehub.fs;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
public class FSInputStream extends InputStream{
private boolean closed = false;
BlockingQueue<Byte> q = new LinkedBlockingQueue<Byte>(20000);
public int byteRead = 0;
public int bytegiven = 0;
protected synchronized void add(byte[] buf) {
for (byte b : buf)
try {
//System.out.println("adding "+b);
q.put(b);
byteRead++;
} catch (InterruptedException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
@Override
public int read() throws IOException {
try {
//System.out.println("q is empty ? "+q.isEmpty());
Byte retrievedValue;
do{
retrievedValue=q.poll(2, TimeUnit.SECONDS);
} while (retrievedValue==null && !closed);
if (closed && retrievedValue==null) {
return -1;
}
int value = retrievedValue & 0xFF;
//System.out.println("reading byte: ==== "+value);
bytegiven++;
return value;
} catch (InterruptedException e) {
//System.out.println("interrupt -------------");
e.printStackTrace();
return -1;
}
}
@Override
public int available() throws IOException {
return q.size();
}
@Override
public void close() throws IOException {
this.closed= true;
super.close();
}
}

@ -0,0 +1,85 @@
package org.gcube.data.access.storagehub.fs;
import java.io.IOException;
import java.io.InputStream;
import org.gcube.common.storagehub.client.dsl.FileContainer;
import org.gcube.common.storagehub.model.items.AbstractFileItem;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jnr.ffi.Pointer;
import jnr.ffi.types.off_t;
import jnr.ffi.types.size_t;
import ru.serce.jnrfuse.ErrorCodes;
import ru.serce.jnrfuse.struct.FileStat;
public class FileDownload implements SHFile{
public static Logger logger = LoggerFactory.getLogger(FileDownload.class);
InputStream stream;
AbstractFileItem fileItem;
public FileDownload(FileContainer fileContainer) throws Exception {
stream = fileContainer.download().getStream();
fileItem = fileContainer.get();
logger.trace("FILE-DOWNLOAD initialized with {} , {}", fileItem.getName(), fileItem.getContent().getSize());
}
public synchronized int read(Pointer buf, @size_t long size, @off_t long offset) {
logger.trace("read called with size {} and offset {} ", size, offset);
int bytesToRead = (int) (size);
byte[] mybuf = new byte[bytesToRead];
int readTotal= 0;;
try {
int read =0;
while ((read= stream.read(mybuf, 0 , bytesToRead-readTotal))!=-1 && bytesToRead>readTotal) {
buf.put(0, mybuf, 0, read);
readTotal+= read;
}
logger.trace("bytes to read {} and read total {} and last read {}", bytesToRead, readTotal, read);
}catch (Exception e) {
logger.error("error in read",e);
try {
stream.close();
} catch (IOException e1) {}
return -ErrorCodes.ENOENT();
}
return readTotal;
}
public synchronized int flush() {
logger.trace("called flush");
//logger.trace("file is ready "+mapPathUpload.get(path).toString());
try {
stream.close();
} catch (IOException e1) {
logger.error("error closing stream",e1);
}
return 0;
}
public int getAttr(FileStat stat) {
logger.trace("is in download");
stat.st_mode.set(FileStat.S_IFREG | 0555);
stat.st_size.set(fileItem.getContent().getSize());
stat.st_mtim.tv_sec.set(fileItem.getLastModificationTime().toInstant().getEpochSecond());
stat.st_mtim.tv_nsec.set(fileItem.getLastModificationTime().toInstant().getNano());
stat.st_ctim.tv_sec.set(fileItem.getCreationTime().toInstant().getEpochSecond());
stat.st_ctim.tv_nsec.set(fileItem.getCreationTime().toInstant().getNano());
stat.st_atim.tv_sec.set(fileItem.getLastModificationTime().toInstant().getEpochSecond());
stat.st_atim.tv_nsec.set(fileItem.getLastModificationTime().toInstant().getNano());
return 0;
}
}

@ -0,0 +1,63 @@
package org.gcube.data.access.storagehub.fs;
import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jnr.ffi.Pointer;
import ru.serce.jnrfuse.ErrorCodes;
import ru.serce.jnrfuse.struct.FileStat;
public class FileUpload implements SHFile {
public static Logger logger = LoggerFactory.getLogger(FileUpload.class);
FSInputStream stream;
private int bytesRead =0;
public FileUpload(FSInputStream stream) {
super();
this.stream = stream;
}
public synchronized int write(Pointer buf, long size, long offset) {
logger.trace(Thread.currentThread().getName()+" ) calling write "+ size+" "+offset);
if (stream==null) return -ErrorCodes.ENOENT();
byte[] mybuf = new byte[(int)size];
try {
buf.get(0, mybuf, 0, (int)size);
stream.add(mybuf);
}catch (Exception e) {
logger.error("error on download",e);
try {
stream.close();
} catch (IOException e1) {}
return -ErrorCodes.ENOENT();
}
bytesRead+=size;
return (int)size;
}
@Override
public synchronized int flush() {
try {
stream.close();
} catch (IOException e1) {
e1.printStackTrace();
}
return 0;
}
@Override
public int getAttr(FileStat stat) {
stat.st_mode.set(FileStat.S_IFREG | 0555);
stat.st_size.set(bytesRead);
return 0;
}
}

@ -0,0 +1,85 @@
package org.gcube.data.access.storagehub.fs;
import java.nio.file.Paths;
import java.util.List;
import org.cache2k.Cache;
import org.gcube.common.storagehub.client.dsl.FolderContainer;
import org.gcube.common.storagehub.client.dsl.ItemContainer;
import org.gcube.common.storagehub.model.items.Item;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class PathUtils {
public static Logger logger = LoggerFactory.getLogger(PathUtils.class);
private Cache<String,ItemContainer<Item>> cache;
private FolderContainer rootDirectory;
public PathUtils(Cache<String, ItemContainer<Item>> cache, FolderContainer rootDirectory) {
super();
this.cache = cache;
this.rootDirectory = rootDirectory;
}
public String getLastComponent(String path) {
while (path.substring(path.length() - 1).equals("/")) {
path = path.substring(0, path.length() - 1);
}
if (path.isEmpty()) {
return "";
}
return path.substring(path.lastIndexOf("/") + 1);
}
public String getParentPath(String path) {
return Paths.get(path).getParent().toString();
}
public ItemContainer<? extends Item> getPath(String path) {
if (path.equals("/")) return rootDirectory;
if (cache.containsKey(path)) {
ItemContainer<? extends Item> cached = cache.peek(path);
logger.trace("path "+path+" retrieved in cache with id "+cached.getId());
return cached;
} else logger.trace("path "+path+" not in cache");
synchronized (this) {
ItemContainer<? extends Item> retrievedItem = getPathRecursive(path, rootDirectory);
if (retrievedItem!=null)cache.put(path, (ItemContainer<Item>) retrievedItem);
return retrievedItem;
}
}
public ItemContainer<? extends Item> getPathRecursive(String path, FolderContainer parentContainer) {
try {
while (path.startsWith("/")) {
path = path.substring(1);
}
if (!path.contains("/")) {
logger.trace("seaching path "+path+" in "+parentContainer.get().getTitle());
List<ItemContainer<? extends Item>> items = parentContainer.findByName(path).withContent().getContainers();
logger.trace("found? "+(items.size()>0));
return items.size()>0? items.get(0): null;
}
String nextName = path.substring(0, path.indexOf("/"));
String rest = path.substring(path.indexOf("/"));
for (ItemContainer<? extends Item> container : parentContainer.findByName(nextName).withContent().getContainers()) {
if (container instanceof FolderContainer) {
logger.trace("seaching path "+rest+" in "+container.get().getTitle());
return getPathRecursive(rest, (FolderContainer)container);
}
}
}catch(Exception e) {
logger.error("error in gpath recursive",e);
}
return null;
}
}

@ -0,0 +1,22 @@
package org.gcube.data.access.storagehub.fs;
import jnr.ffi.Pointer;
import jnr.ffi.types.off_t;
import jnr.ffi.types.size_t;
import ru.serce.jnrfuse.ErrorCodes;
import ru.serce.jnrfuse.struct.FileStat;
public interface SHFile {
default int read(Pointer buf, @size_t long size, @off_t long offset) {
return -ErrorCodes.ENOSYS();
}
default int write(Pointer buf, long size, long offset) {
return -ErrorCodes.ENOSYS();
}
int flush();
int getAttr(FileStat stat);
}

@ -0,0 +1,483 @@
package org.gcube.data.access.storagehub.fs;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import org.cache2k.Cache;
import org.cache2k.Cache2kBuilder;
import org.gcube.common.authorization.library.AuthorizedTasks;
import org.gcube.common.authorization.library.provider.SecurityTokenProvider;
import org.gcube.common.scope.api.ScopeProvider;
import org.gcube.common.storagehub.client.dsl.ContainerType;
import org.gcube.common.storagehub.client.dsl.FileContainer;
import org.gcube.common.storagehub.client.dsl.FolderContainer;
import org.gcube.common.storagehub.client.dsl.ItemContainer;
import org.gcube.common.storagehub.client.dsl.StorageHubClient;
import org.gcube.common.storagehub.model.exceptions.StorageHubException;
import org.gcube.common.storagehub.model.exceptions.UserNotAuthorizedException;
import org.gcube.common.storagehub.model.items.AbstractFileItem;
import org.gcube.common.storagehub.model.items.FolderItem;
import org.gcube.common.storagehub.model.items.Item;
import org.gcube.common.storagehub.model.items.SharedFolder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jnr.ffi.Pointer;
import jnr.ffi.types.mode_t;
import jnr.ffi.types.off_t;
import jnr.ffi.types.size_t;
import ru.serce.jnrfuse.ErrorCodes;
import ru.serce.jnrfuse.FuseFillDir;
import ru.serce.jnrfuse.FuseStubFS;
import ru.serce.jnrfuse.struct.FileStat;
import ru.serce.jnrfuse.struct.FuseFileInfo;
public class StorageHubFS extends FuseStubFS {
public static Logger logger = LoggerFactory.getLogger(StorageHubFS.class);
StorageHubClient client;
String token;
String scope;
HashMap<String, SHFile> tempFiles = new HashMap<>();
static final String VREFOLDERS_NAME= "VREFolders";
Cache<String,ItemContainer<Item>> cache;
PathUtils pathUtils;
private FolderContainer rootDirectory;
public StorageHubFS(String token, String scope) {
super();
this.token = token;
this.scope = scope;
ScopeProvider.instance.set(scope);
SecurityTokenProvider.instance.set(token);
client = new StorageHubClient();
rootDirectory = client.getWSRoot();
cache = new Cache2kBuilder<String, ItemContainer<Item>>() {}
.expireAfterWrite(30, TimeUnit.SECONDS)
.resilienceDuration(30, TimeUnit.SECONDS)
.build();
pathUtils = new PathUtils(cache, rootDirectory);
}
/*
* fileUpload
* @see ru.serce.jnrfuse.FuseStubFS#write(java.lang.String, jnr.ffi.Pointer, long, long, ru.serce.jnrfuse.struct.FuseFileInfo)
*/
@Override
public synchronized int write(String path, Pointer buf, long size, long offset, FuseFileInfo fi) {
ScopeProvider.instance.set(scope);
SecurityTokenProvider.instance.set(token);
logger.trace(Thread.currentThread().getName()+" ) calling write "+ size+" "+offset);
SHFile file = tempFiles.get(path);
return file.write(buf, size, offset);
}
@Override
public synchronized int flush(String path, FuseFileInfo fi) {
logger.trace("called flush for "+path);
tempFiles.get(path).flush();
tempFiles.remove(path);
return 0;
}
/*
* fileCreation
* @see ru.serce.jnrfuse.FuseStubFS#write(java.lang.String, jnr.ffi.Pointer, long, long, ru.serce.jnrfuse.struct.FuseFileInfo)
*/
@Override
public synchronized int create(final String path, @mode_t long mode, FuseFileInfo fi) {
ScopeProvider.instance.set(scope);
SecurityTokenProvider.instance.set(token);
logger.trace(Thread.currentThread().getName()+" ) calling create "+path);
if (pathUtils.getPath(path) != null) {
return -ErrorCodes.EEXIST();
}
final ItemContainer<? extends Item> parentContainer;
if (path.substring(1).contains("/")) {
String parentPath = Paths.get(path).getParent().toString();
parentContainer= pathUtils.getPath(parentPath);
} else parentContainer = rootDirectory;
final FSInputStream stream = new FSInputStream();
FileUpload fileUpload = new FileUpload(stream);
tempFiles.put(path, fileUpload);
new Thread(AuthorizedTasks.bind(new Runnable() {
@Override
public void run() {
try {
((FolderContainer) parentContainer).uploadFile(stream, pathUtils.getLastComponent(path), "");
}catch(Throwable t) {
t.printStackTrace();
tempFiles.get(path).flush();
}
}
})).start();
return 0;
}
@Override
public int getattr(String path, FileStat stat) {
ScopeProvider.instance.set(scope);
SecurityTokenProvider.instance.set(token);
logger.trace(Thread.currentThread().getName()+" ) calling getattr "+path);
if (Objects.equals(path, "/") || path.contains("Trash") || path.equals("/"+VREFOLDERS_NAME)) {
stat.st_mode.set(FileStat.S_IFDIR | 0755);
stat.st_nlink.set(2);
} else if(pathUtils.getLastComponent(path).startsWith(".")) {
logger.trace("start with /.");
return super.getattr(path, stat);
} else if (tempFiles.containsKey(path)){
return tempFiles.get(path).getAttr(stat);
}else {
logger.trace("trying items");
ItemContainer<? extends Item> container = pathUtils.getPath(path);
logger.trace("item for path "+path+" is null ? "+(container==null));
if (container==null) {
return -ErrorCodes.ENOENT();
}else
try{
getAttrSHItem(container, stat);
}catch (Throwable e) {
logger.error("error gettign attributes ",e);
return -ErrorCodes.ENOENT();
}
}
return 0;
}
private void getAttrSHItem(ItemContainer<? extends Item> container, FileStat stat) throws IllegalArgumentException{
if (container.getType()==ContainerType.FILE) {
AbstractFileItem fileItem = ((AbstractFileItem)container.get());
stat.st_size.set(fileItem.getContent().getSize());
setCommonAttributes(fileItem, stat, FileStat.S_IFREG);
logger.trace("fileContent is "+fileItem.getContent().getSize());
} else if (container.getType()==ContainerType.FOLDER) {
FolderItem folderItem = ((FolderItem)container.get());
stat.st_size.set(4096);
setCommonAttributes(folderItem, stat, FileStat.S_IFDIR);
} else throw new IllegalArgumentException("container type not valid");
}
private void setCommonAttributes(Item item, FileStat stat, int type) {
if (item.isShared()) {
stat.st_mode.set(type | FileStat.S_IROTH);
}else {
stat.st_mode.set(type | 0755);
}
stat.st_mtim.tv_sec.set(item.getLastModificationTime().toInstant().getEpochSecond());
stat.st_mtim.tv_nsec.set(item.getLastModificationTime().toInstant().getNano());
stat.st_ctim.tv_sec.set(item.getCreationTime().toInstant().getEpochSecond());
stat.st_ctim.tv_nsec.set(item.getCreationTime().toInstant().getNano());
stat.st_atim.tv_sec.set(item.getLastModificationTime().toInstant().getEpochSecond());
stat.st_atim.tv_nsec.set(item.getLastModificationTime().toInstant().getNano());
}
@Override
public int mkdir(String path, @mode_t long mode) {
ScopeProvider.instance.set(scope);
SecurityTokenProvider.instance.set(token);
logger.trace(Thread.currentThread().getName()+" ) calling mkdir");
if (pathUtils.getPath(path) != null) {
return -ErrorCodes.EEXIST();
}
ItemContainer<? extends Item> parentContainer;
if (path.substring(1).contains("/")) {
String parentPath = Paths.get(path).getParent().toString();
parentContainer= pathUtils.getPath(parentPath);
} else parentContainer = rootDirectory;
FolderContainer parentDir = (FolderContainer) parentContainer;
String dirName= pathUtils.getLastComponent(path);
try {
parentDir.newFolder(dirName,dirName );
return 0;
} catch (Exception e) {
logger.error("error in mkdir",e);
return -ErrorCodes.ENOENT();
}
}
/*
* fileDownload
* @see ru.serce.jnrfuse.FuseStubFS#write(java.lang.String, jnr.ffi.Pointer, long, long, ru.serce.jnrfuse.struct.FuseFileInfo)
*/
@Override
public int read(String path, Pointer buf, @size_t long size, @off_t long offset, FuseFileInfo fi) {
ScopeProvider.instance.set(scope);
SecurityTokenProvider.instance.set(token);
logger.trace("!!! read called in path {} with size {} and offset {} ",path, size, offset);
SHFile fileDownload;
if (tempFiles.containsKey(path)) {
fileDownload = tempFiles.get(path);
} else {
ItemContainer<? extends Item> item = pathUtils.getPath(path);
if (item == null) {
return -ErrorCodes.ENOENT();
}
if (item.getType()!=ContainerType.FILE) {
return -ErrorCodes.EISDIR();
}
try {
fileDownload = new FileDownload((FileContainer)item);
} catch (Exception e) {
logger.error("error reading remote file",e);
return -ErrorCodes.ENOENT();
}
tempFiles.put(path, fileDownload);
}
return fileDownload.read(buf, size, offset);
}
/*
* list dir
* @see ru.serce.jnrfuse.FuseStubFS#write(java.lang.String, jnr.ffi.Pointer, long, long, ru.serce.jnrfuse.struct.FuseFileInfo)
*/
@Override
public int readdir(String path, Pointer buf, FuseFillDir filter, @off_t long offset, FuseFileInfo fi) {
logger.trace("readdir called");
ScopeProvider.instance.set(scope);
SecurityTokenProvider.instance.set(token);
logger.trace(Thread.currentThread().getName()+" ) calling readdir "+path);
if (path.contains(".Trash")) return 0;
List<ItemContainer <? extends Item>> containers;
if (path.equals("/"+VREFOLDERS_NAME)) {
try {
containers= client.getVREFolders().getContainers();
}catch(StorageHubException she) {
logger.error("error reading dir",she);
return -ErrorCodes.EACCES();
}
}else {
ItemContainer<? extends Item> container = pathUtils.getPath(path);
if (container == null) {
return -ErrorCodes.ENOENT();
}
if (!(container.getType()==ContainerType.FOLDER)) {
return -ErrorCodes.ENOTDIR();
}
try {
logger.trace("reading folder "+path);
containers = ((FolderContainer)container).list().withContent().getContainers();
logger.trace("folder read "+path);
}catch(UserNotAuthorizedException una) {
logger.error("folder error ",una);
return -ErrorCodes.EACCES();
}catch(StorageHubException she) {
logger.error("folder error ",she);
return -ErrorCodes.EREMOTEIO();
}catch(Throwable t) {
logger.error("folder error ",t);
throw new RuntimeException(t);
}
}
filter.apply(buf, ".", null, 0);
filter.apply(buf, "..", null, 0);
for (ItemContainer <? extends Item> child : containers ) {
try {
Item it = child.get();
filter.apply(buf, it.getTitle(), null, 0);
if (path.charAt(path.length() - 1)!='/')
path+="/";
cache.put(path+it.getTitle(), (ItemContainer<Item>) child);
}catch (Exception e) {
logger.error("error riding children ",e);
}
}
logger.trace("tempFiles.entrySet() is empty ? {}",(tempFiles.entrySet().isEmpty()));
for(Entry<String, SHFile> entry: tempFiles.entrySet()) {
logger.trace("entry in temp map {}", entry.getKey());
if (entry.getValue() instanceof FileUpload || pathUtils.getParentPath(entry.getKey()).equals(path)) {
filter.apply(buf, pathUtils.getLastComponent(entry.getKey()), null, 0);
logger.trace("last temp entry added {}", entry.getKey());
}
}
if (path.equals("/")) filter.apply(buf, VREFOLDERS_NAME , null, 0);
return 0;
}
/* @Override
public int statfs(String path, Statvfs stbuf) {
if (Platform.getNativePlatform().getOS() == WINDOWS) {
// statfs needs to be implemented on Windows in order to allow for copying
// data from other devices because winfsp calculates the volume size based
// on the statvfs call.
// see https://github.com/billziss-gh/winfsp/blob/14e6b402fe3360fdebcc78868de8df27622b565f/src/dll/fuse/fuse_intf.c#L654
if ("/".equals(path)) {
stbuf.f_blocks.set(1024 * 1024); // total data blocks in file system
stbuf.f_frsize.set(1024); // fs block size
stbuf.f_bfree.set(1024 * 1024); // free blocks in fs
}
}
return super.statfs(path, stbuf);
}
*/
@Override
public int rename(String path, String newName) {
ScopeProvider.instance.set(scope);
SecurityTokenProvider.instance.set(token);
ItemContainer<? extends Item> folder = pathUtils.getPath(path);
if (folder == null) {
return -ErrorCodes.ENOENT();
}
ItemContainer<? extends Item> newParent = pathUtils.getPath(pathUtils.getParentPath(newName));
if (newParent == null) {
return -ErrorCodes.ENOENT();
}
if (newParent.getType()!=ContainerType.FOLDER) {
return -ErrorCodes.ENOTDIR();
}
try {
if (newParent.getId()!=folder.get().getParentId()) {
folder.move((FolderContainer)newParent);
}
if (!pathUtils.getLastComponent(newName).equals(pathUtils.getLastComponent(path)))
folder.rename(pathUtils.getLastComponent(newName));
cache.remove(path);
}catch(UserNotAuthorizedException una) {
return -ErrorCodes.EACCES();
}catch(StorageHubException she) {
return -ErrorCodes.EREMOTEIO();
}
return 0;
}
@Override
public int rmdir(String path) {
if (path.equals("/"+VREFOLDERS_NAME))
return -ErrorCodes.EACCES();
ScopeProvider.instance.set(scope);
SecurityTokenProvider.instance.set(token);
ItemContainer<? extends Item> folder = pathUtils.getPath(path);
if (folder == null) {
return -ErrorCodes.ENOENT();
}
if (folder.getType()!=ContainerType.FOLDER) {
return -ErrorCodes.ENOTDIR();
}
ScopeProvider.instance.set(scope);
SecurityTokenProvider.instance.set(token);
try {
checkSpecialFolderRemove(path);
if (folder.get() instanceof SharedFolder && ((SharedFolder) folder.get()).isVreFolder())
return -ErrorCodes.EACCES();
folder.delete();
cache.remove(path);
}catch(UserNotAuthorizedException una) {
return -ErrorCodes.EACCES();
}catch(StorageHubException she) {
return -ErrorCodes.EREMOTEIO();
}
return 0;
}
public void checkSpecialFolderRemove(String path) throws UserNotAuthorizedException{
if (path.equals(String.format("/%s", VREFOLDERS_NAME))) throw new UserNotAuthorizedException(VREFOLDERS_NAME+" cannot be deleted");
}
/*
* delete file
* @see ru.serce.jnrfuse.FuseStubFS#write(java.lang.String, jnr.ffi.Pointer, long, long, ru.serce.jnrfuse.struct.FuseFileInfo)
*/
@Override
public int unlink(String path) {
ScopeProvider.instance.set(scope);
SecurityTokenProvider.instance.set(token);
ItemContainer<? extends Item> file = pathUtils.getPath(path);
if (file == null) {
return -ErrorCodes.ENOENT();
}
if (file.getType()!=ContainerType.FILE) {
return -ErrorCodes.EISDIR();
}
ScopeProvider.instance.set(scope);
SecurityTokenProvider.instance.set(token);
try {
file.delete();
cache.remove(path);
}catch(UserNotAuthorizedException una) {
return -ErrorCodes.EACCES();
}catch(StorageHubException she) {
return -ErrorCodes.EREMOTEIO();
}
return 0;
}
@Override
public int open(String path, FuseFileInfo fi) {
logger.info("open called");
return 0;
}
/*
@Override
public int access(String path, int mask) {
logger.trace("access function called "+path+" "+mask);
return super.access(path, mask);
}
*/
}

@ -0,0 +1,17 @@
package org.gcube.data.access.storagehub.fs;
import java.nio.file.Paths;
public class StorageHubFuseLauncher {
public static void main(String ...args) {
String token = args[0];
String scope = args[1];
String path = args[2];
StorageHubFS shFS= new StorageHubFS(token, scope);
shFS.mount(Paths.get(path), true, true);
}
}

@ -0,0 +1,30 @@
package org.gcube.data.access.storagehub.fuse;
import java.nio.file.Paths;
import org.gcube.data.access.storagehub.fs.StorageHubFS;
import org.junit.Test;
import jnr.ffi.Platform;
public class FuseTest {
@Test
public void mount() {
StorageHubFS memfs = new StorageHubFS("b7c80297-e4ed-42ab-ab42-fdc0b8b0eabf-98187548","/gcube");
try {
String path;
switch (Platform.getNativePlatform().getOS()) {
case WINDOWS:
path = "J:\\";
break;
default:
path = "/home/lucio/javaMount/mnt1";
}
memfs.mount(Paths.get(path), true, true);
} finally {
memfs.umount();
}
}
}

@ -0,0 +1,17 @@
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{0}: %msg%n</pattern>
</encoder>
</appender>
<logger name="org.gcube.data.access.storagehub.fs" level="TRACE" />
<logger name="org.gcube" level="WARN" />
<root level="WARN">
<appender-ref ref="STDOUT" />
</root>
</configuration>
Loading…
Cancel
Save