use of diskCacheV111.util.FileExistsCacheException in project dcache by dCache.
the class ChimeraNameSpaceProvider method createSymLink.
@Override
public PnfsId createSymLink(Subject subject, String path, String dest, FileAttributes assignAttributes) throws CacheException {
checkArgument(assignAttributes.isUndefined(INVALID_CREATE_SYM_LINK_ATTRIBUTES), "Illegal assign attributes: %s", assignAttributes.getDefinedAttributes());
try {
File newEntryFile = new File(path);
String parentPath = newEntryFile.getParent();
if (parentPath == null) {
throw new FileExistsCacheException("File exists: " + path);
}
ExtendedInode parent = pathToInode(subject, parentPath);
if (!Subjects.isExemptFromNamespaceChecks(subject)) {
FileAttributes attributes = getFileAttributesForPermissionHandler(parent);
if (_permissionHandler.canCreateFile(subject, attributes) != ACCESS_ALLOWED) {
throw new PermissionDeniedCacheException("Access denied: " + path);
}
}
FsInode inode;
try {
int uid = assignAttributes.getOwnerIfPresent().orElseGet(() -> defaultUid(subject, parent));
int gid = assignAttributes.getGroupIfPresent().orElseGet(() -> defaultGid(subject, parent));
int mode = assignAttributes.getModeIfPresent().orElse(SYMLINK_MODE);
assignAttributes.undefine(OWNER, OWNER_GROUP, MODE);
inode = _fs.createLink(parent, newEntryFile.getName(), uid, gid, mode, dest.getBytes(UTF_8));
} catch (UncheckedIOException e) {
throw e.getCause();
}
PnfsId pnfsid = new PnfsId(inode.getId());
if (!assignAttributes.getDefinedAttributes().isEmpty()) {
setFileAttributes(subject, pnfsid, assignAttributes, EnumSet.noneOf(FileAttribute.class));
}
return pnfsid;
} catch (NotDirChimeraException e) {
throw new NotDirCacheException("Not a directory: " + path);
} catch (FileNotFoundChimeraFsException e) {
throw new FileNotFoundCacheException("No such file or directory: " + path);
} catch (FileExistsChimeraFsException e) {
throw new FileExistsCacheException("File exists: " + path);
} catch (IOException e) {
throw new CacheException(CacheException.UNEXPECTED_SYSTEM_EXCEPTION, e.getMessage());
}
}
use of diskCacheV111.util.FileExistsCacheException in project dcache by dCache.
the class ChimeraNameSpaceProvider method createDirectory.
@Override
public PnfsId createDirectory(Subject subject, String path, FileAttributes attributes) throws CacheException {
checkArgument(attributes.isUndefined(INVALID_CREATE_DIRECTORY_ATTRIBUTES), "Illegal assign attributes: %s", attributes.getDefinedAttributes());
try {
File newEntryFile = new File(path);
String parentPath = newEntryFile.getParent();
if (parentPath == null) {
throw new FileExistsCacheException("File exists: " + path);
}
ExtendedInode parent = pathToInode(subject, parentPath);
ExtendedInode inode;
try {
int uid = attributes.getOwnerIfPresent().orElseGet(() -> defaultUid(subject, parent));
int gid = attributes.getGroupIfPresent().orElseGet(() -> defaultGid(subject, parent));
int mode = attributes.getModeIfPresent().orElse(parent.statCache().getMode() & UMASK_DIR);
attributes.undefine(OWNER, OWNER_GROUP, MODE);
inode = mkdir(subject, parent, newEntryFile.getName(), uid, gid, mode);
} catch (UncheckedIOException e) {
throw e.getCause();
}
if (!attributes.getDefinedAttributes().isEmpty()) {
setFileAttributes(subject, inode.getPnfsId(), attributes, EnumSet.noneOf(FileAttribute.class));
}
return inode.getPnfsId();
} catch (NotDirChimeraException e) {
throw new NotDirCacheException("Not a directory: " + path);
} catch (FileNotFoundChimeraFsException e) {
throw new FileNotFoundCacheException("No such file or directory: " + path);
} catch (FileExistsChimeraFsException e) {
throw new FileExistsCacheException("File exists: " + path);
} catch (IOException e) {
throw new CacheException(CacheException.UNEXPECTED_SYSTEM_EXCEPTION, e.getMessage());
}
}
use of diskCacheV111.util.FileExistsCacheException in project dcache by dCache.
the class ChimeraNameSpaceProvider method rename.
@Override
public void rename(Subject subject, @Nullable PnfsId pnfsId, String sourcePath, String destinationPath, boolean overwrite) throws CacheException {
try {
/* Resolve the source directory.
*/
File source = new File(sourcePath);
ExtendedInode sourceDir = pathToInode(subject, source.getParent());
Set<FileAttribute> attributes = EnumSet.noneOf(FileAttribute.class);
attributes.addAll(_permissionHandler.getRequiredAttributes());
if (!_allowMoveToDirectoryWithDifferentStorageClass) {
attributes.add(FileAttribute.STORAGECLASS);
attributes.add(FileAttribute.CACHECLASS);
}
FileAttributes sourceDirAttributes = getFileAttributes(sourceDir, attributes);
ExtendedInode inode;
if (pnfsId != null) {
inode = new ExtendedInode(_fs, pnfsId, STAT);
} else {
if (!Subjects.isExemptFromNamespaceChecks(subject) && _permissionHandler.canLookup(subject, sourceDirAttributes) != ACCESS_ALLOWED) {
throw new PermissionDeniedCacheException("Access denied: " + sourcePath);
}
inode = sourceDir.inodeOf(source.getName(), STAT);
}
/* Resolve the target directory.
*/
File dest = new File(destinationPath);
ExtendedInode destDir;
FileAttributes destDirAttributes;
try {
if (dest.getParent().equals(source.getParent())) {
destDir = sourceDir;
destDirAttributes = sourceDirAttributes;
} else {
destDir = pathToInode(subject, dest.getParent());
destDirAttributes = getFileAttributes(destDir, attributes);
if (!_allowMoveToDirectoryWithDifferentStorageClass) {
FileAttributes sourceAttributes = sourceDirAttributes;
if (inode.isDirectory()) {
sourceAttributes = getFileAttributes(new ExtendedInode(_fs, inode), attributes);
}
if (!(nullToEmpty(destDirAttributes.getStorageClass()).equals(nullToEmpty(sourceAttributes.getStorageClass())) && nullToEmpty(destDirAttributes.getCacheClass()).equals(nullToEmpty(sourceAttributes.getCacheClass())))) {
throw new PermissionDeniedCacheException("Mv denied: " + dest.getParent() + " has different storage tags; use cp.");
}
}
}
} catch (FileNotFoundChimeraFsException e) {
throw new NotDirCacheException("No such directory: " + dest.getParent());
}
/* Permission checks.
*/
if (!Subjects.isExemptFromNamespaceChecks(subject) || !overwrite) {
if (!Subjects.isExemptFromNamespaceChecks(subject) && _permissionHandler.canRename(subject, sourceDirAttributes, destDirAttributes, inode.isDirectory()) != ACCESS_ALLOWED) {
throw new PermissionDeniedCacheException("Access denied: " + pnfsId);
}
try {
ExtendedInode destInode = destDir.inodeOf(dest.getName(), STAT);
if (!overwrite) {
throw new FileExistsCacheException("File exists:" + destinationPath);
}
/* Destination name exists and we were requested to
* overwrite it. Thus the subject must have delete
* permission for the destination name.
*/
FileAttributes destAttributes = getFileAttributesForPermissionHandler(destInode);
if (destInode.isDirectory()) {
if (_permissionHandler.canDeleteDir(subject, destDirAttributes, destAttributes) != ACCESS_ALLOWED) {
throw new PermissionDeniedCacheException("Access denied: " + destinationPath);
}
} else {
if (_permissionHandler.canDeleteFile(subject, destDirAttributes, destAttributes) != ACCESS_ALLOWED) {
throw new PermissionDeniedCacheException("Access denied: " + destinationPath);
}
}
} catch (FileNotFoundChimeraFsException e) {
/* Destination doesn't exist and we can move the file;
* unfortunately there is no way to test this with
* Chimera without throwing an exception.
*/
}
}
_fs.rename(inode, sourceDir, source.getName(), destDir, dest.getName());
} catch (FileNotFoundChimeraFsException e) {
throw new FileNotFoundCacheException("No such file or directory: " + pnfsId);
} catch (FileExistsChimeraFsException e) {
/* With the current implementation of Chimera, I don't
* expect this to be thrown. Instead Chimera insists on
* overwriting the destination file.
*/
throw new FileExistsCacheException("File exists:" + destinationPath);
} catch (IOException e) {
throw new CacheException(CacheException.UNEXPECTED_SYSTEM_EXCEPTION, e.getMessage());
}
}
use of diskCacheV111.util.FileExistsCacheException in project dcache by dCache.
the class ChimeraNameSpaceProvider method createFile.
@Override
public FileAttributes createFile(Subject subject, String path, FileAttributes assignAttributes, Set<FileAttribute> requestedAttributes) throws CacheException {
checkArgument(assignAttributes.isUndefined(INVALID_CREATE_FILE_ATTRIBUTES), "Illegal assign attributes: %s", assignAttributes.getDefinedAttributes());
File newEntryFile = new File(path);
String parentPath = newEntryFile.getParent();
try {
if (parentPath == null) {
throw new FileExistsCacheException("File exists: " + path);
}
ExtendedInode parent = pathToInode(subject, parentPath);
if (!Subjects.isExemptFromNamespaceChecks(subject)) {
FileAttributes attributes = getFileAttributesForPermissionHandler(parent);
if (_permissionHandler.canCreateFile(subject, attributes) != ACCESS_ALLOWED) {
throw new PermissionDeniedCacheException("Access denied: " + path);
}
}
ExtendedInode inode;
try {
int uid = assignAttributes.getOwnerIfPresent().orElseGet(() -> defaultUid(subject, parent));
int gid = assignAttributes.getGroupIfPresent().orElseGet(() -> defaultGid(subject, parent));
int mode = assignAttributes.getModeIfPresent().orElse(parent.statCache().getMode() & UMASK_FILE);
assignAttributes.undefine(OWNER, OWNER_GROUP, MODE);
inode = parent.create(newEntryFile.getName(), uid, gid, mode);
} catch (UncheckedIOException e) {
throw e.getCause();
}
FileAttributes fileAttributes;
if (assignAttributes.getDefinedAttributes().isEmpty()) {
fileAttributes = getFileAttributes(inode, requestedAttributes);
} else {
fileAttributes = setFileAttributes(subject, inode.getPnfsId(), assignAttributes, requestedAttributes);
}
if (parent.getTags().containsKey(TAG_EXPECTED_SIZE)) {
ImmutableList<String> size = parent.getTag(TAG_EXPECTED_SIZE);
if (!size.isEmpty()) {
fileAttributes.setSize(Long.parseLong(size.get(0)));
}
}
return fileAttributes;
} catch (NotDirChimeraException e) {
throw new NotDirCacheException("Not a directory: " + parentPath);
} catch (FileNotFoundChimeraFsException e) {
throw new FileNotFoundCacheException("No such directory: " + parentPath);
} catch (FileExistsChimeraFsException e) {
throw new FileExistsCacheException("File exists: " + path);
} catch (IOException e) {
throw new CacheException(CacheException.UNEXPECTED_SYSTEM_EXCEPTION, e.getMessage());
}
}
use of diskCacheV111.util.FileExistsCacheException in project dcache by dCache.
the class XrootdRedirectHandler method doOnOpen.
/**
* For client-server read and write, the open, if successful, will always result in a redirect
* response to the proper pool; hence no subsequent requests like sync, read, write or close are
* expected at the door.
* <p>
* For third-party copy where dCache is the source, the interactions are as follows:
* <p>
* 1. The client opens the file to check availability (the 'placement' stage). An OK response
* is followed by the client closing the file. 2. The client opens the file again with
* rendezvous metadata. The client will close the file only when notified by the destination
* server that the transfer has completed. 3. The destination server will open the file for the
* actual read.
* <p>
* The order of 2, 3 is not deterministic; hence the response here must provide for the
* possibility that the destination server attempts an open before the client specifies a
* time-to-live on the rendezvous point.
* <p>
* The strategy adopted is therefore as follows: response to (1) is simply to check file
* permissions. No metadata is generated and a "dummy" file handle is returned. For 2 and 3,
* whichever occurs first will cause a metadata object to be stored. If the destination server
* open occurs first, a wait response will tell the server to try again in a maximum of 3
* seconds; otherwise, if the request matches and occurs within the ttl, the mover will be
* started and the destination redirected to the pool. Response to the client will carry a file
* handle but will not actually open a mover. The close from the client is handled at the door
* by removing the rendezvous information.
* <p>
* Third-party copy where dCache is the destination should proceed with the usual upload
* transfer creation, but when the client is redirected to the pool and calls kXR_open there, a
* third-party client will be started which does read requests from the source and then writes
* the data to the mover channel.
* <p>
* NOTE: with the changed TPC Lite protocol, the client is not required to open the source
* again during the copy phase (2) if delegation is being used.
*/
@Override
protected XrootdResponse<OpenRequest> doOnOpen(ChannelHandlerContext ctx, OpenRequest req) {
/*
* TODO
*
* We ought to process this asynchronously to not block the calling thread during
* staging or queuing. We should also switch to an asynchronous reply model if
* the request is nearline or is queued on a pool. The naive approach to always
* use an asynchronous reply model doesn't work because the xrootd 3.x client
* introduces an artificial 1 second delay when processing such a response.
*/
InetSocketAddress localAddress = getDestinationAddress();
InetSocketAddress remoteAddress = getSourceAddress();
LoginSessionInfo loginSessionInfo = sessionInfo();
Map<String, String> opaque;
try {
opaque = OpaqueStringParser.getOpaqueMap(req.getOpaque());
if (opaque.isEmpty()) {
/*
* create a new HashMap as empty opaque map is immutable
*/
opaque = new HashMap<>();
}
} catch (ParseException e) {
_log.warn("Ignoring malformed open opaque {}: {}", req.getOpaque(), e.getMessage());
opaque = new HashMap<>();
}
try {
FsPath path = createFullPath(req.getPath());
XrootdResponse response = conditionallyHandleThirdPartyRequest(req, loginSessionInfo, opaque, path, remoteAddress.getHostName());
if (response != null) {
return response;
}
FilePerm neededPerm = req.getRequiredPermission();
_log.info("Opening {} for {}", req.getPath(), neededPerm.xmlText());
if (_log.isDebugEnabled()) {
logDebugOnOpen(req);
}
String ioQueue = appSpecificQueue(req);
Long size = null;
try {
String value = opaque.get("oss.asize");
if (value != null) {
size = Long.valueOf(value);
}
} catch (NumberFormatException exception) {
_log.warn("Ignoring malformed oss.asize: {}", exception.getMessage());
}
_log.info("OPAQUE : {}", opaque);
Set<String> triedHosts = extractTriedHosts(opaque);
UUID uuid = UUID.randomUUID();
opaque.put(UUID_PREFIX, uuid.toString());
/*
* In case this is a third-party open as destination,
* pass the client information to the pool.
*/
opaque.put("org.dcache.xrootd.client", getTpcClientId(req.getSession()));
String opaqueString = OpaqueStringParser.buildOpaqueString(opaque);
/*
* Interact with core dCache to open the requested file.
*/
XrootdTransfer transfer;
if (neededPerm == FilePerm.WRITE) {
/**
* boolean createDir = req.isMkPath() has
* been changed to default to true
* so as to conform to the general expectations that this
* behavior should not depend on the client.
*/
boolean overwrite = req.isDelete() && !req.isNew();
boolean persistOnSuccessfulClose = (req.getOptions() & XrootdProtocol.kXR_posc) == XrootdProtocol.kXR_posc;
// TODO: replace with req.isPersistOnSuccessfulClose() with the latest xrootd4j
transfer = _door.write(remoteAddress, path, triedHosts, ioQueue, uuid, true, overwrite, size, loginSessionInfo.getMaximumUploadSize(), localAddress, loginSessionInfo.getSubject(), loginSessionInfo.getRestriction(), persistOnSuccessfulClose, ((loginSessionInfo.isLoggedIn()) ? loginSessionInfo.getUserRootPath() : _rootPath), req.getSession().getDelegatedCredential(), opaque);
} else {
/*
* If this is a tpc transfer, then dCache is source here.
*
* Since we accept (from the destination server) any
* valid form of authentication, but without requiring
* the associated user to be mapped, we can override
* file permission restrictions (since we possess the
* 'token' rendezvous key, and the client file permissions
* have been checked during its open request).
*/
Subject subject;
if (opaque.get("tpc.key") == null) {
subject = loginSessionInfo.getSubject();
} else {
subject = Subjects.ROOT;
}
transfer = _door.read(remoteAddress, path, triedHosts, ioQueue, uuid, localAddress, subject, loginSessionInfo.getRestriction(), opaque);
/*
* Again, if this is a tpc transfer, then dCache is source here.
* The transfer is initiated by the destination server
* (= current session). However, we wish the doorinfo
* client in billing to reflect the original user connection,
* so we overwrite the transfer client address, which
* is unused by the mover.
*/
String client = opaque.get("tpc.org");
if (client != null) {
int index = client.indexOf("@");
if (index != -1 && index < client.length() - 1) {
client = client.substring(index + 1);
transfer.setClientAddress(new InetSocketAddress(client, 0));
}
}
}
/*
* ok, open was successful
*/
InetSocketAddress address = transfer.getRedirect();
/*
* Do not use the IP address as host name, as this will block
* TLS from working.
*
* According to https://tools.ietf.org/html/rfc5280#section-4.2.1.6
* an IP is required to be in the list of Subject Alternative Names
* in the host certificate, but these are rarely added in practice.
* TLS enforces the RFC and this is a workaround.
*/
String host = address.getHostName();
if (InetAddresses.isInetAddress(host)) {
_log.warn("Unable to resolve IP address {} " + "to a canonical name", host);
}
_log.info("Redirecting to {}, {}", host, address);
return new RedirectResponse<>(req, host, address.getPort(), opaqueString, "");
} catch (ParseException e) {
return withError(req, kXR_ArgInvalid, "Path arguments do not parse");
} catch (FileNotFoundCacheException e) {
return withError(req, xrootdErrorCode(e.getRc()), "No such file");
} catch (FileExistsCacheException e) {
return withError(req, kXR_NotAuthorized, "File already exists");
} catch (TimeoutCacheException e) {
return withError(req, xrootdErrorCode(e.getRc()), "Internal timeout");
} catch (PermissionDeniedCacheException e) {
return withError(req, xrootdErrorCode(e.getRc()), e.getMessage());
} catch (FileIsNewCacheException e) {
return withError(req, xrootdErrorCode(e.getRc()), "File is locked by upload");
} catch (NotFileCacheException e) {
return withError(req, xrootdErrorCode(e.getRc()), "Not a file");
} catch (CacheException e) {
return withError(req, xrootdErrorCode(e.getRc()), String.format("Failed to open file (%s [%d])", e.getMessage(), e.getRc()));
} catch (InterruptedException e) {
/* Interrupt may be caused by cell shutdown or client
* disconnect. If the client disconnected, then the error
* message will never reach the client, so saying that the
* server shut down is okay.
*/
return withError(req, kXR_ServerError, "Server shutdown");
} catch (XrootdException e) {
return withError(req, e.getError(), e.getMessage());
}
}
Aggregations