ServerJS/Filesystem API/A: Difference between revisions

Finished the structure of draft 5.
mNo edit summary
(Finished the structure of draft 5.)
Line 15: Line 15:
The "file" module must export the following:
The "file" module must export the following:


Files:
==== Files ====


; open(path (String)|options Object, [mode (String|Array|Object)], [options Object|mode (String|Array)]): returns a stream object that supports an appropriate interface for the given options and mode, which include reading, writing, updating, byte, character, unbuffered, buffered, and line buffered streams.  More details follow in the [#Stream] section of this document.
; open(path (String)|options Object, [mode (String|Array|Object)], [options Object|mode (String|Array)])
: returns a stream object that supports an appropriate interface for the given options and mode, which include reading, writing, updating, byte, character, unbuffered, buffered, and line buffered streams.  More details follow in the [#Stream] section of this document.
* path
* path
* mode: "rwa+bxc", ["read", "write", "append", "update", "binary", "exclusive", "canonical"], {read, write, append, update, binary, exclusive, canonical}
* mode: "rwa+bxc", ["read", "write", "append", "update", "binary", "exclusive", "canonical"], {read, write, append, update, binary, exclusive, canonical}
Line 26: Line 27:
** newLine String
** newLine String
** delimiter String
** delimiter String
; read(path String|options Object, [options (Object)|mode (String|Array)]): opens, reads, and closes a file, returning its content.
; read(path String|options Object, [options (Object)|mode (String|Array)])
; write(path String|options Object, content String|ByteString|ByteArray, [options (Object)|mode (String|Array)]): opens, writes, flushes, and closes a file with the given content.  If the content is a ByteArray or ByteString, the binary mode is implied.
: opens, reads, and closes a file, returning its content.
; copy(source String, target String): reads one file and writes another in byte mode.
; write(path String|options Object, content String|ByteString|ByteArray, [options (Object)|mode (String|Array)])
: opens, writes, flushes, and closes a file with the given content.  If the content is a ByteArray or ByteString, the binary mode is implied.
; copy(source String, target String)
: reads one file and writes another in byte mode.
; move(from String, to String)
; move(from String, to String)
:
; remove(path String)
; remove(path String)
:
; rename(path String, name String)
; rename(path String, name String)
:
; touch(path, [mtime Date])
; touch(path, [mtime Date])
:


Directories:
==== Directories ====


; list(path String) Iterator: returns an iterator that yields the names of the entries in a directory.  Throws an error if the directory is inaccessible or does not exist.
; list(path String) Iterator
: returns an iterator that yields the names of the entries in a directory.  Throws an error if the directory is inaccessible or does not exist.
; mkdir(path String)
; mkdir(path String)
:
; mkdirs(path String)
; mkdirs(path String)
; rmdir(path String)
:
; rmdir(path String)  
:
; rmtree(path String)
; rmtree(path String)
:


Links:
==== Links ====


Paths:
==== Paths ====


; [new] Path(path String|Path|Array, [fs FileSystem]) Path
; [new] Path(path String|Path|Array, [fs FileSystem]) Path
: returns a Path object that closes on a File System object and a "path" representation.  The path object is a chainable shorthand for working with paths in the context of the "file" module.  "Path" objects have no more or less authority to manipulate the file system than the FileSystem object that they are attached to, as any path string is reachable by chaining operations on a path instance.  The FileSystem object defaults to the "file" module if the argument is omitted or undefined.  More details follow in the [#Path Path] section of this document.
: returns a Path object that closes on a File System object and a "path" representation.  The path object is a chainable shorthand for working with paths in the context of the "file" module.  "Path" objects have no more or less authority to manipulate the file system than the FileSystem object that they are attached to, as any path string is reachable by chaining operations on a path instance.  The FileSystem object defaults to the "file" module if the argument is omitted or undefined.  More details follow in the [#Path Path] section of this document.
; path(path String|Path, fs FileSystem) Path: "fs.path(path)" is a shorthand for "new fs.Path(path, fs)".
; path(path String|Path, fs FileSystem) Path
: "fs.path(path)" is a shorthand for "new fs.Path(path, fs)".


; cwd() String: returns the current working directory.
===== Working Path =====
; chdir(path String): changes the current working directory.


Traditional path manipulation:
The current working directory is used by all routines that resolve relative paths to absolute file system paths, including "open", and "absolute".


; join(...): takes a variadic list of path Strings, joins them on the file system's path separator, and normalizes the result.
; cwd() String
; split(path String) Array: returns an array of path components.  If the path is absolute, the first component will be an indicator of the root of the file system; for file systems with drives (such as Windows), this is the drive identifier with a colon, like "c:"; on Unix, this is an empty string "".  The intent is that calling "join.apply" with the result of "split" as arguments will reconstruct the path.
: returns the current working directory.
; normal(path String): removes '.' path components and simplifies '..' paths, if possible, for a given path.
; chdir(path String)
; absolute(path String): returns the absolute path, starting with the root of this file system object, for the given path, resolved from the current working directory.  If the file system supports home directory aliases, absolute resolves those from the root of the file system.  The resulting path is in normal form.  On most systems, this is equivalent to expanding any user directory alias, joining the path to the current working directory, and normalizing the result.  "absolute" can be implemented in terms of "cwd", "join", and "normal".
: changes the current working directory.
; canonical(path String): returns the canonical path to a given abstract path.  Canonical paths are both absolute and intrinsic, such that all paths that refer to a given file (whether it exists or not) have the same corresponding canonical path.  This function must not communicate information about the true parent directories of files in chroot environments.  This function is equivalent to expanding a user directory alias, joining the given path to the current working directory, joining all symbolic links along the path, and normalizing the result.  "canonical" can be implemented in terms of "cwd", "join", "normal" and "readlink".
; dirname(path String) String: returns the path of a file's containing directory, albeit the parent directory if the file is a directory.  A terminal directory separator is ignored.
; basename(path String, [extension String]) String: returns the part of the path that is after the last directory separator.  If an extension is provided and is equal to the file's extension, the extension is removed from the result.
; extension(path String) String: returns the extension of a file.  The extension of a file is the last dot (excluding any number of initial dots) followed by one or more non-dot characters. Returns an empty string if no valid extension exists.  [http://github.com/kriskowal/narwhal-test/blob/master/src/test/file/extension.js unit test].


URL-like path manipulation:
===== Traditional =====
 
; join(...)
: takes a variadic list of path Strings, joins them on the file system's path separator, and normalizes the result.
; split(path String) Array
: returns an array of path components.  If the path is absolute, the first component will be an indicator of the root of the file system; for file systems with drives (such as Windows), this is the drive identifier with a colon, like "c:"; on Unix, this is an empty string "".  The intent is that calling "join.apply" with the result of "split" as arguments will reconstruct the path.
; normal(path String)
: removes '.' path components and simplifies '..' paths, if possible, for a given path.
; absolute(path String)
: returns the absolute path, starting with the root of this file system object, for the given path, resolved from the current working directory.  If the file system supports home directory aliases, absolute resolves those from the root of the file system.  The resulting path is in normal form.  On most systems, this is equivalent to expanding any user directory alias, joining the path to the current working directory, and normalizing the result.  "absolute" can be implemented in terms of "cwd", "join", and "normal".
; canonical(path String)
: returns the canonical path to a given abstract path.  Canonical paths are both absolute and intrinsic, such that all paths that refer to a given file (whether it exists or not) have the same corresponding canonical path.  This function must not communicate information about the true parent directories of files in chroot environments.  This function is equivalent to expanding a user directory alias, joining the given path to the current working directory, joining all symbolic links along the path, and normalizing the result.  "canonical" can be implemented in terms of "cwd", "join", "normal" and "readlink".
; dirname(path String) String
: returns the path of a file's containing directory, albeit the parent directory if the file is a directory.  A terminal directory separator is ignored.
; basename(path String, [extension String]) String
: returns the part of the path that is after the last directory separator.  If an extension is provided and is equal to the file's extension, the extension is removed from the result.
; extension(path String) String
: returns the extension of a file.  The extension of a file is the last dot (excluding any number of initial dots) followed by one or more non-dot characters. Returns an empty string if no valid extension exists.  [http://github.com/kriskowal/narwhal-test/blob/master/src/test/file/extension.js unit test].
 
===== URL-like =====


; resolve(...)
; resolve(...)
: a function like "join" except that it treats each argument as as either an absolute or relative path and, as is the convention with URL's, treats everything up to the final directory separator as a location, and everything afterward as an entry in that directory, even if the entry refers to a directory in the underlying storage.  Resolve starts at the location "" and walks to the locations referenced by each path, and returns the path of the last file.  Thus, resolve(file, "") idempotently refers to the location containing a file or directory entry, and resolve(file, neighbor) always gives the path of a file in the same directory.  "resolve" is useful for finding paths in the "neighborhood" of a given file, while gracefully accepting both absolute and relative paths at each stage. [http://github.com/kriskowal/narwhal-test/blob/master/src/test/file/resolve.js unit test].
: a function like "join" except that it treats each argument as as either an absolute or relative path and, as is the convention with URL's, treats everything up to the final directory separator as a location, and everything afterward as an entry in that directory, even if the entry refers to a directory in the underlying storage.  Resolve starts at the location "" and walks to the locations referenced by each path, and returns the path of the last file.  Thus, resolve(file, "") idempotently refers to the location containing a file or directory entry, and resolve(file, neighbor) always gives the path of a file in the same directory.  "resolve" is useful for finding paths in the "neighborhood" of a given file, while gracefully accepting both absolute and relative paths at each stage. [http://github.com/kriskowal/narwhal-test/blob/master/src/test/file/resolve.js unit test].
; relative(from, to): returns the relative path from one path to another using only ".." to traverse up to the two paths' common ancestor.
; relative(from, to)
: returns the relative path from one path to another using only ".." to traverse up to the two paths' common ancestor.


Tests:
==== Tests ====


; exists(path): whether a file exists at a given path: receives a path and returns whether that path, joined on the current working directory, corresponds to a file that exists.  If the file is a broken symbolic link, returns false.
; exists(path)
; isFile(path): returns whether a path exists and that it corresponds to a file.
:whether a file exists at a given path: receives a path and returns whether that path, joined on the current working directory, corresponds to a file that exists.  If the file is a broken symbolic link, returns false.
; isDirectory(path): returns whether a path exists and that it corresponds to a directory.
; isFile(path)
; isLink(path): returns whether a path exists and that it corresponds to a symbolic link (TODO or shortcut?).
:returns whether a path exists and that it corresponds to a file.
; isReadable(path): returns whether a path exists, that it corresponds to a file, and that it can be opened for reading by "fs.open".
; isDirectory(path)
; isWritable(path): If a path exists, returns whether a file may be opened for writing, or entries added or removed from an  existing directory.  If the path does not exist, returns whether entries for files, directories, or links can be created at its location.
:returns whether a path exists and that it corresponds to a directory.
; isLink(path)
:returns whether a path exists and that it corresponds to a symbolic link (TODO or shortcut?).
; isReadable(path)
:returns whether a path exists, that it corresponds to a file, and that it can be opened for reading by "fs.open".
; isWritable(path)
:If a path exists, returns whether a file may be opened for writing, or entries added or removed from an  existing directory.  If the path does not exist, returns whether entries for files, directories, or links can be created at its location.


Metadata:
==== Metadata ====


; stat(path String): Returns an object that contains the file's metadata, including all of the following that are applicable in the target platform's file system
; stat(path String)
;; device Number: device number of the file system
:Returns an object that contains the file's metadata, including all of the following that are applicable in the target platform's file system
;; inode Number: virtual node number
;; device Number
;; mode Number: type and permissions, numeric
:device number of the file system
;; linkCount Number: number of hard links to the file
;; inode Number
;; uid Number: numeric id of the owner user
:virtual node number
;; rdev Number: the device identifier for special files
;; mode Number
;; size NUmber: total size in bytes
:type and permissions, numeric
;; blockSize Number: preferred block size for file system IO, in bytes
;; linkCount Number
;; blockCount Number: number of blocks allocated
:number of hard links to the file
;; mtime Date: time of last modification (write)
;; uid Number
;; atime Date: time of last access (read, write, update)
:numeric id of the owner user
;; ctime Date: (TODO created vs. stat changed.  is /.time/ really the best pattern for expressing these times?)
;; rdev Number
;; xattrs: extended attributes (reserved)
:the device identifier for special files
;; acls: access control lists (reserved)
;; size NUmber
:total size in bytes
;; blockSize Number
:preferred block size for file system IO, in bytes
;; blockCount Number
:number of blocks allocated
;; mtime Date
:time of last modification (write)
;; atime Date
:time of last access (read, write, update)
;; ctime Date
:(TODO created vs. stat changed.  is /.time/ really the best pattern for expressing these times?)
;; xattrs
:extended attributes (reserved)
;; acls
:access control lists (reserved)


; size(path String):Number
; size(path String)
; mtime(path String):Date
:Number
; atime(path String):Date
; mtime(path String)
; ctime(path String):Date
:Date
; same(pathA String, pathB String) Boolean: whether the two files are identical, in that they come from the same file system, same device, and have the same node and corresponding storage, such that modifying one would implicitly and atomically modify the other.
; atime(path String)
:Date
; ctime(path String)
:Date
; same(pathA String, pathB String) Boolean
:whether the two files are identical, in that they come from the same file system, same device, and have the same node and corresponding storage, such that modifying one would implicitly and atomically modify the other.


Security:
==== Security ====


; chroot(path String)
; chroot(path String)
: returns an object that conforms to the File System API, like the "file" module or the "system.fs" variable, that can be safely passed into a sandbox as the "file" module and "system.fs" objects.




Line 111: Line 167:


; [new] Path(path String|Path|Array, [fs FileSystem]) Path
; [new] Path(path String|Path|Array, [fs FileSystem]) Path
:


The prototype for the Path constructor is a String object.
The prototype for the Path constructor is a String object.
Line 118: Line 175:
Every path object has the members "normal", "absolute", "canonical", "dirname", "basename", "join", and "resolve".  All of these return new Path objects constructed by converting the path to a string, passing it through the likewise named method of "fs", and converting it back to a Path.  Thus, all of these methods are chainable.  In addition, "join" and "resolve" are variadic, so additional paths can be passed as arguments in either String, Path, or Array form.
Every path object has the members "normal", "absolute", "canonical", "dirname", "basename", "join", and "resolve".  All of these return new Path objects constructed by converting the path to a string, passing it through the likewise named method of "fs", and converting it back to a Path.  Thus, all of these methods are chainable.  In addition, "join" and "resolve" are variadic, so additional paths can be passed as arguments in either String, Path, or Array form.


Every path object has "chroot", "copy", "exists", "extname", "isDirectory", "isFile", "isLink", "isReadable", "isWritable", "mkdir", "mkdirs", "move", "mtime", "open", "read", "remove", "rename", "rmdir", "rmtree", "same", "size", "split", "stat", "touch", and "write".  All of these functions convert themselves to strings and pass the results through the likewise named method of "fs".
Every path object has "chroot", "copy", "exists", "extension", "isDirectory", "isFile", "isLink", "isReadable", "isWritable", "mkdir", "mkdirs", "move", "mtime", "open", "read", "remove", "rename", "rmdir", "rmtree", "same", "size", "split", "stat", "touch", and "write".  All of these functions convert themselves to strings and pass the results through the likewise named method of "fs".


In addition, paths implement:
In addition, paths implement:


; toString()
; toString()
; to(path): uses "fs.relative" to return a Path from this path to another one.
:
; from(path): uses "fs.relative" to return a Path to this path from another one.
; to(path)
; list(): returns an iterator of Path objects for the contained directory entries.
: uses "fs.relative" to return a Path from this path to another one.
; from(path)
: uses "fs.relative" to return a Path to this path from another one.
; list()
: returns an iterator of Path objects for the contained directory entries.


(TODO resolve whether it's more proper to make "Path" foundational and eliminate "fs".  Wrapping the "Path" object around a central "fs" object will be necessary for "chroot" whether we expose that level of the API or not, and having routines that work with strings on one architectural layer and paths on the next up gives the programmer an oppoertunity to program at the level that makes sense for their task.  It also, however, gives the programmer more to learn.)
(TODO resolve whether it's more proper to make "Path" foundational and eliminate "fs".  Wrapping the "Path" object around a central "fs" object will be necessary for "chroot" whether we expose that level of the API or not, and having routines that work with strings on one architectural layer and paths on the next up gives the programmer an oppoertunity to program at the level that makes sense for their task.  It also, however, gives the programmer more to learn.)
Line 144: Line 205:
** if "w" mode, wrap "raw" in a TextWriter
** if "w" mode, wrap "raw" in a TextWriter
** if "u" mode, wrap "raw" in a TextUpdater
** if "u" mode, wrap "raw" in a TextUpdater
Types:


; ByteReader
; ByteReader
: appropriate for standard input
: appropriate for reading binary opaque struct records or other binary data or protocols
; ByteWriter
; ByteWriter
: appropriate for standard output
: appropriate for writing binary opaque struct records or other binary data or protocols
; ByteUpdater
; ByteUpdater
: appropriate for a database
: appropriate for a database
Line 156: Line 215:
: appropriate for sockets
: appropriate for sockets
; TextReader
; TextReader
: appropriate for standard input
; TextWriter
; TextWriter
: appropriate for standard output
; TextUpdater
; TextUpdater
:
; TextReaderWriter
; TextReaderWriter
: appropriate for a TTY
: appropriate for a TTY


*Reader, *Updater, *ReaderWriter:
(TODO: resolve whether it is necessary for all stream types to have a common prototype, or whether it makes sense for them to be arranged in a class hierarchy.)


; read():*String
=== *Reader, *Updater ===
 
TextReader, ByteReader, TextUpdater, ByteUpdater, TextReaderWriter, and ByteReaderWriter have the following properties and methods:
 
; read() *String
: reads and returns all of the file until EOF is encountered.  Return ByteStrings for Byte* types, and Strings for Text* types.
; read(max Number) *String
; read(max Number) *String
:
; readInto(buffer *Array, [begin Number], [end Number]) Number
; readInto(buffer *Array, [begin Number], [end Number]) Number
; canRead():Boolean
:
; canRead() Boolean
:
; skip(n Number) Number
; skip(n Number) Number
:
=== *Writer, *Updater ===


*Writer, *Updater, *ReaderWriter:
TextWriter, ByteWriter, TextUpdater, ByteUpdater, TextReaderWriter, and ByteReaderWriter have the following properties and methods:


; canWrite() Boolean
; canWrite() Boolean
:
; flush()
; flush()
:


ByteUpdater:
=== ByteUpdater ===


; tell() Number
; tell() Number
:
; seek(position Number, whence Number)
; seek(position Number, whence Number)
:
; truncate([length Number=0])
; truncate([length Number=0])
; rewind(): a shortcut for seek(0)
:
; rewind()
: a shortcut for seek(0)


TextUpdater:
=== Text* ===


; tell() OpaqueCookie
TextReader, TextWriter, TextUpdater, and TextReaderWriter have the following properties and methods:
; seek(position OpaqueCookie)
; truncate([position OpaqueCookie)
; rewind(): seeks to the beginning of the file.
 
Text*:


; raw Byte*
; raw Byte*
: the underlying byte stream, ByteReader for TextReaders, ByteWriter for TextWriters, and so on.


TextReader:
=== TextReader ===


; readLine() String
; readLine() String
: reads a line from the reader.  If EOF is encountered before any data is gathered, returns "".  Otherwise, returns the line including the "newLine".
: reads a line from the reader.  If EOF is encountered before any data is gathered, returns "".  Otherwise, returns the line including the "newLine".
; readLines() Array*String: returns an Array of Strings accumulated by calling readLine until an empty string turns up.  Does not include the final empty string, and does include "newLine" at the end of every line.
; readLines() Array*String
; next() String or throws StopIteration: returns the next line of input without its "newLine".  Throws StopIteration if EOF is encountered.
: returns an Array of Strings accumulated by calling readLine until an empty string turns up.  Does not include the final empty string, and does include "newLine" at the end of every line.
; iterator() Iterator: returns the reader itself
; next() String or throws StopIteration
: returns the next line of input without its "newLine".  Throws StopIteration if EOF is encountered.
; iterator() Iterator
: returns the reader itself


TextWriter:
=== TextWriter ===


; writeLine(line String)
; writeLine(line String)
; print(...): writes a "delimiter" delimited array of Strings terminated with a "newLine"
:
; print(...)
: writes a "delimiter" delimited array of Strings terminated with a "newLine"
 
=== TextUpdater ===


; tell() OpaqueCookie
:
; seek(position OpaqueCookie)
:
; truncate([position OpaqueCookie)
:
; rewind()
: seeks to the beginning of the file.


== Deliberate Omissions ==
 
== Notes ==


* Path separators, and other file-system-specific constants are not included in this specification.
* Path separators, and other file-system-specific constants are not included in this specification.


= Todo =
= Todo =
171

edits