Skip to content

Commit

Permalink
Replace createWriter, FileSystemWriter with createWritable, WritableF…
Browse files Browse the repository at this point in the history
…ileStream

This adds specs for `WritableFileStream` and options.

It links to `WritableStreams` related specs, with an inheritance
relationship.
  • Loading branch information
oyiptong committed Dec 23, 2019
1 parent 051d26c commit 5892f07
Showing 1 changed file with 108 additions and 71 deletions.
179 changes: 108 additions & 71 deletions index.bs
Original file line number Diff line number Diff line change
Expand Up @@ -187,15 +187,15 @@ The <dfn method for=FileSystemHandle>requestPermission(|descriptor|)</dfn> metho
## The {{FileSystemFileHandle}} interface ## {#api-filesystemfilehandle}

<xmp class=idl>
dictionary FileSystemCreateWriterOptions {
dictionary FileSystemCreateWritableOptions {
boolean inPlace = false;
boolean keepExistingData = false;
};

[Exposed=(Window,Worker), SecureContext, Serializable]
interface FileSystemFileHandle : FileSystemHandle {
Promise<File> getFile();
Promise<FileSystemWriter> createWriter(optional FileSystemCreateWriterOptions options);
Promise<FileSystemWritableFileStream> createWritable(optional FileSystemCreateWritableOptions options);
};
</xmp>

Expand All @@ -218,41 +218,47 @@ The <dfn method for=FileSystemFileHandle>getFile()</dfn> method, when invoked, m

</div>

### The {{FileSystemFileHandle/createWriter()}} method ### {#api-filesystemfilehandle-createwriter}
### The {{FileSystemFileHandle/createWritable()}} method ### {#api-filesystemfilehandle-createwritable}

<div class="note domintro">
: |writer| = await |fileHandle| . {{FileSystemFileHandle/createWriter()}}
: |writer| = await |fileHandle| . {{FileSystemFileHandle/createWriter()|createWriter}}({ {{FileSystemCreateWriterOptions/inPlace}}: false })
: |writer| = await |fileHandle| . {{FileSystemFileHandle/createWriter()|createWriter}}({ {{FileSystemCreateWriterOptions/keepExistingData}}: |keepExistingData|, {{FileSystemCreateWriterOptions/inPlace}}: false })
:: Returns a {{FileSystemWriter}} that can be used to write to the file. Any changes made through
|writer| won't be reflected in the file represented by |fileHandle| until its
{{FileSystemWriter/close()}} method is called.
: |stream| = await |fileHandle| . {{FileSystemFileHandle/createWritable()}}
: |stream| = await |fileHandle| . {{FileSystemFileHandle/createWritable()|createWritable}}({ {{FileSystemCreateWritableOptions/inPlace}}: false })
: |stream| = await |fileHandle| . {{FileSystemFileHandle/createWritable()|createWritable}}({ {{FileSystemCreateWritableOptions/keepExistingData}}: |keepExistingData|, {{FileSystemCreateWritableOptions/inPlace}}: false })
:: Returns a {{FileSystemWritableFileStream}} that can be used to write to the file. Any changes made through
|stream| won't be reflected in the file represented by |fileHandle| until its
{{FileSystemWritableFileStream/close()}} method is called.
User agents try to ensure that no partial writes happen, i.e. the file represented by
|fileHandle| will either contains its old contents or it will contain whatever data was written
through |writer| up until one of these methods was called.
through |stream| up until one of these methods was called.

This is typically implemented by writing data to a temporary file, and only replacing the file
represented by |fileHandle| with the temporary file when the writer is closed.
represented by |fileHandle| with the temporary file when the writable filestream is closed.

If |keepExistingData| is `false` or not specified, the temporary file starts out empty,
otherwise the existing file is first copied to this temporary file.

: |writer| = await |fileHandle| . {{FileSystemFileHandle/createWriter()|createWriter}}({ {{FileSystemCreateWriterOptions/inPlace}}: true })
: |writer| = await |fileHandle| . {{FileSystemFileHandle/createWriter()|createWriter}}({ {{FileSystemCreateWriterOptions/keepExistingData}}: |keepExistingData|, {{FileSystemCreateWriterOptions/inPlace}}: true })
:: Returns a {{FileSystemWriter}} that can be used to write to the file. Any changes made through
|writer| might not be reflected in the file represented by |fileHandle| until its
{{FileSystemWriter/close()}} method is called.
|stream| is a {{WritableStream}}. An underlying sink will have been created and the stream
initialized for use.

: |stream| = await |fileHandle| . {{FileSystemFileHandle/createWritable()|createWritable}}({ {{FileSystemCreateWritableOptions/inPlace}}: true })
: |stream| = await |fileHandle| . {{FileSystemFileHandle/createWritable()|createWritable}}({ {{FileSystemCreateWritableOptions/keepExistingData}}: |keepExistingData|, {{FileSystemCreateWritableOptions/inPlace}}: true })
:: Returns a {{FileSystemWritableFileStream}} that can be used to write to the file. Any changes made through
|stream| might not be reflected in the file represented by |fileHandle| until its
{{FileSystemWritableFileStream/close()}} method is called.
User agents are free to either flush changes to the file as they are made, or batch them
up (possibly by writing to some kind of change log) until {{FileSystemWriter/close()}}
up (possibly by writing to some kind of change log) until {{FileSystemWritableFileStream/close()}}
is called. Specifically for less trusted websites, user agents
will want to batch up changes so that malware scanners or other security checks can be
performed before actually flushing changes to disk.

If |keepExistingData| is `false` or not specified, the file will start out empty.

|stream| is a {{WritableStream}}. An underlying sink will have been created and the stream
initialized for use.
</div>

<div algorithm>
The <dfn method for=FileSystemFileHandle>createWriter(|options|)</dfn> method, when invoked, must run these steps:
The <dfn method for=FileSystemFileHandle>createWritable(|options|)</dfn> method, when invoked, must run these steps:

1. TODO

Expand Down Expand Up @@ -426,107 +432,138 @@ these steps:

</div>

## The {{FileSystemWriter}} interface ## {#api-filesystemwriter}
## The {{FileSystemWritableFileStream}} interface ## {#api-filesystemwritablefilestream}

<xmp class=idl>
enum WriteCommandType {
"truncate",
"seek",
"write",
};

dictionary WriteParams {
required WriteCommandType type;
unsigned long long? size;
unsigned long long? position;
(BufferSource or Blob or USVString)? data;
};

[Exposed=(Window,Worker), SecureContext]
interface FileSystemWriter {
Promise<void> write(unsigned long long position, (BufferSource or Blob or USVString) data);
WritableStream asWritableStream();
interface FileSystemWritableFileStream : WritableStream {
Promise<void> write((BufferSource or Blob or USVString or WriteParams) data);
Promise<void> seek(unsigned long long position);
Promise<void> truncate(unsigned long long size);
Promise<void> close();
};
</xmp>

A {{FileSystemWriter}} has an associated <dfn for=FileSystemWriter>atomic flag</dfn>.
A {{FileSystemWritableFileStream}} object is a {{WritableStream}} object with additional methods to operate
on a single file on disk.


### The {{FileSystemWriter/write()}} method ### {#api-filesystemwriter-write}
Upon creation, an underlying sink will have been created and the stream will be usable. All operations executed on the stream are queuable and producers will be able to respond to backpressure.

The underlying sink's write method, and therefore {{WritableStreamDefaultWriter/write()|WritableStreamDefaultWriter's write()}} method, will accept byte-like data or {{WriteParams}} as input.

The {{FileSystemWritableFileStream}} has an file position cursor initialized at the byte offset 0 from the top of the file. When using {{FileSystemWritableFileStream/write()|write()}} or by using WritableStream capabilities through the {{WritableStreamDefaultWriter/write()|WritableStreamDefaultWriter's write()}} method, this position will be advanced based on the number of bytes written through this stream object.

Similarly, when piping a {{ReadableStream}} into a {{FileSystemWritableFileStream}} object, this position is updated with the number of bytes that passed through the stream.

{{WritableStream/getWriter()|WritableStream's getWriter()}} method returns an instance of {{WritableStreamDefaultWriter}}.

### The {{FileSystemWritableFileStream/write()}} method ### {#api-filesystemwritablefilestream-write}

<div class="note domintro">
: await |writer| . {{FileSystemWriter/write()|write}}(|position|, |data|)
:: Writes the content of |data| into the file associated with |writer| at position |position|.
If |position| is past the end of the file writing will fail and this method rejects.
: await |stream| . {{FileSystemWritableFileStream/write()|write}}(|data|)
:: This method is similar to {{WritableStreamDefaultWriter/write()|WritableStreamDefaultWriter's write()}}
with some behavior specific to {{FileSystemWritableFileStream}}.

Writes the content of |data| into the file associated with |stream| at the current file
cursor offset in bytes from the top of the file by default.

There are no guarantees that the data written to the file using this method is actually
reflected in the file on disk until the {{FileSystemWriter/close()}}
method is called. Specifically when |writer|'s
[=atomic flag=] is set, the user agent will ensure that no changes are written to the actual
reflected in the file on disk until the {{FileSystemWritableFileStream/close()}}
method is called. Specifically when |stream| has been created with
{{FileSystemCreateWritableOptions/inPlace|inPlace}} set to false, the user agent will ensure that no changes are written to the actual
file until one of those methods is called.
</div>
: await |stream| . {{FileSystemWritableFileStream/write()|write}}(|write_params|)
:: This method is similar to {{WritableStreamDefaultWriter/write()|WritableStreamDefaultWriter's write()}}
with some behavior specific to {{FileSystemWritableFileStream}}.

<div algorithm>
The <dfn method for=FileSystemWriter>write(|position|, |data|)</dfn> method, when invoked, must run
these steps:
Interprets and validates the content of |write_params|, which might result in
changes into the file associated with |stream|.

1. TODO
{{WriteParams}} requires the attribute {{WriteParams/type|type}} which determines what the operations to
execute are.

</div>
If {{WriteParams/type|type}} is {{truncate}}, {{WriteParams/size|size}} is a <span class=allow-2119>required</span> attribute.

### The {{FileSystemWriter/asWritableStream()}} method ### {#api-filesystemwriter-aswritablestream}
If {{WriteParams/type|type}} is {{seek}}, {{WriteParams/position|position}} is a <span class=allow-2119>required</span> attribute.

Issue(19): The functionality described by this method will likely stay, but the exact shape of
the method is still in flux even more than the rest of this specification.

<div class="note domintro">
: let |stream| = |writer| . {{FileSystemWriter/asWritableStream()}}
:: Returns a {{WritableStream}} that can be used to write data into the file, starting
at the beginning of the file.
If {{WriteParams/type|type}} is {{write}}, {{WriteParams/position|position}} is an <span class=allow-2119>optional</span> attribute, {{WriteParams/data|data}} is a <span class=allow-2119>required</span> attribute.

There are no guarantees that the data written to the file using this method is actually
reflected in the file on disk until the {{FileSystemWriter/close()}}
method is called. Specifically when |writer|'s
[=atomic flag=] is set, the user agent will ensure that no changes are written to the actual
reflected in the file on disk until the {{FileSystemWritableFileStream/close()}}
method is called. Specifically when |stream| has been created with
{{FileSystemCreateWritableOptions/inPlace|inPlace}} set to false, the user agent will ensure that no changes are written to the actual
file until one of those methods is called.
</div>

<div algorithm>
The <dfn method for=FileSystemWriter>asWritableStream()</dfn> method, when invoked,
must run these steps:
The <dfn method for=FileSystemWritableFileStream>write(|data|)</dfn> method, when invoked, must run
these steps:

1. TODO

</div>

### The {{FileSystemWriter/truncate()}} method ### {#api-filesystemwriter-truncate}
### The {{FileSystemWritableFileStream/truncate()}} method ### {#api-filesystemwritablefilestream-truncate}

<div class="note domintro">
: await |writer| . {{FileSystemWriter/truncate()|truncate}}(|size|)
:: Resizes the file associated with |writer| to be |size| bytes long. If |size| is larger than
: await |stream| . {{FileSystemWritableFileStream/truncate()|truncate}}(|size|)
:: Resizes the file associated with |stream| to be |size| bytes long. If |size| is larger than
the current file size this pads the file with zero bytes, otherwise it truncates the file.

The file cursor is updated when {{truncate}} is called. If the offset is smaller than offset,
it remains unchanged. If the offset is larger than |size|, the offset is set to |size| to
ensure that subsequent writes do not error.

There are no guarantees that the changes made to the file using this method are actually
reflected in the file on disk until the {{FileSystemWriter/close()}}
method is called. Specifically when |writer|'s
[=atomic flag=] is set, the user agent will ensure that no changes are written to the actual
file until one of those methods is called.
reflected in the file on disk until the {{FileSystemWritableFileStream/close()}}
method is called. Specifically when |stream|'s
{{FileSystemCreateWritableOptions/inPlace|inPlace}} is set to false, the user agent will ensure that no changes are written to
the actual file until one of those methods is called.
</div>

<div algorithm>
The <dfn method for=FileSystemWriter>truncate(|size|)</dfn> method, when invoked, must run these
The <dfn method for=FileSystemWritableFileStream>truncate(|size|)</dfn> method, when invoked, must run these
steps:

1. TODO

</div>

### The {{FileSystemWriter/close()}} method ### {#api-filesystemwriter-close}
### The {{FileSystemWritableFileStream/close()}} method ### {#api-filesystemwritablefilestream-close}

<div class="note domintro">
: await |writer| . {{FileSystemWriter/close()}}
:: First flushes any data written so far to disk, and then closes the writer.
If |writer|'s [=atomic flag=] is set, no changes will
be visible in the file until this method is called.
Furthermore, if the file on disk changed between creating this |writer| and this invocation of
{{FileSystemWriter/close()}}, this will reject and all future operations on the writer will
fail.

This operation can take some time to complete (even if the |writer|'s [=atomic flag=] is not
set), as user agents might use this moment to run malware scanners or perform other security
checks if the website isn't sufficiently trusted.
: await |stream| . {{FileSystemWritableFileStream/close()}}
:: This method is similar to {{WritableStreamDefaultWriter/close()|WritableStreamDefaultWriter's close()}}
with some behavior specific to {{FileSystemWritableFileStream}}.

First flushes any data written so far to disk, and then closes the writable filestream.
If |stream|'s {{FileSystemCreateWritableOptions/inPlace|inPlace}} option is set to false, no changes will be visible in the
file until this method is called.

Furthermore, if the file on disk changed between creating this |stream| and this
invocation of {{FileSystemWritableFileStream/close()}}, this will reject and all future
operations on the writable filestream will fail.

This operation can take some time to complete (even if the |stream|'s {{FileSystemCreateWritableOptions/inPlace|inPlace}} option
is set to false), as user agents might use this moment to run malware scanners or perform
other security checks if the website isn't sufficiently trusted.
</div>

<div algorithm>
The <dfn method for=FileSystemWriter>close()</dfn> method, when invoked, must run these
The <dfn method for=FileSystemWritableFileStream>close()</dfn> method, when invoked, must run these
steps:

1. TODO
Expand Down

0 comments on commit 5892f07

Please sign in to comment.