Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I see if some folder is a child of another using NSURL?

Tags:

swift

cocoa

nsurl

I have an [URL] which represent a set of special parent directories. I am given another [URL] which represents files scattered around the system. I want to know if any of these files are in any of my special directories, or any of their subdirectories. Is there a simple/intended way to do this, without manually parsing/traversing an absolute URL's path?

like image 677
Ky. Avatar asked Oct 12 '25 19:10

Ky.


2 Answers

A slightly improved, Swift 5 version combining nice features of both Umair and rmaddy's existing excellent answers.

Like Umair's answer, this correctly handles the case where a folder in the path is a partial match (that is, it will not say that /foo/bar-baz/bang has /foo/bar/ as an ancestor).

It also performs the canonicalization (standardizing paths to eliminate things like . or ../, and resolving symlinks) like rmaddy's answer.

func pathHasAncestor(maybeChild: URL, maybeAncestor: URL) -> Bool {
    let ancestorComponents: [String] = canonicalize(maybeAncestor).pathComponents
    let childComponents: [String] = canonicalize(maybeChild).pathComponents

    return ancestorComponents.count < childComponents.count
        && !zip(ancestorComponents, childComponents).contains(where: !=)
}

func canonicalize(_ url: URL) -> URL {
    url.standardizedFileURL.resolvingSymlinksInPath()
}

Here's a very simple unit test to verify the basic functionality:

import XCTest

class FileUtilsTests: XCTestCase {
    func testPathHasAncestor() throws {
        let leaf = URL(fileURLWithPath: "/foo/bar/baz")
        let parent = leaf.deletingLastPathComponent()
        XCTAssertTrue(pathHasAncestor(maybeChild: leaf, maybeAncestor: parent))
        XCTAssertFalse(pathHasAncestor(maybeChild: URL(fileURLWithPath: "/foo/bar 1/baz"), maybeAncestor: parent))
        XCTAssertFalse(pathHasAncestor(maybeChild: leaf, maybeAncestor: leaf))
    }
}
like image 195
s3cur3 Avatar answered Oct 14 '25 21:10

s3cur3


There's no method in NSURL that lets you see if another NSURL represents the root path of the other.

One possible solution is to convert the two URLs to path strings using the path property. Then see if one string is the prefix of the other. But before getting the URL's path, use both URLByStandardizingPath and URLByResolvingSymlinksInPath to ensure a consistent result.

Example:

NSURL *specialURL = ... // a URL for one of the special parent directories
NSURL *fileURL = ... // a URL for one of the files to check
NSString *specialPath = [specialURL.URLByStandardizingPath.URLByResolvingSymlinksInPath.path stringByAppendingString:@"/"];
NSString *filePath = fileURL.URLByStandardizingPath.URLByResolvingSymlinksInPath.path
if ([filePath hasPrefix:specialPath]) {
    // This file is in this special directory
}
like image 34
rmaddy Avatar answered Oct 14 '25 21:10

rmaddy



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!