io.milton.ftp.MiltonFtpFile Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of milton-server-ce Show documentation
Show all versions of milton-server-ce Show documentation
Milton Community Edition: Supports DAV level 1 and is available on Apache2 license
The newest version!
/*
*
* Copyright 2014 McEvoy Software Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.milton.ftp;
import io.milton.common.BufferingOutputStream;
import io.milton.common.Path;
import io.milton.http.Auth;
import io.milton.http.Request.Method;
import io.milton.http.exceptions.BadRequestException;
import io.milton.http.exceptions.ConflictException;
import io.milton.http.exceptions.NotAuthorizedException;
import io.milton.http.exceptions.NotFoundException;
import io.milton.resource.*;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import org.apache.ftpserver.ftplet.FtpFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Adapter to between apache FTP's FtpFile interface and milton's Resource interface
*
* This class can wrap any Resource instance and will allow or disallow requests
* as appropriate given what methods the resource instance supports - E.g. DeletableResource,
* MoveableResource, etc
*
* @author u370681
*/
public class MiltonFtpFile implements FtpFile {
private static final Logger log = LoggerFactory.getLogger( MiltonFtpFile.class );
private final Path path;
private CollectionResource parent;
private final MiltonFsView ftpFactory;
private Resource r;
private final MiltonUser user;
public MiltonFtpFile( MiltonFsView resourceFactory, Path path, Resource r, MiltonUser user ) {
this.path = path;
this.r = r;
this.parent = null;
this.ftpFactory = resourceFactory;
this.user = user;
}
public MiltonFtpFile( MiltonFsView resourceFactory, Path path, CollectionResource parent, Resource r, MiltonUser user ) {
this.path = path;
this.r = null;
this.parent = parent;
this.ftpFactory = resourceFactory;
this.user = user;
}
@Override
public String getAbsolutePath() {
String s = path.toString();
if( s.length() == 0) {
s = "/"; // root
}
return s;
}
@Override
public String getName() {
return r.getName();
}
@Override
public boolean isHidden() {
return false;
}
@Override
public boolean isDirectory() {
return ( r instanceof CollectionResource );
}
@Override
public boolean isFile() {
return !isDirectory();
}
@Override
public boolean doesExist() {
return r != null;
}
@Override
public boolean isReadable() {
log.debug( "isReadble" );
if( r == null || !( r instanceof GetableResource ) ) return false;
Auth auth = new Auth( user.getName(), user.getUser() );
FtpRequest request = new FtpRequest( Method.GET, auth, path.toString() );
return r.authorise( request, request.getMethod(), auth );
}
/**
* Check file write permission.
*/
@Override
public boolean isWritable() {
try {
log.debug( "isWritable: " + getAbsolutePath() );
if( path.isRoot() ) return false;
Auth auth = new Auth( user.getName(), user.getUser() );
FtpRequest request = new FtpRequest( Method.DELETE, auth, path.toString() );
if( r != null ) {
if( r instanceof ReplaceableResource ) {
return r.authorise( request, Method.PUT, auth );
}
}
if( getParent() instanceof PutableResource ) {
return getParent().authorise( request, Method.PUT, auth );
} else {
return false;
}
} catch (NotAuthorizedException | BadRequestException ex) {
throw new RuntimeException(ex);
}
}
@Override
public boolean isRemovable() {
log.debug( "isRemovable: " + getAbsolutePath() );
if( r == null ) return false;
if( path.isRoot() ) return false;
Auth auth = new Auth( user.getName(), user.getUser() );
FtpRequest request = new FtpRequest( Method.DELETE, auth, path.toString() );
boolean b = r.authorise( request, Method.DELETE, auth );
log.debug( ".. = " + b );
return b;
}
@Override
public String getOwnerName() {
return "anyone";
}
@Override
public String getGroupName() {
return "anygroup";
}
@Override
public int getLinkCount() {
return 0;
}
@Override
public long getLastModified() {
if( r.getModifiedDate() != null ) {
return r.getModifiedDate().getTime();
} else {
return System.currentTimeMillis();
}
}
@Override
public boolean setLastModified( long time ) {
return false;
}
@Override
public long getSize() {
if( r instanceof GetableResource ) {
GetableResource gr = (GetableResource) r;
Long ll = gr.getContentLength();
if( ll == null ) return 0;
return ll;
} else {
return 0;
}
}
@Override
public Object getPhysicalFile() {
return path;
}
@Override
public boolean mkdir() {
log.debug( "mkdir: " + this.path );
if( parent != null ) {
if( parent instanceof MakeCollectionableResource ) {
MakeCollectionableResource mcr = (MakeCollectionableResource) parent;
try {
r = mcr.createCollection( path.getName() );
return true;
} catch( NotAuthorizedException ex ) {
log.debug( "no authorised" );
return false;
} catch( BadRequestException ex ) {
return false;
} catch( ConflictException ex ) {
log.debug( "conflict" );
return false;
}
} else {
log.debug( "parent does not support creating collection" );
return false;
}
} else {
throw new RuntimeException( "no parent" );
}
}
@Override
public boolean delete() {
if( r instanceof DeletableResource ) {
DeletableResource dr = (DeletableResource) r;
try {
dr.delete();
} catch( NotAuthorizedException ex ) {
log.warn( "can't delete, not authorised" );
return false;
} catch( ConflictException ex ) {
log.warn( "can't delete, conflct" );
return false;
} catch( BadRequestException ex ) {
log.warn( "can't delete, bad request" );
return false;
}
return true;
} else {
return false;
}
}
@Override
public boolean move( FtpFile newFile ) {
if( r == null ) {
throw new RuntimeException( "resource not saved yet" );
} else if( r instanceof MoveableResource ) {
try {
MoveableResource src = (MoveableResource) r;
MiltonFtpFile dest = (MiltonFtpFile) newFile;
CollectionResource crDest;
crDest = dest.getParent();
String newName = dest.path.getName();
try {
src.moveTo( crDest, newName );
return true;
} catch( BadRequestException ex ) {
log.error( "bad request, can't move", ex );
return false;
} catch( NotAuthorizedException ex ) {
log.error( "not authorised can't move", ex );
return false;
} catch( ConflictException ex ) {
log.error( "can't move", ex );
return false;
}
} catch( NotAuthorizedException | BadRequestException ex ) {
throw new RuntimeException(ex);
}
} else {
log.debug( "not moveable: " + this.getName() );
return false;
}
}
@Override
public List listFiles() {
log.debug( "listfiles" );
List list = new ArrayList<>();
if( r instanceof CollectionResource ) {
try {
CollectionResource cr = (CollectionResource) r;
for( Resource child : Optional.ofNullable(cr.getChildren()).orElse(List.of()) ) {
list.add( ftpFactory.wrap( path.child( child.getName() ), child ) );
}
} catch (NotAuthorizedException | BadRequestException ex) {
throw new RuntimeException(ex);
}
}
return list;
}
@Override
public OutputStream createOutputStream( long offset ) throws IOException {
log.debug( "createOutputStream: " + offset );
final BufferingOutputStream out = new BufferingOutputStream( 50000 );
if( r instanceof ReplaceableResource ) {
log.debug( "resource is replaceable" );
final ReplaceableResource rr = (ReplaceableResource) r;
Runnable runnable = () -> {
try {
rr.replaceContent(out.getInputStream(), out.getSize());
} catch (BadRequestException | NotAuthorizedException | ConflictException ex) {
throw new RuntimeException(ex);
}
};
out.setOnClose( runnable );
return out;
} else {
CollectionResource col;
try {
col = getParent();
} catch (NotAuthorizedException | BadRequestException ex) {
throw new RuntimeException(ex);
}
if( col == null ) {
throw new IOException( "parent not found" );
} else if( col instanceof PutableResource ) {
final PutableResource putableResource = (PutableResource) col;
final String newName = path.getName();
Runnable runnable = () -> {
try {
putableResource.createNew( newName, out.getInputStream(), out.getSize(), null );
} catch( BadRequestException | IOException | ConflictException | NotAuthorizedException ex ) {
throw new RuntimeException( ex );
}
};
out.setOnClose( runnable );
return out;
} else {
throw new IOException( "folder doesnt support PUT, and the resource is not replaceable" );
}
}
}
@Override
public InputStream createInputStream( long offset ) throws IOException {
if( r instanceof GetableResource ) {
GetableResource gr = (GetableResource) r;
String ct = gr.getContentType( null );
BufferingOutputStream out = new BufferingOutputStream( 50000 );
try {
gr.sendContent( out, null, null, ct );
out.close();
return out.getInputStream();
} catch (NotFoundException ex) {
log.warn("Not found exception", ex);
return null;
} catch( BadRequestException ex ) {
log.warn( "bad request", ex );
return null;
} catch( NotAuthorizedException ex ) {
log.warn( "not authorising", ex );
return null;
}
} else {
return null;
}
}
private CollectionResource getParent() throws NotAuthorizedException, BadRequestException {
if( parent == null ) {
MiltonFsView.ResourceAndPath rp = ftpFactory.getResource( path.getParent() );
if( rp.resource == null ) {
throw new RuntimeException( "couldnt find parent: " + path );
} else {
parent = (CollectionResource) rp.resource;
}
}
return parent;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy