You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
349 lines
13 KiB
349 lines
13 KiB
4 years ago
|
/*
|
||
|
* Copyright 1999,2004 The Apache Software Foundation.
|
||
|
*
|
||
|
* 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 net.sf.webdav.methods;
|
||
|
|
||
|
import java.io.IOException;
|
||
|
import java.util.Hashtable;
|
||
|
|
||
|
import javax.servlet.http.HttpServletRequest;
|
||
|
import javax.servlet.http.HttpServletResponse;
|
||
|
|
||
|
import net.sf.webdav.ITransaction;
|
||
|
import net.sf.webdav.IWebdavStore;
|
||
|
import net.sf.webdav.StoredObject;
|
||
|
import net.sf.webdav.WebdavStatus;
|
||
|
import net.sf.webdav.exceptions.AccessDeniedException;
|
||
|
import net.sf.webdav.exceptions.LockFailedException;
|
||
|
import net.sf.webdav.exceptions.ObjectAlreadyExistsException;
|
||
|
import net.sf.webdav.exceptions.ObjectNotFoundException;
|
||
|
import net.sf.webdav.exceptions.WebdavException;
|
||
|
import net.sf.webdav.fromcatalina.RequestUtil;
|
||
|
import net.sf.webdav.locking.ResourceLocks;
|
||
|
|
||
|
public class DoCopy extends AbstractMethod {
|
||
|
|
||
|
private static org.slf4j.Logger LOG = org.slf4j.LoggerFactory
|
||
|
.getLogger(DoCopy.class);
|
||
|
|
||
|
private IWebdavStore _store;
|
||
|
private ResourceLocks _resourceLocks;
|
||
|
private DoDelete _doDelete;
|
||
|
private boolean _readOnly;
|
||
|
|
||
|
public DoCopy(IWebdavStore store, ResourceLocks resourceLocks,
|
||
|
DoDelete doDelete, boolean readOnly) {
|
||
|
_store = store;
|
||
|
_resourceLocks = resourceLocks;
|
||
|
_doDelete = doDelete;
|
||
|
_readOnly = readOnly;
|
||
|
}
|
||
|
|
||
|
public void execute(ITransaction transaction, HttpServletRequest req,
|
||
|
HttpServletResponse resp) throws IOException, LockFailedException {
|
||
|
LOG.trace("-- " + this.getClass().getName());
|
||
|
|
||
|
String path = getRelativePath(req);
|
||
|
if (!_readOnly) {
|
||
|
|
||
|
String tempLockOwner = "doCopy" + System.currentTimeMillis()
|
||
|
+ req.toString();
|
||
|
if (_resourceLocks.lock(transaction, path, tempLockOwner, false, 0,
|
||
|
TEMP_TIMEOUT, TEMPORARY)) {
|
||
|
try {
|
||
|
if (!copyResource(transaction, req, resp))
|
||
|
return;
|
||
|
} catch (AccessDeniedException e) {
|
||
|
resp.sendError(WebdavStatus.SC_FORBIDDEN);
|
||
|
} catch (ObjectAlreadyExistsException e) {
|
||
|
resp.sendError(WebdavStatus.SC_CONFLICT, req
|
||
|
.getRequestURI());
|
||
|
} catch (ObjectNotFoundException e) {
|
||
|
resp.sendError(WebdavStatus.SC_NOT_FOUND, req
|
||
|
.getRequestURI());
|
||
|
} catch (WebdavException e) {
|
||
|
resp.sendError(WebdavStatus.SC_INTERNAL_SERVER_ERROR);
|
||
|
} finally {
|
||
|
_resourceLocks.unlockTemporaryLockedObjects(transaction,
|
||
|
path, tempLockOwner);
|
||
|
}
|
||
|
} else {
|
||
|
resp.sendError(WebdavStatus.SC_INTERNAL_SERVER_ERROR);
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
resp.sendError(WebdavStatus.SC_FORBIDDEN);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Copy a resource.
|
||
|
*
|
||
|
* @param transaction
|
||
|
* indicates that the method is within the scope of a WebDAV
|
||
|
* transaction
|
||
|
* @param req
|
||
|
* Servlet request
|
||
|
* @param resp
|
||
|
* Servlet response
|
||
|
* @return true if the copy is successful
|
||
|
* @throws WebdavException
|
||
|
* if an error in the underlying store occurs
|
||
|
* @throws IOException
|
||
|
* when an error occurs while sending the response
|
||
|
* @throws LockFailedException
|
||
|
*/
|
||
|
public boolean copyResource(ITransaction transaction,
|
||
|
HttpServletRequest req, HttpServletResponse resp)
|
||
|
throws WebdavException, IOException, LockFailedException {
|
||
|
|
||
|
// Parsing destination header
|
||
|
String destinationPath = parseDestinationHeader(req, resp);
|
||
|
|
||
|
if (destinationPath == null)
|
||
|
return false;
|
||
|
|
||
|
String path = getRelativePath(req);
|
||
|
|
||
|
if (path.equals(destinationPath)) {
|
||
|
resp.sendError(WebdavStatus.SC_FORBIDDEN);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
Hashtable<String, Integer> errorList = new Hashtable<String, Integer>();
|
||
|
String parentDestinationPath = getParentPath(getCleanPath(destinationPath));
|
||
|
|
||
|
if (!checkLocks(transaction, req, resp, _resourceLocks,
|
||
|
parentDestinationPath)) {
|
||
|
resp.setStatus(WebdavStatus.SC_LOCKED);
|
||
|
return false; // parentDestination is locked
|
||
|
}
|
||
|
|
||
|
if (!checkLocks(transaction, req, resp, _resourceLocks, destinationPath)) {
|
||
|
resp.setStatus(WebdavStatus.SC_LOCKED);
|
||
|
return false; // destination is locked
|
||
|
}
|
||
|
|
||
|
// Parsing overwrite header
|
||
|
|
||
|
boolean overwrite = true;
|
||
|
String overwriteHeader = req.getHeader("Overwrite");
|
||
|
|
||
|
if (overwriteHeader != null) {
|
||
|
overwrite = overwriteHeader.equalsIgnoreCase("T");
|
||
|
}
|
||
|
|
||
|
// Overwriting the destination
|
||
|
String lockOwner = "copyResource" + System.currentTimeMillis()
|
||
|
+ req.toString();
|
||
|
|
||
|
if (_resourceLocks.lock(transaction, destinationPath, lockOwner, false,
|
||
|
0, TEMP_TIMEOUT, TEMPORARY)) {
|
||
|
StoredObject copySo, destinationSo = null;
|
||
|
try {
|
||
|
copySo = _store.getStoredObject(transaction, path);
|
||
|
// Retrieve the resources
|
||
|
if (copySo == null) {
|
||
|
resp.sendError(HttpServletResponse.SC_NOT_FOUND);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if (copySo.isNullResource()) {
|
||
|
String methodsAllowed = DeterminableMethod
|
||
|
.determineMethodsAllowed(copySo);
|
||
|
resp.addHeader("Allow", methodsAllowed);
|
||
|
resp.sendError(WebdavStatus.SC_METHOD_NOT_ALLOWED);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
errorList = new Hashtable<String, Integer>();
|
||
|
|
||
|
destinationSo = _store.getStoredObject(transaction,
|
||
|
destinationPath);
|
||
|
|
||
|
if (overwrite) {
|
||
|
|
||
|
// Delete destination resource, if it exists
|
||
|
if (destinationSo != null) {
|
||
|
_doDelete.deleteResource(transaction, destinationPath,
|
||
|
errorList, req, resp);
|
||
|
|
||
|
} else {
|
||
|
resp.setStatus(WebdavStatus.SC_CREATED);
|
||
|
}
|
||
|
} else {
|
||
|
|
||
|
// If the destination exists, then it's a conflict
|
||
|
if (destinationSo != null) {
|
||
|
resp.sendError(WebdavStatus.SC_PRECONDITION_FAILED);
|
||
|
return false;
|
||
|
} else {
|
||
|
resp.setStatus(WebdavStatus.SC_CREATED);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
copy(transaction, path, destinationPath, errorList, req, resp);
|
||
|
|
||
|
if (!errorList.isEmpty()) {
|
||
|
sendReport(req, resp, errorList);
|
||
|
}
|
||
|
|
||
|
} finally {
|
||
|
_resourceLocks.unlockTemporaryLockedObjects(transaction,
|
||
|
destinationPath, lockOwner);
|
||
|
}
|
||
|
} else {
|
||
|
resp.sendError(WebdavStatus.SC_INTERNAL_SERVER_ERROR);
|
||
|
return false;
|
||
|
}
|
||
|
return true;
|
||
|
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* copies the specified resource(s) to the specified destination.
|
||
|
* preconditions must be handled by the caller. Standard status codes must
|
||
|
* be handled by the caller. a multi status report in case of errors is
|
||
|
* created here.
|
||
|
*
|
||
|
* @param transaction
|
||
|
* indicates that the method is within the scope of a WebDAV
|
||
|
* transaction
|
||
|
* @param sourcePath
|
||
|
* path from where to read
|
||
|
* @param destinationPath
|
||
|
* path where to write
|
||
|
* @param req
|
||
|
* HttpServletRequest
|
||
|
* @param resp
|
||
|
* HttpServletResponse
|
||
|
* @throws WebdavException
|
||
|
* if an error in the underlying store occurs
|
||
|
* @throws IOException
|
||
|
*/
|
||
|
private void copy(ITransaction transaction, String sourcePath,
|
||
|
String destinationPath, Hashtable<String, Integer> errorList,
|
||
|
HttpServletRequest req, HttpServletResponse resp)
|
||
|
throws WebdavException, IOException {
|
||
|
|
||
|
StoredObject sourceSo = _store.getStoredObject(transaction, sourcePath);
|
||
|
if (sourceSo.isResource()) {
|
||
|
_store.createResource(transaction, destinationPath);
|
||
|
long resourceLength = _store.setResourceContent(transaction,
|
||
|
destinationPath, _store.getResourceContent(transaction,
|
||
|
sourcePath), null, null);
|
||
|
|
||
|
if (resourceLength != -1) {
|
||
|
StoredObject destinationSo = _store.getStoredObject(
|
||
|
transaction, destinationPath);
|
||
|
destinationSo.setResourceLength(resourceLength);
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
|
||
|
if (sourceSo.isFolder()) {
|
||
|
copyFolder(transaction, sourcePath, destinationPath, errorList,
|
||
|
req, resp);
|
||
|
} else {
|
||
|
resp.sendError(WebdavStatus.SC_NOT_FOUND);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* helper method of copy() recursively copies the FOLDER at source path to
|
||
|
* destination path
|
||
|
*
|
||
|
* @param transaction
|
||
|
* indicates that the method is within the scope of a WebDAV
|
||
|
* transaction
|
||
|
* @param sourcePath
|
||
|
* where to read
|
||
|
* @param destinationPath
|
||
|
* where to write
|
||
|
* @param errorList
|
||
|
* all errors that ocurred
|
||
|
* @param req
|
||
|
* HttpServletRequest
|
||
|
* @param resp
|
||
|
* HttpServletResponse
|
||
|
* @throws WebdavException
|
||
|
* if an error in the underlying store occurs
|
||
|
*/
|
||
|
private void copyFolder(ITransaction transaction, String sourcePath,
|
||
|
String destinationPath, Hashtable<String, Integer> errorList,
|
||
|
HttpServletRequest req, HttpServletResponse resp)
|
||
|
throws WebdavException {
|
||
|
|
||
|
_store.createFolder(transaction, destinationPath);
|
||
|
boolean infiniteDepth = true;
|
||
|
String depth = req.getHeader("Depth");
|
||
|
if (depth != null) {
|
||
|
if (depth.equals("0")) {
|
||
|
infiniteDepth = false;
|
||
|
}
|
||
|
}
|
||
|
if (infiniteDepth) {
|
||
|
String[] children = _store
|
||
|
.getChildrenNames(transaction, sourcePath);
|
||
|
children = children == null ? new String[] {} : children;
|
||
|
|
||
|
StoredObject childSo;
|
||
|
for (int i = children.length - 1; i >= 0; i--) {
|
||
|
children[i] = "/" + children[i];
|
||
|
try {
|
||
|
childSo = _store.getStoredObject(transaction,
|
||
|
(sourcePath + children[i]));
|
||
|
if (childSo.isResource()) {
|
||
|
_store.createResource(transaction, destinationPath
|
||
|
+ children[i]);
|
||
|
long resourceLength = _store.setResourceContent(
|
||
|
transaction, destinationPath + children[i],
|
||
|
_store.getResourceContent(transaction,
|
||
|
sourcePath + children[i]), null, null);
|
||
|
|
||
|
if (resourceLength != -1) {
|
||
|
StoredObject destinationSo = _store
|
||
|
.getStoredObject(transaction,
|
||
|
destinationPath + children[i]);
|
||
|
destinationSo.setResourceLength(resourceLength);
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
copyFolder(transaction, sourcePath + children[i],
|
||
|
destinationPath + children[i], errorList, req,
|
||
|
resp);
|
||
|
}
|
||
|
} catch (AccessDeniedException e) {
|
||
|
errorList.put(destinationPath + children[i], new Integer(
|
||
|
WebdavStatus.SC_FORBIDDEN));
|
||
|
} catch (ObjectNotFoundException e) {
|
||
|
errorList.put(destinationPath + children[i], new Integer(
|
||
|
WebdavStatus.SC_NOT_FOUND));
|
||
|
} catch (ObjectAlreadyExistsException e) {
|
||
|
errorList.put(destinationPath + children[i], new Integer(
|
||
|
WebdavStatus.SC_CONFLICT));
|
||
|
} catch (WebdavException e) {
|
||
|
errorList.put(destinationPath + children[i], new Integer(
|
||
|
WebdavStatus.SC_INTERNAL_SERVER_ERROR));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
}
|