Re: [whatwg] Using requestFileSystem to setup mounts
Hi, what about window.MOUNT_ONCE - mount only for current session - would open select folder dialog window.MOUNT_ALWAYS - mount for all time (or to be more precise for the time of life time of IndexDB, cookies, etc). - user have to give explicit permission for this and only after this permission is given, select folder dialog is opened - delete browser data (IndexDB, cookies, etc) would only remove permission to access such folder, not it's content FileSystem interface has property name, so programmers could distinguish among several FileSystem object and could store those somewhere (e.g. LocalStorage). if folder, which is already mounted, was selected from select directory dialog, than already existing FileSystem object would be returned corresponding with that directory (e.g. fs.name = '123-456-abc' is created once c:/tmp is requested and that FileSystem object would be always returned if the same folder is requested). Name property would than probably have to be some kind of hash of the original directory path (so it's unique across users desktop file system) This could be very important feature, because currently there is no (real) persistent storage, even when window.PERSISTENT file system is created, data can be removed by just users desire to delete cookies (browser generally do not allow to specifie what kind data should be removed [cookies/indexdb/websql/app cache/local storage/etc.] At this point, it's quite a pain to e.g. create export file from data you already have in browser without accessing server... The only problem I see with this approach is that it does not allow very common screnario: save file as in regular desktop app way: 1/ user clicks save 2/ save as dialog is opened and file (file name with path) is returned 3/ app creates file based on that path 4/ app writes data to file having only FS mounted to directory would require: 1/ have someinput type=text where user writes file name 2/ user types file name to that input 3/ user clicks save 4/ select folder dialog is opened, FileSystem is returned in callback 5/ app creates file based on returned FileSystem and file name from step 1 6/ app writes data to file in desktop app scenario user specifies whole file path, in requestFileSystem scenario, user would have to specifie file name and then path... quite a different behaviour from what users are used to (users are used to desktop app behaviour even in browser when downloading file from internet)... B. On 21.11.2011 15:10, Kinuko Yasuda wrote: Additionally, I might pass window.MOUNT into rFS, which may prompt the user to select a mount point, bypassinginputaltogether. This sounds cool, and I think eventually we want to have some explicit way to mount an arbitrary directory in a way this (requestFileSystem(MOUNT)), but what concerns me most in this generalized API is how we should define the lifetime of the mount'ed filesystem. -Charles
Re: [whatwg] Using requestFileSystem to setup mounts
On Mon, Nov 28, 2011 at 9:18 AM, Kinuko Yasuda kin...@chromium.org wrote: On Wed, Nov 23, 2011 at 1:58 AM, Glenn Maynard gl...@zewt.org wrote: This would lead to interop problems if it's not consistent, though. For example, if my application creates ZIP files, and the user drags two files into the root directory of the ZIP, he wants to put those files at the top of the ZIP: /file1.txt /file2.txt If the UA creates a virtual directory for that drag, then it'd end up putting the files in a subdirectory with the name of the virtual directory, as if a directory was dragged: /drag-and-drop/file1.txt /drag-and-drop/file2.txt The UA can simply puts the file1.txt and file2.txt in the virtual 'root' directory if Entry.fullPath matters. The problem is that a drop event with two separate files will probably be treated differently by some software than one with a single directory containing two files. That'll be true no matter what Entry.fullPath is set to. That's why it'd be an interop problem if some browsers do this and some don't. (I don't think the value of Entry.fullPath is very important for drops. It can probably just be /.) -- Glenn Maynard
Re: [whatwg] Using requestFileSystem to setup mounts
On Tue, Nov 22, 2011 at 7:30 AM, Glenn Maynard gl...@zewt.org wrote: On Mon, Nov 21, 2011 at 4:33 PM, Charles Pritchard ch...@jumis.com wrote: Multiple directories still have a shared file system root. Their relative paths are exposed in webkitdirectory files already. The benefit is neutered .files object while maintaining compatibility with existing code bases. It would be strange to drag in multiple directories and to have it exposed as a virtual directory containing the dragged files. It could be done, but it's inconsistent with the design of DataTransfer, and it feels unnatural. I don't know what you mean by compatibility with existing code bases; the compatibility is no different than a getAsEntry/getAsWritableEntry API would be. Putting aside the API discussion, actually I like the idea having one shared isolated filesystem that contains multiple directories/files being dropped in, as in that way both the UA and script can easily distinguish the set of dropped files/directories as a single group sharing the same filesystem object. I don't think that must be enforced as a part of spec or recommendation, but I don't think it's strange having multiple files/directories being dropped in the same virtual root directory either. (I'm not saying we should weigh rFS approach more than .entries or getAsEntry) Also, remember that DataTransfer objects can be filled in programmatically. You can do, for example: dt.items.add(hello world, text/plain); // already supported dt.items.add(myFile); // already supported dt.items.add(myFileEntry); // new DataTransferItemList.add(Entry data) method dt.items.add(myDirectoryEntry); The requestFileSystem approach doesn't fit with DataTransfer's design very naturally. (Adding a File would be equivalent to adding a FileEntry containing the File; both would just create a DataTransferItem with a kind of file.) What values will Entry.filesystem and Entry.fullpath have? Each Entry would have a dummy FileSystem object attached to it, in order to fill out the Entry.filesystem API, but all it would contain is the file itself. Again I think this could be left to the UA's implementation decision. Entry.fullPath would be the same as Entry.name, prefixed with /. As synchronous methods, won't these block the user if they need to confirm permission to mount a directory? As async methods, these might add a lot of calls to the stack. Async methods (eg. theoretically getAsWritableEntry) is adding no more calls than would be added by a similar async requestFileSystem call, which is also async. getAsEntry gives read-only access; as with getAsFile, there's no additional permission prompt. Both methods could be async if we really want to allow for separate permissions prompting even for read-only access (though that's awkward UI, especially *during* a drag). Either way, it's no more code for users than a requestFileSystem call. Recursing directories is the current behavior of webkitdirectory. Yes, this should go away if possible, or at least not be propagated to other browsers. It's not a scalable approach, as we discussed earlier. -- Glenn Maynard
Re: [whatwg] Using requestFileSystem to setup mounts
On Tue, Nov 22, 2011 at 6:06 AM, Kinuko Yasuda kin...@chromium.org wrote: Putting aside the API discussion, actually I like the idea having one shared isolated filesystem that contains multiple directories/files being dropped in, as in that way both the UA and script can easily distinguish the set of dropped files/directories as a single group sharing the same filesystem object. I don't think that must be enforced as a part of spec or recommendation, but I don't think it's strange having multiple files/directories being dropped in the same virtual root directory either. (I'm not saying we should weigh rFS approach more than .entries or getAsEntry) This would lead to interop problems if it's not consistent, though. For example, if my application creates ZIP files, and the user drags two files into the root directory of the ZIP, he wants to put those files at the top of the ZIP: /file1.txt /file2.txt If the UA creates a virtual directory for that drag, then it'd end up putting the files in a subdirectory with the name of the virtual directory, as if a directory was dragged: /drag-and-drop/file1.txt /drag-and-drop/file2.txt Each Entry would have a dummy FileSystem object attached to it, in order to fill out the Entry.filesystem API, but all it would contain is the file itself. Again I think this could be left to the UA's implementation decision. The main point is just that a FileSystem object will always be available, even if the UA is only exposing one file in a directory which contains other (inaccessible) files. Most of the time it wouldn't be used, it just avoids exceptional cases in the API. (In other words, Entry.filesystem would not become nullable.) -- Glenn Maynard
Re: [whatwg] Using requestFileSystem to setup mounts
Hi, thanks for your comment! On Sun, Nov 20, 2011 at 5:54 AM, Charles Pritchard ch...@jumis.com wrote: Kinuko Yasuda, I saw your post to whatwg regarding drag-and-drop directory mounts. I'm sure you've seen the various concerns people have with the proposal.. Like others, I'm also concerned about the security implications of traversing a directory and sealing the action upon drop, or otherwise setting up a mount point. That said, directory is still an extension and open to change: http://lists.whatwg.org/htdig.cgi/whatwg-whatwg.org/2010-April/025764.html http://www.whatwg.org/specs/web-apps/current-work/multipage/number-state.html#file-upload-state I'd like to consider your proposal in light of the existing requestFileSystem method. requestFileSystem is still very much open and under experiment with Chromium. For example: // Typical use of rFS: window.requestFileSystem(window.PERSISTENT, 1*1024*1024, cb); // Proposal, using DataTransfer with rFS: input.ondrop = function(e) { window.requestFileSystem(e.dataTransfer, 0, cb); } This looks neat, though this would do almost same as what I was assuming the internal implementation would do. One clear benefit I found in your proposal is the code would make the fact that the UA is actually instantiating a new filesystem per drop clearer. On the other hand I'm afraid this may slightly complicate the API by overloading the requestFileSystem. There's some slight room for delaying the population of e.dataTransfer.files, by using a long-running for loop, or something of that sort. Otherwise, if rFS is used, .files will not be populated. This avoids directory traversal overhead while using rFS for permissions management. I may not be quite following this point. I might be missing something but isn't it same with the case where the app script just checks the existence of the new field like .entries and then falls back to .files if the field doesn't exist? If .entries is supported the script doesn't need to touch the .files field thus the UA does not need to populate the .files field (though I guess if the UA supports .files field it'd start populating the field before it is actually accessed). Authors can pass in 0 for the requested size to give the UA a hint that they have no intention of writing to disk. This gives authors a chance to use FileEntry instead of File, in addition to mounting directories which helps with copyTo. Might add a new constant, where we have window.PERSISTENT, we could add window.MOUNT or EXTERNAL. That way, I can run: if(window.MOUNT) to detect the feature, and otherwise fall back to .files. Additionally, I might pass window.MOUNT into rFS, which may prompt the user to select a mount point, bypassinginput altogether. This sounds cool, and I think eventually we want to have some explicit way to mount an arbitrary directory in a way this (requestFileSystem(MOUNT)), but what concerns me most in this generalized API is how we should define the lifetime of the mount'ed filesystem. In the original thread I proposed the mounting feature in a very limited context, i.e. input and drag-and-drop context, mainly because I hoped limiting the scoped and usage would have much smaller security and lifetime issues (though it still needs a serious consideration). In the drag-and-drop context it's clear that the permission and namespace must go away once the context goes away. But for more generic and extended usage (I assume requestFileSystem(window.MOUNT) would imply more generic usage) probably we should be more careful about how long and when the filesystem lifetime should expire. Maybe we could collect real usage with the limited mount support and then move things forward incrementally. Wdyt? -Charles
Re: [whatwg] Using requestFileSystem to setup mounts
I wish people wouldn't randomly split threads. This isn't a different conversation. On Mon, Nov 21, 2011 at 9:10 AM, Kinuko Yasuda kin...@chromium.org wrote: On Sun, Nov 20, 2011 at 5:54 AM, Charles Pritchard ch...@jumis.com wrote: input.ondrop = function(e) { window.requestFileSystem(e.dataTransfer, 0, cb); } This looks neat, though this would do almost same as what I was assuming the internal implementation would do. One clear benefit I found in your proposal is the code would make the fact that the UA is actually instantiating a new filesystem per drop clearer. On the other hand I'm afraid this may slightly complicate the API by overloading the requestFileSystem. This API doesn't work, because you can drop multiple directories at once; you'd need to pass the DataTransferItem. I don't really see the benefit to this approach, though. I didn't look closely enough at the DataTransferItem API before. It looks like Entry can be fully supported without removing anything currently specced. Add a getAsEntry method, which returns FileEntry (for kind == file) or DirectoryEntry (for a new kind == directory). getAsFile would be unchanged, returning File for kind == file and null for anything else (including kind == directory). This is also a convenient way to expose access (a bit later on). Add an async method getAsWritableEntry(onsuccess, ondenied) method. On success, the callback supplies a new FileEntry or DirectoryEntry which allows write access. Note that while this needs to be async, since it may ask the user for permission, the read-only method can be synchronous like getFile. (In practice the UA would probably ask do you want to allow the page to write to these files, not ask for each individual file, so it doesn't ask over and over if the caller is requesting write access to several simultaneously-dropped files.) If .entries is supported the script doesn't need to touch the .files field thus the UA does not need to populate the .files field (though I guess if the UA supports .files field it'd start populating the field before it is actually accessed). I don't think .files should ever recurse directories, which makes this problem go away. In the drag-and-drop context it's clear that the permission and namespace must go away once the context goes away. The permission should be attached to the Entry object, not the browsing context. If you send an Entry to a SharedWorker, the SharedWorker should still have access to the file if the context that sent it is closed. If *all* contexts attached to the SharedWorker go away, then the worker will be terminated, and that's when you'll lose the permission as a side-effect of losing the object. This is clear and consistent, and scales cleanly to future APIs (in both Window and Worker) exposing Entry objects from various sources. But for more generic and extended usage (I assume requestFileSystem(window.MOUNT) would imply more generic usage) probably we should be more careful about how long and when the filesystem lifetime should expire. Maybe we could collect real usage with the limited mount support and then move things forward incrementally. Wdyt? I think drag-and-drop is a good next step for the API. -- Glenn Maynard
Re: [whatwg] Using requestFileSystem to setup mounts
On 11/21/11 6:10 AM, Kinuko Yasuda wrote: Hi, thanks for your comment! On Sun, Nov 20, 2011 at 5:54 AM, Charles Pritchardch...@jumis.com wrote: // Proposal, using DataTransfer with rFS: input.ondrop = function(e) { window.requestFileSystem(e.dataTransfer, 0, cb); } There's some slight room for delaying the population of e.dataTransfer.files, by using a long-running for loop, or something of that sort. Otherwise, if rFS is used, .files will not be populated. This avoids directory traversal overhead while using rFS for permissions management. I may not be quite following this point. I might be missing something but isn't it same with the case where the app script just checks the existence of the new field like .entries and then falls back to .files if the field doesn't exist? If .entries is supported the script doesn't need to touch the .files field thus the UA does not need to populate the .files field (though I guess if the UA supports .files field it'd start populating the field before it is actually accessed). Neuter the .files object early in the event loop so that FileList does not need to be populated // .files is neutered after rFS. window.requestFileSystem(e.dataTransfer, 0, cb); e.dataTransfer.files; /* this will throw an error. */ Additionally, I might pass window.MOUNT into rFS, which may prompt the user to select a mount point, bypassinginputaltogether. This sounds cool, and I think eventually we want to have some explicit way to mount an arbitrary directory in a way this (requestFileSystem(MOUNT)), but what concerns me most in this generalized API is how we should define the lifetime of the mount'ed filesystem. Conservatively have Entry.toURL return undefined, or a new prefixed value. Undefined is fairly safe and is the default case for file:/// with webkitURL.createObjectURL Users can still run .file and create a blob url. An extended Entry.toURL returns the filesystem: url prefix: filesystem:blob:random:/path/. The lifetime of the filesystem is undefined and may expire at any time. In the drag-and-drop context it's clear that the permission and namespace must go away once the context goes away. But for more generic and extended usage (I assume requestFileSystem(window.MOUNT) would imply more generic usage) probably we should be more careful about how long and when the filesystem lifetime should expire. Maybe we could collect real usage with the limited mount support and then move things forward incrementally. Wdyt? Afaik, the requestFileSystem API is used by extension developers and browser extensions are a good place to carefully roll out new APIs. requestFileSystem(window.MOUNT) could simply trigger directory selection. // Basic polyfill for requestFileSystem(window.MOUNT) var input = document.createElement('input'); input.type = 'file'; input.setAttribute('webkitdirectory', ''); input.click(); // HTML polyfill of input type=file and mount points: input type=file onclick=requestFileSystem(window.MOUNT); return false; / -Charles
Re: [whatwg] Using requestFileSystem to setup mounts
On 11/21/11 8:45 AM, Glenn Maynard wrote: On Mon, Nov 21, 2011 at 9:10 AM, Kinuko Yasuda kin...@chromium.org mailto:kin...@chromium.org wrote: On Sun, Nov 20, 2011 at 5:54 AM, Charles Pritchard ch...@jumis.com mailto:ch...@jumis.com wrote: input.ondrop = function(e) { window.requestFileSystem(e.dataTransfer, 0, cb); } This looks neat, though this would do almost same as what I was assuming the internal implementation would do. One clear benefit I found in your proposal is the code would make the fact that the UA is actually instantiating a new filesystem per drop clearer. On the other hand I'm afraid this may slightly complicate the API by overloading the requestFileSystem. This API doesn't work, because you can drop multiple directories at once; you'd need to pass the DataTransferItem. I don't really see the benefit to this approach, though. Multiple directories still have a shared file system root. Their relative paths are exposed in webkitdirectory files already. The benefit is neutered .files object while maintaining compatibility with existing code bases. I didn't look closely enough at the DataTransferItem API before. It looks like Entry can be fully supported without removing anything currently specced. Add a getAsEntry method, which returns FileEntry (for kind == file) or DirectoryEntry (for a new kind == directory). What values will Entry.filesystem and Entry.fullpath have? As synchronous methods, won't these block the user if they need to confirm permission to mount a directory? As async methods, these might add a lot of calls to the stack. If .entries is supported the script doesn't need to touch the .files field thus the UA does not need to populate the .files field (though I guess if the UA supports .files field it'd start populating the field before it is actually accessed). I don't think .files should ever recurse directories, which makes this problem go away. Recursing directories is the current behavior of webkitdirectory. But for more generic and extended usage (I assume requestFileSystem(window.MOUNT) would imply more generic usage) probably we should be more careful about how long and when the filesystem lifetime should expire. Maybe we could collect real usage with the limited mount support and then move things forward incrementally. Wdyt? I think drag-and-drop is a good next step for the API. I think addressing the issues with FileList and webkitdirectory is a good first step. -Charles
Re: [whatwg] Using requestFileSystem to setup mounts
On Mon, Nov 21, 2011 at 4:33 PM, Charles Pritchard ch...@jumis.com wrote: ** Multiple directories still have a shared file system root. Their relative paths are exposed in webkitdirectory files already. The benefit is neutered .files object while maintaining compatibility with existing code bases. It would be strange to drag in multiple directories and to have it exposed as a virtual directory containing the dragged files. It could be done, but it's inconsistent with the design of DataTransfer, and it feels unnatural. I don't know what you mean by compatibility with existing code bases; the compatibility is no different than a getAsEntry/getAsWritableEntry API would be. Also, remember that DataTransfer objects can be filled in programmatically. You can do, for example: dt.items.add(hello world, text/plain); // already supported dt.items.add(myFile); // already supported dt.items.add(myFileEntry); // new DataTransferItemList.add(Entry data) method dt.items.add(myDirectoryEntry); The requestFileSystem approach doesn't fit with DataTransfer's design very naturally. (Adding a File would be equivalent to adding a FileEntry containing the File; both would just create a DataTransferItem with a kind of file.) What values will Entry.filesystem and Entry.fullpath have? Each Entry would have a dummy FileSystem object attached to it, in order to fill out the Entry.filesystem API, but all it would contain is the file itself. Entry.fullPath would be the same as Entry.name, prefixed with /. As synchronous methods, won't these block the user if they need to confirm permission to mount a directory? As async methods, these might add a lot of calls to the stack. Async methods (eg. theoretically getAsWritableEntry) is adding no more calls than would be added by a similar async requestFileSystem call, which is also async. getAsEntry gives read-only access; as with getAsFile, there's no additional permission prompt. Both methods could be async if we really want to allow for separate permissions prompting even for read-only access (though that's awkward UI, especially *during* a drag). Either way, it's no more code for users than a requestFileSystem call. Recursing directories is the current behavior of webkitdirectory. Yes, this should go away if possible, or at least not be propagated to other browsers. It's not a scalable approach, as we discussed earlier. -- Glenn Maynard