subconsciousnetwork / subconscious

Apache License 2.0
8 stars 0 forks source link

File sync seems overeager on iPhone #57

Closed gordonbrander closed 2 years ago

gordonbrander commented 2 years ago

The issue

iOS app document containers exist have a symlinked equivalent:

/var/mobile/Containers/Data/Application/...
/private/var/mobile/Containers/Data/Application/...

Not sure which of these is the symlink, but anyway, Apple's APIs are not consistent w/r/t which is returned.

Furthermore, its URL type (https://developer.apple.com/documentation/foundation/url) does not have a relativization method. You must get the string path and relativize through string methods.

Taken together, This makes relativizing URLs difficult.

Luckily, there is a property of URL, .standardizedFileURL (https://developer.apple.com/documentation/foundation/url/2293229-standardizedfileurl) which will resolve symlinks, giving you a consistent path for a given file.

HOWEVER, if you drop the path extension through url.deletePathExtension(), .standardizedFileURL no longer recognizes the URL as a file URL, and does not normalize it.

Resolution

Our extension method, .relativizingPath calls .standardizedFileURL to normalize the URL and base URL, then relativizes the URL by removing the prefixed base URL from the string path.

It is extremely important that we call relativizingPath WITHOUT calling url.deletePathExtension().

Instead, we relativize the path, get back a string, and then use our custom String extension to remove the file extension from the string path.

gordonbrander commented 2 years ago

Note that application Documents folder changes between builds:

Example of two Documents folders from different builds of same revision on same phone:

file:///var/mobile/Containers/Data/Application/88454EB2-8141-434E-AD93-F993D1561224/Documents/

file:///var/mobile/Containers/Data/Application/4D00F078-7C28-4F0D-B4DB-90A288A07251/Documents/

Could it be that iOS copies the files over to the new location, thus modifying timestamps?

Update: see next comment. It looks like the timestamps are unchanged.

gordonbrander commented 2 years ago

Another note:

Change(url: file:///var/mobile/Containers/Data/Application/88454EB2-8141-434E-AD93-F993D1561224/Documents/magic-circle-phrases.subtext, status: rightOnly),
Change(url: file:///private/var/mobile/Containers/Data/Application/88454EB2-8141-434E-AD93-F993D1561224/Documents/Applying%20a%20known%20process%20to%20known%20information%20to%20reveal%20latent%20information.subtext, status: leftOnly),
Change(url: file:///var/mobile/Containers/Data/Application/88454EB2-8141-434E-AD93-F993D1561224/Documents/2021-07-14-quote.subtext, status: rightOnly),
Change(url: file:///var/mobile/Containers/Data/Application/88454EB2-8141-434E-AD93-F993D1561224/Documents/oneness-by-thich-nhat-hanh.subtext, status: rightOnly),
Change(url: file:///var/mobile/Containers/Data/Application/88454EB2-8141-434E-AD93-F993D1561224/Documents/genes-used-together-are-fused-together.subtext, status: rightOnly),
Change(url: file:///private/var/mobile/Containers/Data/Application/88454EB2-8141-434E-AD93-F993D1561224/Documents/The%20internet%20works%20over%20a%20wide%20range%20of%20infrastructure.subtext, status: leftOnly),
Change(url: file:///var/mobile/Containers/Data/Application/88454EB2-8141-434E-AD93-F993D1561224/Documents/meta-preferential-attachment.subtext, status: rightOnly),
Change(url: file:///var/mobile/Containers/Data/Application/88454EB2-8141-434E-AD93-F993D1561224/Documents/satori.subtext, status: rightOnly),
Change(url: file:///private/var/mobile/Containers/Data/Application/88454EB2-8141-434E-AD93-F993D1561224/Documents/dao.subtext, status: leftOnly)

Notice that some of these start with file:///private/var/, and others start with file:///var/.

These seem to correspond with /var/ is .rightOnly and /private/var/ is .leftOnly. Are we absolutizing for one code path and not another?

How might this affect things (I think we relativize paths?)

Ok, it looks like we're getting 2 changes for every file: one for the left (/var/private/ path) and one for the right (/var/ path).

gordonbrander commented 2 years ago

It's because

FileManager.default.contentsOfDirectory(
    at: directory,
    includingPropertiesForKeys: nil,
    options: .skipsHiddenFiles
)

returns paths with file:///private/var/ and the API that gets us the directory (documents directory) does not.

URL.standardizedFileURL is supposed to resolve this (it's a symlink thing), but it doesn't anymore.

gordonbrander commented 2 years ago

WOAH this is caused by .deletingPathExtension() being called before .relativizingPath().

This should not matter, since . standardizedFileURL is called within .relativizingPath(), and should give us a normalized URL, but I'm guessing the normalization code borks without a file extension.

UUUUUGGHHH Foundation URL is a mess.