Re: Polished FileSystem API proposal

On Tue, Jul 16, 2013 at 12:32 AM, Jonas Sicking <jonas@sicking.cc> wrote:
> On Mon, Jul 15, 2013 at 11:02 PM, Kinuko Yasuda <kinuko@chromium.org> wrote:
>> Glad to see this proposal has a new draft.
>>
>> On Sat, Jul 13, 2013 at 9:31 AM, Jonas Sicking <jonas@sicking.cc> wrote:
>>>
>>> Executive Summary (aka TL;DR):
>>> Below is the mozilla proposal for a simplified filesystem API. It
>>> contains two new abstractions, a Directory object which allows
>>> manipulating files and directories within it, and a FileHandle object
>>> which allows holding an exclusive lock on a file while performing
>>> multiple read/write operations on it.
>>>
>>> It's largely modeled after posix, but because we've tried to keep it
>>> author friendly despite it's asynchronous nature, it differs in a few
>>> cases.
>>>
>>> There are opportunities for further simplifications by straying
>>> further from posix. It's unclear if this is desired or not.
>>>
>>> Detailed proposal:
>>>
>>> partial interface Navigator {
>>>   Promise<Directory> getFilesystem(optional FilesystemParameters
>>> parameters);
>>> };
>>>
>>> interface Directory {
>>>   readonly attribute DOMString name;
>>
>>
>> So neither File nor Directory has 'path' attribute but only exposes 'name'.
>> It feels a bit inconvenient but is it intentional?
>
> It's something that I intended to add but forgot.

Having the full path within the filesystem removes some of the
security benefit of not allowing "..", doesn't it?  Conversely, is the
path useful if you can't use it to manipulate anything above the
current dir in the tree?

> Keeping .name as just containing the leafname is probably the right thing to do.
>
> So we could introduce a .path property which contains the path within
> the filesystem. The full filename would be .path + .name.
>
> And doing exactly the same for both Directory and File objects seems
> like a good thing.
>
>> File object is meant to be a snapshot and becomes invalid after modification
>> is made.
>> Will Directory follow the same model?
>> Say, if a Directory is acquired then moved (renamed) to another name, does
>> the Directory object keep functioning or become invalid?
>
> Good question. I think the most sane way to implement the Directory
> object is to internally keep a full path. Whenever an operation is to
> be performed, we check if that full path still exists. If it doesn't,
> the operation fails.

Just to be clear: if you rename a Directory's parent, it goes stale
and you can't use it.  But if you then create a new directory with the
same name as the parent used to have, with a child of the right name,
this object will again be valid.  The Directory is explicitly defined
as referring to a specific path string.

>>>   Promise<File> createFile(DOMString path, MakeFileOptions options);
>>>   Promise<Directory> createDirectory(DOMString path);
>>>
>>>   Promise<(File or Directory)> get(DOMString path);
>>>
>>>   Promise<void> move((DOMString or File or Directory) entry,
>>>                      (DOMString or Directory or DestinationDict) dest);
>>>   Promise<void> copy((DOMString or File or Directory) entry,
>>>                      (DOMString or Directory or DestinationDict) dest);
>>>   Promise<boolean> remove((DOMString or File or Directory) path,
>>>                        optional DeleteMode recursive = "nonrecursive");
>>
>>
>> One of the major requests we've gotten in Chrome's FS API for potentially
>> long-running copy/remove operations is the ability to get progress and to
>> abort the operation.
>> Does it make sense to make them return AbortableProgressPromise when they
>> run recursively?
>
> Yeah, I think that's a good idea. We have to figure out exactly what
> the progress information would look like, but that seems very doable.
>
>> It's possible that an app creates tons of files in a directory and then
>> copies the entire directory to another, which could take long time
>> (depending on implementation).
>>
>> (Also +1 to have a separate method for recursiveRemove or removeDepp)
>
> Done. Though I'd still like to remove the non-recursive variant. Is it
> really useful?
>
>>>   Promise<FileHandle> openRead((DOMString or File) file);
>>>   Promise<FileHandleWritable> openWrite((DOMString or File) file,
>>>         optional CreateMode createMode = "createifneeded");
>>>   Promise<FileHandleWritable> openAppend((DOMString or File) file,
>>>         optional CreateMode createMode = "createifneeded");
>>>
>>>   EventStream<(File or Directory)> enumerate();
>>>   EventStream<File> enumerateDeep();
>>
>>
>> Can this enumeration/stream be stopped halfway?  If a directory contains
>> thousands of files callers may not want to keep the disk spinning until the
>> enumeration reaches the end.
>
> EventStream is something that still needs to be defined. And shouldn't
> be a filesystem specific interface. But yes, it definitely needs to be
> stoppable halfway. Maybe we'll need something like
> AbortableEventStream, or PausableEventStream, or some such.
>
>>> The FileHandle class automatically closes itself as soon as the page
>>> stops posting further calls to .read/.readBinary/.write to it. This
>>> happens once the last Promise returned from one of those operations
>>> has been resolved, without further calls to .read/.readBinary/.write
>>> having happened.
>>
>> Can the same FileHandle be reused after it's closed, or one need to create a
>> new FileHandler to start another sequence of read/write?
>
> Once it's closed, i.e. once the last accept/reject callback has
> happened and no new operations were started, the FileHandle becomes
> useless. You have to call openRead/openWrite again to start another
> sequence.
>
> / Jonas
>

Received on Tuesday, 16 July 2013 15:53:51 UTC