Permalink
Browse files

Support MOVE

  • Loading branch information...
justinsb committed Dec 20, 2013
1 parent bbfb919 commit 4f10248117a36c4f9d912eee0bf255f5281b5465
@@ -251,6 +251,7 @@ private void createNewEntry(FsPath parent, ByteString name, InodeData.Builder in
ByteString dirEntryValue = ByteStrings.encode(created.getInode());
Modifier[] modifiers;
if (overwrite) {
// TODO: Should we record any existing key in the deleted section?
modifiers = new Modifier[] {};
} else {
modifiers = new Modifier[] { IfNotExists.INSTANCE };
@@ -343,4 +344,23 @@ public boolean delete(FsPath fsPath) throws IOException {
return store.delete(key);
}
}
public void move(FsPath fsPath, FsPath newParentFsPath, ByteString newName) throws IOException {
long id = fsPath.getId();
ByteString oldKey = buildDirEntryKey(fsPath);
ByteString newKey = buildDirEntryKey(newParentFsPath, newName);
// Create the new dir entry, delete the old one
{
ByteString dirEntryValue = ByteStrings.encode(id);
Modifier[] modifiers = new Modifier[] { IfNotExists.INSTANCE };
if (!store.put(newKey, dirEntryValue, modifiers)) {
throw new FsFileAlreadyExistsException();
}
}
store.delete(oldKey);
}
}
@@ -28,4 +28,31 @@ public static FsVolume fromHost(String host) {
public ByteString getPrefix() {
return prefix;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) (key ^ (key >>> 32));
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
FsVolume other = (FsVolume) obj;
if (key != other.key) {
return false;
}
return true;
}
}
@@ -48,7 +48,6 @@ public HttpObject doAction(FsPath fsPath) throws Exception {
// TODO: Handle ETAG??
// If-Modified-Since Validation
String ifModifiedSince = request.getHeader(HttpHeaders.Names.IF_MODIFIED_SINCE);
if (!Strings.isNullOrEmpty(ifModifiedSince)) {
Date ifModifiedSinceDate;
@@ -63,7 +62,7 @@ public HttpObject doAction(FsPath fsPath) throws Exception {
long ifModifiedSinceDateSeconds = ifModifiedSinceDate.getTime() / 1000;
long fileLastModifiedSeconds = fsPath.getModified() / 1000;
if (ifModifiedSinceDateSeconds == fileLastModifiedSeconds) {
// throw new WebdavResponseException(HttpResponseStatus.NOT_MODIFIED);
throw new WebdavResponseException(HttpResponseStatus.NOT_MODIFIED);
}
}
@@ -14,7 +14,6 @@
import java.io.FileNotFoundException;
import java.net.URI;
import java.util.Calendar;
import java.util.Collections;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.concurrent.Callable;
@@ -37,7 +36,6 @@
import com.google.common.base.Charsets;
import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.util.concurrent.AsyncFunction;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
@@ -255,28 +253,7 @@ public FsPath call() throws Exception {
String host = "";
String path = resolvePath;
List<String> pathTokens;
if (path.equals("") || path.equals("/")) {
pathTokens = Collections.emptyList();
} else {
if (path.contains("//")) {
path = path.replace("//", "/");
}
if (path.startsWith("/")) {
path = path.substring(1);
}
if (path.endsWith("/")) {
path = path.substring(0, path.length() - 1);
}
pathTokens = Lists.newArrayList();
for (String token : Splitter.on('/').split(path)) {
pathTokens.add(Urls.decodeComponent(token));
}
}
List<String> pathTokens = Urls.pathToTokens(path);
FsVolume volume = FsVolume.fromHost(host);
return getFsClient().resolve(volume, credentials, pathTokens);
@@ -0,0 +1,66 @@
package com.cloudata.files.webdav;
import io.netty.handler.codec.http.HttpObject;
import io.netty.handler.codec.http.HttpResponseStatus;
import java.io.FileNotFoundException;
import java.net.URI;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.cloudata.files.fs.FsCredentials;
import com.cloudata.files.fs.FsPath;
import com.cloudata.files.fs.FsVolume;
import com.google.common.base.Strings;
import com.google.protobuf.ByteString;
public class MoveHandler extends MethodHandler {
private static final Logger log = LoggerFactory.getLogger(MoveHandler.class);
public MoveHandler(WebdavRequestHandler requestHandler) {
super(requestHandler);
}
@Override
protected HttpObject doAction(FsPath fsPath) throws Exception {
WebdavRequest request = getRequest();
String destination = request.getHeader("Destination");
if (Strings.isNullOrEmpty(destination)) {
throw new IllegalArgumentException();
}
String newName;
FsPath newParentFsPath;
{
URI uri = URI.create(destination);
String path = uri.getPath();
String parentPath = Urls.getParentPath(path);
List<String> pathTokens = Urls.pathToTokens(parentPath);
newName = Urls.getLastPathComponent(path, true);
FsVolume volume = fsPath.getVolume();
if (!volume.equals(FsVolume.fromHost(uri.getHost()))) {
log.error("Move attempted between different volumes: {} {}", getUri(), uri);
throw new IllegalArgumentException();
}
FsCredentials credentials = request.getCredentials();
newParentFsPath = getFsClient().resolve(volume, credentials, pathTokens);
}
if (newParentFsPath == null) {
throw new FileNotFoundException();
}
getFsClient().move(fsPath, newParentFsPath, ByteString.copyFromUtf8(newName));
return buildFullResponse(HttpResponseStatus.CREATED);
}
}
@@ -2,8 +2,12 @@
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.Collections;
import java.util.List;
import com.google.common.base.Splitter;
import com.google.common.base.Throwables;
import com.google.common.collect.Lists;
public class Urls {
@@ -52,4 +56,30 @@ public static String decodeComponent(String component) {
}
}
public static List<String> pathToTokens(String path) {
List<String> pathTokens;
if (path.equals("") || path.equals("/")) {
pathTokens = Collections.emptyList();
} else {
if (path.contains("//")) {
path = path.replace("//", "/");
}
if (path.startsWith("/")) {
path = path.substring(1);
}
if (path.endsWith("/")) {
path = path.substring(0, path.length() - 1);
}
pathTokens = Lists.newArrayList();
for (String token : Splitter.on('/').split(path)) {
pathTokens.add(Urls.decodeComponent(token));
}
}
return pathTokens;
}
}
@@ -94,10 +94,10 @@ public void close() throws IOException {
handler = new PutHandler(this);
} else if (request.getMethod() == HttpMethod.DELETE) {
handler = new DeleteHandler(this);
} else if (request.getMethod().name().equals("PROPPATCH")) {
throw new UnsupportedOperationException();
} else if (request.getMethod().name().equals("MOVE")) {
handler = new MoveHandler(this);
} else {
log.warn("Method not allowed: " + request.getMethod());
log.warn("Method not allowed: {}", request);
throw new WebdavResponseException(HttpResponseStatus.METHOD_NOT_ALLOWED);
}

0 comments on commit 4f10248

Please sign in to comment.