/** * Fetches properties for a path. * * @param string $path * @param PropFind $propFind * @return void */ public function propFind($path, PropFind $propFind) { try { $node = $this->tree->getNodeForPath($path); if (!$node instanceof Node) { return; } } catch (ServiceUnavailable $e) { // might happen for unavailable mount points, skip return; } catch (NotFound $e) { // in some rare (buggy) cases the node might not be found, // we catch the exception to prevent breaking the whole list with a 404 // (soft fail) \OC::$server->getLogger()->warning('Could not get node for path: \\"' . $path . '\\" : ' . $e->getMessage(), array('app' => 'files')); return; } $requestedProps = $propFind->get404Properties(); // these might appear $requestedProps = array_diff($requestedProps, $this->ignoredProperties); if (empty($requestedProps)) { return; } if ($node instanceof Directory && $propFind->getDepth() !== 0) { // note: pre-fetching only supported for depth <= 1 $this->loadChildrenProperties($node, $requestedProps); } $props = $this->getProperties($node, $requestedProps); foreach ($props as $propName => $propValue) { $propFind->set($propName, $propValue); } }
/** * Small helper to support PROPFIND with DEPTH_INFINITY. */ private function addPathNodesRecursively(&$propFindRequests, PropFind $propFind) { $newDepth = $propFind->getDepth(); $path = $propFind->getPath(); if ($newDepth !== self::DEPTH_INFINITY) { $newDepth--; } foreach ($this->tree->getChildren($path) as $childNode) { $subPropFind = clone $propFind; $subPropFind->setDepth($newDepth); $subPath = $path ? $path . '/' . $childNode->getName() : $childNode->getName(); $subPropFind->setPath($subPath); $propFindRequests[] = [ $subPropFind, $childNode ]; if (($newDepth === self::DEPTH_INFINITY || $newDepth >= 1) && $childNode instanceof ICollection) { $this->addPathNodesRecursively($propFindRequests, $subPropFind); } } }
/** * Adds tags and favorites properties to the response, * if requested. * * @param PropFind $propFind * @param \Sabre\DAV\INode $node * @return void */ public function handleGetProperties(PropFind $propFind, \Sabre\DAV\INode $node) { if (!$node instanceof \OCA\DAV\Connector\Sabre\Node) { return; } // need prefetch ? if ($node instanceof \OCA\DAV\Connector\Sabre\Directory && $propFind->getDepth() !== 0 && (!is_null($propFind->getStatus(self::TAGS_PROPERTYNAME)) || !is_null($propFind->getStatus(self::FAVORITE_PROPERTYNAME)))) { // note: pre-fetching only supported for depth <= 1 $folderContent = $node->getChildren(); $fileIds[] = (int) $node->getId(); foreach ($folderContent as $info) { $fileIds[] = (int) $info->getId(); } $tags = $this->getTagger()->getTagsForObjects($fileIds); if ($tags === false) { // the tags API returns false on error... $tags = array(); } $this->cachedTags = $this->cachedTags + $tags; $emptyFileIds = array_diff($fileIds, array_keys($tags)); // also cache the ones that were not found foreach ($emptyFileIds as $fileId) { $this->cachedTags[$fileId] = []; } } $tags = null; $isFav = null; $propFind->handle(self::TAGS_PROPERTYNAME, function () use($tags, &$isFav, $node) { list($tags, $isFav) = $this->getTagsAndFav($node->getId()); return new TagList($tags); }); $propFind->handle(self::FAVORITE_PROPERTYNAME, function () use($isFav, $node) { if (is_null($isFav)) { list(, $isFav) = $this->getTagsAndFav($node->getId()); } return $isFav; }); }
/** * Adds shares to propfind response * * @param PropFind $propFind propfind object * @param \Sabre\DAV\INode $sabreNode sabre node */ public function handleGetProperties(PropFind $propFind, \Sabre\DAV\INode $sabreNode) { if (!$sabreNode instanceof \OCA\DAV\Connector\Sabre\Node) { return; } // need prefetch ? if ($sabreNode instanceof \OCA\DAV\Connector\Sabre\Directory && $propFind->getDepth() !== 0 && !is_null($propFind->getStatus(self::SHARETYPES_PROPERTYNAME))) { $folderNode = $this->userFolder->get($propFind->getPath()); $children = $folderNode->getDirectoryListing(); $this->cachedShareTypes[$folderNode->getId()] = $this->getShareTypes($folderNode); foreach ($children as $childNode) { $this->cachedShareTypes[$childNode->getId()] = $this->getShareTypes($childNode); } } $propFind->handle(self::SHARETYPES_PROPERTYNAME, function () use($sabreNode) { if (isset($this->cachedShareTypes[$sabreNode->getId()])) { $shareTypes = $this->cachedShareTypes[$sabreNode->getId()]; } else { $node = $this->userFolder->get($sabreNode->getPath()); $shareTypes = $this->getShareTypes($node); } return new ShareTypeList($shareTypes); }); }