|
1 | 1 | /* |
| 2 | + * Elemental |
| 3 | + * Copyright (C) 2024, Evolved Binary Ltd |
| 4 | + * |
| 5 | + * admin@evolvedbinary.com |
| 6 | + * https://www.evolvedbinary.com | https://www.elemental.xyz |
| 7 | + * |
| 8 | + * This library is free software; you can redistribute it and/or |
| 9 | + * modify it under the terms of the GNU Lesser General Public |
| 10 | + * License as published by the Free Software Foundation; version 2.1. |
| 11 | + * |
| 12 | + * This library is distributed in the hope that it will be useful, |
| 13 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 14 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 15 | + * Lesser General Public License for more details. |
| 16 | + * |
| 17 | + * You should have received a copy of the GNU Lesser General Public |
| 18 | + * License along with this library; if not, write to the Free Software |
| 19 | + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
| 20 | + * |
| 21 | + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. |
| 22 | + * The original license header is included below. |
| 23 | + * |
| 24 | + * ===================================================================== |
| 25 | + * |
2 | 26 | * eXist-db Open Source Native XML Database |
3 | 27 | * Copyright (C) 2001 The eXist-db Authors |
4 | 28 | * |
|
22 | 46 | package org.exist.xquery.functions.securitymanager; |
23 | 47 |
|
24 | 48 | import org.exist.collections.Collection; |
25 | | -import org.exist.dom.persistent.DocumentImpl; |
26 | 49 | import org.exist.dom.QName; |
27 | 50 | import org.exist.dom.memtree.MemTreeBuilder; |
| 51 | +import org.exist.dom.persistent.LockedDocument; |
28 | 52 | import org.exist.security.*; |
29 | 53 | import org.exist.security.ACLPermission.ACE_ACCESS_TYPE; |
30 | 54 | import org.exist.security.ACLPermission.ACE_TARGET; |
31 | 55 | import org.exist.storage.DBBroker; |
| 56 | +import org.exist.storage.lock.Lock; |
32 | 57 | import org.exist.storage.txn.TransactionException; |
33 | 58 | import org.exist.storage.txn.Txn; |
| 59 | +import org.exist.util.LockException; |
34 | 60 | import org.exist.util.SyntaxException; |
35 | 61 | import org.exist.xmldb.XmldbURI; |
36 | 62 | import org.exist.xquery.BasicFunction; |
|
52 | 78 |
|
53 | 79 | /** |
54 | 80 | * |
55 | | - * @author <a href="mailto:adam@existsolutions.com">Adam Retter</a> |
| 81 | + * @author <a href="mailto:adam@evolvedbinary.com">Adam Retter</a> |
56 | 82 | */ |
57 | 83 | public class PermissionsFunction extends BasicFunction { |
58 | 84 |
|
@@ -409,20 +435,49 @@ private Sequence functionOctalToMode(final String octal) { |
409 | 435 | } |
410 | 436 |
|
411 | 437 | private Permission getPermissions(final XmldbURI pathUri) throws XPathException, PermissionDeniedException { |
412 | | - final Permission permissions; |
413 | | - final Collection col = context.getBroker().getCollection(pathUri); |
414 | | - if(col != null) { |
415 | | - permissions = col.getPermissionsNoLock(); |
| 438 | + final DBBroker broker = context.getBroker(); |
| 439 | + if (pathUri.equals(XmldbURI.DB)) { |
| 440 | + // Can only be a Collection (i.e. `/db`) |
| 441 | + try (final Collection rootCollection = broker.openCollection(pathUri, Lock.LockMode.READ_LOCK)) { |
| 442 | + return rootCollection.getPermissions(); |
| 443 | + } |
| 444 | + |
416 | 445 | } else { |
417 | | - final DocumentImpl doc = context.getBroker().getResource(pathUri, Permission.READ); |
418 | | - if(doc != null) { |
419 | | - permissions = doc.getPermissions(); |
420 | | - } else { |
421 | | - throw new XPathException(this, "Resource or collection '" + pathUri.toString() + "' does not exist."); |
| 446 | + // Interrogate the parent Collection so that we can efficiently work out if this URI indicates a Collection or Document |
| 447 | + final XmldbURI parentCollectionUri = pathUri.removeLastSegment(); |
| 448 | + final XmldbURI resourceName = pathUri.lastSegment(); |
| 449 | + |
| 450 | + try (final Collection parentCollection = broker.openCollection(parentCollectionUri, Lock.LockMode.READ_LOCK)) { |
| 451 | + |
| 452 | + if (parentCollection.hasChildCollectionNoLock(broker, resourceName)) { |
| 453 | + // URI indicates a Collection |
| 454 | + |
| 455 | + try (final Collection collection = broker.openCollection(pathUri, Lock.LockMode.READ_LOCK)) { |
| 456 | + |
| 457 | + // asymmetrical locking - unlock parent |
| 458 | + parentCollection.close(); |
| 459 | + |
| 460 | + return collection.getPermissions(); |
| 461 | + } |
| 462 | + } else { |
| 463 | + // URI indicates a Document |
| 464 | + |
| 465 | + try (final LockedDocument lockedDocument = parentCollection.getDocumentWithLock(broker, resourceName, Lock.LockMode.READ_LOCK)) { |
| 466 | + |
| 467 | + // asymmetrical locking - unlock parent |
| 468 | + parentCollection.close(); |
| 469 | + |
| 470 | + if (lockedDocument != null) { |
| 471 | + return lockedDocument.getDocument().getPermissions(); |
| 472 | + } |
| 473 | + } catch (final LockException e) { |
| 474 | + throw new PermissionDeniedException(e.getMessage(), e); |
| 475 | + } |
| 476 | + } |
422 | 477 | } |
423 | | - } |
424 | 478 |
|
425 | | - return permissions; |
| 479 | + throw new XPathException(this, "Resource or collection '" + pathUri + "' does not exist."); |
| 480 | + } |
426 | 481 | } |
427 | 482 |
|
428 | 483 | private org.exist.dom.memtree.DocumentImpl permissionsToXml(final Permission permission) { |
|
0 commit comments