2014-05-23 18:14:06 +00:00
var Path = require ( '../path.js' ) ;
var normalize = Path . normalize ;
var dirname = Path . dirname ;
var basename = Path . basename ;
var isAbsolutePath = Path . isAbsolute ;
var isNullPath = Path . isNull ;
var Constants = require ( '../constants.js' ) ;
2018-05-24 18:15:09 +00:00
var NODE _TYPE _FILE = Constants . NODE _TYPE _FILE ;
var NODE _TYPE _DIRECTORY = Constants . NODE _TYPE _DIRECTORY ;
var NODE _TYPE _SYMBOLIC _LINK = Constants . NODE _TYPE _SYMBOLIC _LINK ;
var NODE _TYPE _META = Constants . NODE _TYPE _META ;
2014-05-23 18:14:06 +00:00
2018-05-28 19:03:34 +00:00
var FULL _READ _WRITE _EXEC _PERMISSIONS = Constants . FULL _READ _WRITE _EXEC _PERMISSIONS ;
2014-05-23 18:14:06 +00:00
var ROOT _DIRECTORY _NAME = Constants . ROOT _DIRECTORY _NAME ;
var SUPER _NODE _ID = Constants . SUPER _NODE _ID ;
var SYMLOOP _MAX = Constants . SYMLOOP _MAX ;
var O _READ = Constants . O _READ ;
var O _WRITE = Constants . O _WRITE ;
var O _CREATE = Constants . O _CREATE ;
var O _EXCLUSIVE = Constants . O _EXCLUSIVE ;
var O _APPEND = Constants . O _APPEND ;
var O _FLAGS = Constants . O _FLAGS ;
var XATTR _CREATE = Constants . XATTR _CREATE ;
var XATTR _REPLACE = Constants . XATTR _REPLACE ;
var FS _NOMTIME = Constants . FS _NOMTIME ;
var FS _NOCTIME = Constants . FS _NOCTIME ;
2014-06-04 19:52:08 +00:00
var Encoding = require ( '../encoding.js' ) ;
2014-05-23 18:14:06 +00:00
var Errors = require ( '../errors.js' ) ;
var DirectoryEntry = require ( '../directory-entry.js' ) ;
var OpenFileDescription = require ( '../open-file-description.js' ) ;
var SuperNode = require ( '../super-node.js' ) ;
var Node = require ( '../node.js' ) ;
var Stats = require ( '../stats.js' ) ;
2014-08-16 20:22:41 +00:00
var Buffer = require ( '../buffer.js' ) ;
2018-10-09 17:53:26 +00:00
const { validateInteger } = require ( '../shared.js' ) ;
2014-05-23 18:14:06 +00:00
/ * *
* Update node times . Only passed times are modified ( undefined times are ignored )
* and filesystem flags are examined in order to override update logic .
* /
function update _node _times ( context , path , node , times , callback ) {
// Honour mount flags for how we update times
var flags = context . flags ;
2018-11-28 01:49:38 +00:00
if ( flags . includes ( FS _NOCTIME ) ) {
2014-05-23 18:14:06 +00:00
delete times . ctime ;
}
2018-11-28 01:49:38 +00:00
if ( flags . includes ( FS _NOMTIME ) ) {
2014-05-23 18:14:06 +00:00
delete times . mtime ;
}
2018-06-25 12:26:59 +00:00
// Only do the update if required (i.e., times are still present)
var update = false ;
2014-05-23 18:14:06 +00:00
if ( times . ctime ) {
node . ctime = times . ctime ;
// We don't do atime tracking for perf reasons, but do mirror ctime
node . atime = times . ctime ;
update = true ;
}
if ( times . atime ) {
// The only time we explicitly pass atime is when utimes(), futimes() is called.
// Override ctime mirror here if so
node . atime = times . atime ;
update = true ;
}
if ( times . mtime ) {
node . mtime = times . mtime ;
update = true ;
}
function complete ( error ) {
2018-06-25 18:10:27 +00:00
// Queue this change so we can send watch events.
// Unlike node.js, we send the full path vs. basename/dirname only.
2018-05-24 18:55:36 +00:00
context . changes . push ( { event : 'change' , path : path } ) ;
2014-05-23 18:14:06 +00:00
callback ( error ) ;
}
if ( update ) {
2014-08-16 20:22:41 +00:00
context . putObject ( node . id , node , complete ) ;
2014-05-23 18:14:06 +00:00
} else {
complete ( ) ;
}
}
/ * *
* make _node ( )
* /
// in: file or directory path
// out: new node representing file/directory
2018-05-24 18:32:27 +00:00
function make _node ( context , path , type , callback ) {
if ( type !== NODE _TYPE _DIRECTORY && type !== NODE _TYPE _FILE ) {
return callback ( new Errors . EINVAL ( 'type must be a directory or file' , path ) ) ;
2014-05-23 18:14:06 +00:00
}
path = normalize ( path ) ;
var name = basename ( path ) ;
var parentPath = dirname ( path ) ;
var parentNode ;
var parentNodeData ;
var node ;
// Check if the parent node exists
function create _node _in _parent ( error , parentDirectoryNode ) {
if ( error ) {
callback ( error ) ;
2018-05-24 18:32:27 +00:00
} else if ( parentDirectoryNode . type !== NODE _TYPE _DIRECTORY ) {
2014-08-18 23:13:50 +00:00
callback ( new Errors . ENOTDIR ( 'a component of the path prefix is not a directory' , path ) ) ;
2014-05-23 18:14:06 +00:00
} else {
parentNode = parentDirectoryNode ;
find _node ( context , path , check _if _node _exists ) ;
2014-05-13 22:10:11 +00:00
}
2014-05-23 18:14:06 +00:00
}
// Check if the node to be created already exists
function check _if _node _exists ( error , result ) {
if ( ! error && result ) {
2014-08-18 23:13:50 +00:00
callback ( new Errors . EEXIST ( 'path name already exists' , path ) ) ;
2014-05-23 18:14:06 +00:00
} else if ( error && ! ( error instanceof Errors . ENOENT ) ) {
callback ( error ) ;
} else {
2014-08-16 20:22:41 +00:00
context . getObject ( parentNode . data , create _node ) ;
2014-05-13 22:10:11 +00:00
}
2014-05-23 18:14:06 +00:00
}
// Create the new node
function create _node ( error , result ) {
if ( error ) {
callback ( error ) ;
} else {
parentNodeData = result ;
2018-05-15 17:33:45 +00:00
Node . create ( {
guid : context . guid ,
2018-05-24 18:32:27 +00:00
type : type
2018-05-15 17:33:45 +00:00
} , function ( error , result ) {
2014-06-02 20:44:20 +00:00
if ( error ) {
callback ( error ) ;
return ;
}
node = result ;
node . nlinks += 1 ;
2014-08-16 20:22:41 +00:00
context . putObject ( node . id , node , update _parent _node _data ) ;
2014-06-02 20:44:20 +00:00
} ) ;
2014-05-13 22:10:11 +00:00
}
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
// Update parent node time
function update _time ( error ) {
if ( error ) {
callback ( error ) ;
} else {
var now = Date . now ( ) ;
update _node _times ( context , parentPath , node , { mtime : now , ctime : now } , callback ) ;
}
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
// Update the parent nodes data
function update _parent _node _data ( error ) {
if ( error ) {
callback ( error ) ;
} else {
2018-05-24 18:32:27 +00:00
parentNodeData [ name ] = new DirectoryEntry ( node . id , type ) ;
2014-08-16 20:22:41 +00:00
context . putObject ( parentNode . data , parentNodeData , update _time ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
// Find the parent node
find _node ( context , parentPath , create _node _in _parent ) ;
}
/ * *
* find _node
* /
// in: file or directory path
// out: node structure, or error
function find _node ( context , path , callback ) {
path = normalize ( path ) ;
if ( ! path ) {
return callback ( new Errors . ENOENT ( 'path is an empty string' ) ) ;
}
var name = basename ( path ) ;
var parentPath = dirname ( path ) ;
var followedCount = 0 ;
function read _root _directory _node ( error , superNode ) {
if ( error ) {
callback ( error ) ;
2018-05-24 18:32:27 +00:00
} else if ( ! superNode || superNode . type !== NODE _TYPE _META || ! superNode . rnode ) {
2014-05-23 18:14:06 +00:00
callback ( new Errors . EFILESYSTEMERROR ( ) ) ;
} else {
2014-08-16 20:22:41 +00:00
context . getObject ( superNode . rnode , check _root _directory _node ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function check _root _directory _node ( error , rootDirectoryNode ) {
if ( error ) {
callback ( error ) ;
} else if ( ! rootDirectoryNode ) {
callback ( new Errors . ENOENT ( ) ) ;
} else {
callback ( null , rootDirectoryNode ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
// in: parent directory node
// out: parent directory data
function read _parent _directory _data ( error , parentDirectoryNode ) {
if ( error ) {
callback ( error ) ;
2018-05-24 18:32:27 +00:00
} else if ( parentDirectoryNode . type !== NODE _TYPE _DIRECTORY || ! parentDirectoryNode . data ) {
2014-08-18 23:13:50 +00:00
callback ( new Errors . ENOTDIR ( 'a component of the path prefix is not a directory' , path ) ) ;
2014-05-23 18:14:06 +00:00
} else {
2014-08-16 20:22:41 +00:00
context . getObject ( parentDirectoryNode . data , get _node _from _parent _directory _data ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
// in: parent directory data
// out: searched node
function get _node _from _parent _directory _data ( error , parentDirectoryData ) {
if ( error ) {
callback ( error ) ;
} else {
2018-11-28 01:49:38 +00:00
if ( ! parentDirectoryData . hasOwnProperty ( name ) ) {
2014-08-18 23:13:50 +00:00
callback ( new Errors . ENOENT ( null , path ) ) ;
2014-03-18 18:16:12 +00:00
} else {
2014-05-23 18:14:06 +00:00
var nodeId = parentDirectoryData [ name ] . id ;
2014-08-16 20:22:41 +00:00
context . getObject ( nodeId , is _symbolic _link ) ;
2014-03-18 18:16:12 +00:00
}
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function is _symbolic _link ( error , node ) {
if ( error ) {
callback ( error ) ;
} else {
2018-06-25 12:26:59 +00:00
if ( node . type === NODE _TYPE _SYMBOLIC _LINK ) {
2014-05-23 18:14:06 +00:00
followedCount ++ ;
if ( followedCount > SYMLOOP _MAX ) {
2014-08-18 23:13:50 +00:00
callback ( new Errors . ELOOP ( null , path ) ) ;
2014-03-18 18:16:12 +00:00
} else {
2014-05-23 18:14:06 +00:00
follow _symbolic _link ( node . data ) ;
2014-03-18 18:16:12 +00:00
}
} else {
2014-05-23 18:14:06 +00:00
callback ( null , node ) ;
2014-03-18 18:16:12 +00:00
}
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function follow _symbolic _link ( data ) {
data = normalize ( data ) ;
parentPath = dirname ( data ) ;
name = basename ( data ) ;
2018-06-25 12:26:59 +00:00
if ( ROOT _DIRECTORY _NAME === name ) {
2014-08-16 20:22:41 +00:00
context . getObject ( SUPER _NODE _ID , read _root _directory _node ) ;
2014-03-18 18:16:12 +00:00
} else {
find _node ( context , parentPath , read _parent _directory _data ) ;
}
}
2018-06-25 12:26:59 +00:00
if ( ROOT _DIRECTORY _NAME === name ) {
2014-08-16 20:22:41 +00:00
context . getObject ( SUPER _NODE _ID , read _root _directory _node ) ;
2014-05-23 18:14:06 +00:00
} else {
find _node ( context , parentPath , read _parent _directory _data ) ;
}
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
/ * *
* set extended attribute ( refactor )
* /
2014-10-17 16:55:36 +00:00
function set _extended _attribute ( context , path , node , name , value , flag , callback ) {
function update _time ( error ) {
if ( error ) {
2014-05-23 18:14:06 +00:00
callback ( error ) ;
2014-10-17 16:55:36 +00:00
} else {
update _node _times ( context , path , node , { ctime : Date . now ( ) } , callback ) ;
2014-03-18 18:16:12 +00:00
}
}
2014-10-17 16:55:36 +00:00
var xattrs = node . xattrs ;
if ( flag === XATTR _CREATE && xattrs . hasOwnProperty ( name ) ) {
callback ( new Errors . EEXIST ( 'attribute already exists' , path ) ) ;
2014-05-23 18:14:06 +00:00
}
2014-10-17 16:55:36 +00:00
else if ( flag === XATTR _REPLACE && ! xattrs . hasOwnProperty ( name ) ) {
callback ( new Errors . ENOATTR ( null , path ) ) ;
2014-05-23 18:14:06 +00:00
}
else {
2014-10-17 16:55:36 +00:00
xattrs [ name ] = value ;
context . putObject ( node . id , node , update _time ) ;
2014-05-23 18:14:06 +00:00
}
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
/ * *
2014-07-07 21:02:42 +00:00
* ensure _root _directory . Creates a root node if necessary .
*
* Note : this should only be invoked when formatting a new file system .
* Multiple invocations of this by separate instances will still result
* in only a single super node .
2014-05-23 18:14:06 +00:00
* /
2014-07-07 21:02:42 +00:00
function ensure _root _directory ( context , callback ) {
2014-05-23 18:14:06 +00:00
var superNode ;
var directoryNode ;
var directoryData ;
2014-03-18 18:16:12 +00:00
2014-07-07 21:02:42 +00:00
function ensure _super _node ( error , existingNode ) {
2014-05-23 18:14:06 +00:00
if ( ! error && existingNode ) {
2014-07-07 21:02:42 +00:00
// Another instance has beat us and already created the super node.
callback ( ) ;
2014-05-23 18:14:06 +00:00
} else if ( error && ! ( error instanceof Errors . ENOENT ) ) {
callback ( error ) ;
} else {
2018-06-25 12:26:59 +00:00
SuperNode . create ( { guid : context . guid } , function ( error , result ) {
2014-06-02 20:44:20 +00:00
if ( error ) {
callback ( error ) ;
return ;
}
superNode = result ;
2014-08-16 20:22:41 +00:00
context . putObject ( superNode . id , superNode , write _directory _node ) ;
2014-06-02 20:44:20 +00:00
} ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function write _directory _node ( error ) {
if ( error ) {
callback ( error ) ;
} else {
2018-05-15 17:33:45 +00:00
Node . create ( {
guid : context . guid ,
id : superNode . rnode ,
2018-05-29 14:48:18 +00:00
type : NODE _TYPE _DIRECTORY
2018-05-15 17:33:45 +00:00
} , function ( error , result ) {
2014-06-02 20:44:20 +00:00
if ( error ) {
callback ( error ) ;
return ;
}
directoryNode = result ;
directoryNode . nlinks += 1 ;
2014-08-16 20:22:41 +00:00
context . putObject ( directoryNode . id , directoryNode , write _directory _data ) ;
2014-06-02 20:44:20 +00:00
} ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function write _directory _data ( error ) {
if ( error ) {
callback ( error ) ;
} else {
directoryData = { } ;
2014-08-16 20:22:41 +00:00
context . putObject ( directoryNode . data , directoryData , callback ) ;
2014-03-18 18:16:12 +00:00
}
}
2014-08-16 20:22:41 +00:00
context . getObject ( SUPER _NODE _ID , ensure _super _node ) ;
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
/ * *
* make _directory
* /
function make _directory ( context , path , callback ) {
path = normalize ( path ) ;
var name = basename ( path ) ;
var parentPath = dirname ( path ) ;
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
var directoryNode ;
var directoryData ;
var parentDirectoryNode ;
var parentDirectoryData ;
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function check _if _directory _exists ( error , result ) {
if ( ! error && result ) {
2014-08-18 23:13:50 +00:00
callback ( new Errors . EEXIST ( null , path ) ) ;
2014-05-23 18:14:06 +00:00
} else if ( error && ! ( error instanceof Errors . ENOENT ) ) {
callback ( error ) ;
} else {
find _node ( context , parentPath , read _parent _directory _data ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function read _parent _directory _data ( error , result ) {
if ( error ) {
callback ( error ) ;
} else {
parentDirectoryNode = result ;
2014-08-16 20:22:41 +00:00
context . getObject ( parentDirectoryNode . data , write _directory _node ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function write _directory _node ( error , result ) {
if ( error ) {
callback ( error ) ;
} else {
parentDirectoryData = result ;
2018-05-15 17:33:45 +00:00
Node . create ( {
guid : context . guid ,
2018-05-29 14:48:18 +00:00
type : NODE _TYPE _DIRECTORY
2018-05-15 17:33:45 +00:00
} , function ( error , result ) {
2014-06-02 20:44:20 +00:00
if ( error ) {
callback ( error ) ;
return ;
}
directoryNode = result ;
directoryNode . nlinks += 1 ;
2014-08-16 20:22:41 +00:00
context . putObject ( directoryNode . id , directoryNode , write _directory _data ) ;
2014-06-02 20:44:20 +00:00
} ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function write _directory _data ( error ) {
if ( error ) {
callback ( error ) ;
} else {
directoryData = { } ;
2014-08-16 20:22:41 +00:00
context . putObject ( directoryNode . data , directoryData , update _parent _directory _data ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function update _time ( error ) {
if ( error ) {
callback ( error ) ;
} else {
var now = Date . now ( ) ;
update _node _times ( context , parentPath , parentDirectoryNode , { mtime : now , ctime : now } , callback ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function update _parent _directory _data ( error ) {
if ( error ) {
callback ( error ) ;
} else {
2018-05-24 18:15:09 +00:00
parentDirectoryData [ name ] = new DirectoryEntry ( directoryNode . id , NODE _TYPE _DIRECTORY ) ;
2014-08-16 20:22:41 +00:00
context . putObject ( parentDirectoryNode . data , parentDirectoryData , update _time ) ;
2014-03-18 18:16:12 +00:00
}
}
2014-05-23 18:14:06 +00:00
find _node ( context , path , check _if _directory _exists ) ;
}
2014-03-18 18:16:12 +00:00
2018-11-17 20:31:20 +00:00
function access _file ( context , path , mode , callback ) {
path = normalize ( path ) ;
find _node ( context , path , function ( err ) {
if ( err ) {
return callback ( err ) ;
}
/ *
TODO : we currently only support Constants . fsConstants . F _OK
Working to fix the issue : https : //github.com/filerjs/filer/issues/561
* /
callback ( null ) ;
} ) ;
}
2014-05-23 18:14:06 +00:00
/ * *
* remove _directory
* /
function remove _directory ( context , path , callback ) {
path = normalize ( path ) ;
var name = basename ( path ) ;
var parentPath = dirname ( path ) ;
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
var directoryNode ;
var directoryData ;
var parentDirectoryNode ;
var parentDirectoryData ;
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function read _parent _directory _data ( error , result ) {
if ( error ) {
callback ( error ) ;
} else {
parentDirectoryNode = result ;
2014-08-16 20:22:41 +00:00
context . getObject ( parentDirectoryNode . data , check _if _node _exists ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function check _if _node _exists ( error , result ) {
if ( error ) {
callback ( error ) ;
2018-06-25 12:26:59 +00:00
} else if ( ROOT _DIRECTORY _NAME === name ) {
2014-08-18 23:13:50 +00:00
callback ( new Errors . EBUSY ( null , path ) ) ;
2018-11-28 01:49:38 +00:00
} else if ( ! result . hasOwnProperty ( name ) ) {
2014-08-18 23:13:50 +00:00
callback ( new Errors . ENOENT ( null , path ) ) ;
2014-05-23 18:14:06 +00:00
} else {
parentDirectoryData = result ;
directoryNode = parentDirectoryData [ name ] . id ;
2014-08-16 20:22:41 +00:00
context . getObject ( directoryNode , check _if _node _is _directory ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function check _if _node _is _directory ( error , result ) {
if ( error ) {
callback ( error ) ;
2018-06-25 12:26:59 +00:00
} else if ( result . type !== NODE _TYPE _DIRECTORY ) {
2014-08-18 23:13:50 +00:00
callback ( new Errors . ENOTDIR ( null , path ) ) ;
2014-05-23 18:14:06 +00:00
} else {
directoryNode = result ;
2014-08-16 20:22:41 +00:00
context . getObject ( directoryNode . data , check _if _directory _is _empty ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function check _if _directory _is _empty ( error , result ) {
if ( error ) {
callback ( error ) ;
} else {
directoryData = result ;
2018-11-28 01:49:38 +00:00
if ( Object . keys ( directoryData ) . length > 0 ) {
2014-08-18 23:13:50 +00:00
callback ( new Errors . ENOTEMPTY ( null , path ) ) ;
2014-03-18 18:16:12 +00:00
} else {
2014-05-23 18:14:06 +00:00
remove _directory _entry _from _parent _directory _node ( ) ;
2014-03-18 18:16:12 +00:00
}
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function update _time ( error ) {
if ( error ) {
callback ( error ) ;
} else {
var now = Date . now ( ) ;
update _node _times ( context , parentPath , parentDirectoryNode , { mtime : now , ctime : now } , remove _directory _node ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function remove _directory _entry _from _parent _directory _node ( ) {
delete parentDirectoryData [ name ] ;
2014-08-16 20:22:41 +00:00
context . putObject ( parentDirectoryNode . data , parentDirectoryData , update _time ) ;
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function remove _directory _node ( error ) {
if ( error ) {
callback ( error ) ;
} else {
context . delete ( directoryNode . id , remove _directory _data ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function remove _directory _data ( error ) {
if ( error ) {
callback ( error ) ;
} else {
context . delete ( directoryNode . data , callback ) ;
2014-03-18 18:16:12 +00:00
}
}
2014-05-23 18:14:06 +00:00
find _node ( context , parentPath , read _parent _directory _data ) ;
}
2014-03-18 18:16:12 +00:00
2018-09-24 23:10:09 +00:00
function open _file ( context , path , flags , mode , callback ) {
2018-10-10 00:25:19 +00:00
if ( typeof mode === 'function' ) {
2018-09-24 23:10:09 +00:00
callback = mode ;
2018-10-10 00:28:46 +00:00
mode = null ;
2018-09-24 23:10:09 +00:00
}
2014-05-23 18:14:06 +00:00
path = normalize ( path ) ;
var name = basename ( path ) ;
var parentPath = dirname ( path ) ;
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
var directoryNode ;
var directoryData ;
var directoryEntry ;
var fileNode ;
var fileData ;
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
var followedCount = 0 ;
2018-06-25 12:26:59 +00:00
if ( ROOT _DIRECTORY _NAME === name ) {
2018-11-28 01:49:38 +00:00
if ( flags . includes ( O _WRITE ) ) {
2014-08-18 23:13:50 +00:00
callback ( new Errors . EISDIR ( 'the named file is a directory and O_WRITE is set' , path ) ) ;
2014-08-18 15:03:46 +00:00
} else {
find _node ( context , path , set _file _node ) ;
}
2014-05-23 18:14:06 +00:00
} else {
find _node ( context , parentPath , read _directory _data ) ;
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function read _directory _data ( error , result ) {
if ( error ) {
callback ( error ) ;
2018-05-24 18:32:27 +00:00
} else if ( result . type !== NODE _TYPE _DIRECTORY ) {
2014-08-18 23:13:50 +00:00
callback ( new Errors . ENOENT ( null , path ) ) ;
2014-05-23 18:14:06 +00:00
} else {
directoryNode = result ;
2014-08-16 20:22:41 +00:00
context . getObject ( directoryNode . data , check _if _file _exists ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function check _if _file _exists ( error , result ) {
if ( error ) {
callback ( error ) ;
} else {
directoryData = result ;
2018-11-28 01:49:38 +00:00
if ( directoryData . hasOwnProperty ( name ) ) {
if ( flags . includes ( O _EXCLUSIVE ) ) {
2014-08-18 23:13:50 +00:00
callback ( new Errors . ENOENT ( 'O_CREATE and O_EXCLUSIVE are set, and the named file exists' , path ) ) ;
2014-03-18 18:16:12 +00:00
} else {
2014-05-23 18:14:06 +00:00
directoryEntry = directoryData [ name ] ;
2018-11-28 01:49:38 +00:00
if ( directoryEntry . type === NODE _TYPE _DIRECTORY && flags . includes ( O _WRITE ) ) {
2014-08-18 23:13:50 +00:00
callback ( new Errors . EISDIR ( 'the named file is a directory and O_WRITE is set' , path ) ) ;
2014-03-18 18:16:12 +00:00
} else {
2014-08-16 20:22:41 +00:00
context . getObject ( directoryEntry . id , check _if _symbolic _link ) ;
2014-03-18 18:16:12 +00:00
}
}
} else {
2018-11-28 01:49:38 +00:00
if ( ! flags . includes ( O _CREATE ) ) {
2014-08-18 23:13:50 +00:00
callback ( new Errors . ENOENT ( 'O_CREATE is not set and the named file does not exist' , path ) ) ;
2014-03-18 18:16:12 +00:00
} else {
2014-05-23 18:14:06 +00:00
write _file _node ( ) ;
2014-03-18 18:16:12 +00:00
}
}
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function check _if _symbolic _link ( error , result ) {
if ( error ) {
callback ( error ) ;
} else {
var node = result ;
2018-06-25 12:26:59 +00:00
if ( node . type === NODE _TYPE _SYMBOLIC _LINK ) {
2014-05-23 18:14:06 +00:00
followedCount ++ ;
if ( followedCount > SYMLOOP _MAX ) {
2014-08-18 23:13:50 +00:00
callback ( new Errors . ELOOP ( null , path ) ) ;
2014-03-18 18:16:12 +00:00
} else {
2014-05-23 18:14:06 +00:00
follow _symbolic _link ( node . data ) ;
2014-03-18 18:16:12 +00:00
}
} else {
2014-05-23 18:14:06 +00:00
set _file _node ( undefined , node ) ;
2014-03-18 18:16:12 +00:00
}
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function follow _symbolic _link ( data ) {
data = normalize ( data ) ;
parentPath = dirname ( data ) ;
name = basename ( data ) ;
2018-06-25 12:26:59 +00:00
if ( ROOT _DIRECTORY _NAME === name ) {
2018-11-28 01:49:38 +00:00
if ( flags . includes ( O _WRITE ) ) {
2014-08-18 23:13:50 +00:00
callback ( new Errors . EISDIR ( 'the named file is a directory and O_WRITE is set' , path ) ) ;
2014-03-18 18:16:12 +00:00
} else {
2014-05-23 18:14:06 +00:00
find _node ( context , path , set _file _node ) ;
2014-03-18 18:16:12 +00:00
}
}
2014-05-23 18:14:06 +00:00
find _node ( context , parentPath , read _directory _data ) ;
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function set _file _node ( error , result ) {
if ( error ) {
callback ( error ) ;
} else {
fileNode = result ;
callback ( null , fileNode ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function write _file _node ( ) {
2018-05-15 17:33:45 +00:00
Node . create ( {
guid : context . guid ,
2018-05-29 14:48:18 +00:00
type : NODE _TYPE _FILE
2018-05-15 17:33:45 +00:00
} , function ( error , result ) {
2014-06-02 20:44:20 +00:00
if ( error ) {
callback ( error ) ;
return ;
}
fileNode = result ;
fileNode . nlinks += 1 ;
2018-10-10 00:25:19 +00:00
if ( mode ) {
Node . setMode ( mode , fileNode ) ;
}
2014-08-16 20:22:41 +00:00
context . putObject ( fileNode . id , fileNode , write _file _data ) ;
2014-06-02 20:44:20 +00:00
} ) ;
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function write _file _data ( error ) {
if ( error ) {
callback ( error ) ;
} else {
2014-06-04 19:52:08 +00:00
fileData = new Buffer ( 0 ) ;
2014-06-06 15:14:52 +00:00
fileData . fill ( 0 ) ;
2014-08-16 20:22:41 +00:00
context . putBuffer ( fileNode . data , fileData , update _directory _data ) ;
2014-03-18 18:16:12 +00:00
}
}
2014-05-23 18:14:06 +00:00
function update _time ( error ) {
if ( error ) {
callback ( error ) ;
} else {
var now = Date . now ( ) ;
update _node _times ( context , parentPath , directoryNode , { mtime : now , ctime : now } , handle _update _result ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function update _directory _data ( error ) {
if ( error ) {
callback ( error ) ;
} else {
2018-05-24 18:15:09 +00:00
directoryData [ name ] = new DirectoryEntry ( fileNode . id , NODE _TYPE _FILE ) ;
2014-08-16 20:22:41 +00:00
context . putObject ( directoryNode . data , directoryData , update _time ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function handle _update _result ( error ) {
if ( error ) {
callback ( error ) ;
} else {
callback ( null , fileNode ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
}
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function replace _data ( context , ofd , buffer , offset , length , callback ) {
var fileNode ;
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function return _nbytes ( error ) {
if ( error ) {
callback ( error ) ;
} else {
callback ( null , length ) ;
2014-03-18 18:16:12 +00:00
}
}
2014-05-23 18:14:06 +00:00
function update _time ( error ) {
if ( error ) {
callback ( error ) ;
} else {
var now = Date . now ( ) ;
update _node _times ( context , ofd . path , fileNode , { mtime : now , ctime : now } , return _nbytes ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function update _file _node ( error ) {
if ( error ) {
callback ( error ) ;
} else {
2014-08-16 20:22:41 +00:00
context . putObject ( fileNode . id , fileNode , update _time ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function write _file _data ( error , result ) {
if ( error ) {
callback ( error ) ;
} else {
fileNode = result ;
2014-06-04 19:52:08 +00:00
var newData = new Buffer ( length ) ;
2014-06-06 15:14:52 +00:00
newData . fill ( 0 ) ;
buffer . copy ( newData , 0 , offset , offset + length ) ;
2014-05-23 18:14:06 +00:00
ofd . position = length ;
fileNode . size = length ;
2018-05-24 19:41:54 +00:00
fileNode . version += 1 ;
2014-05-23 18:14:06 +00:00
2014-08-16 20:22:41 +00:00
context . putBuffer ( fileNode . data , newData , update _file _node ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-08-16 20:22:41 +00:00
context . getObject ( ofd . id , write _file _data ) ;
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function write _data ( context , ofd , buffer , offset , length , position , callback ) {
var fileNode ;
var fileData ;
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function return _nbytes ( error ) {
if ( error ) {
callback ( error ) ;
} else {
callback ( null , length ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function update _time ( error ) {
if ( error ) {
callback ( error ) ;
} else {
var now = Date . now ( ) ;
update _node _times ( context , ofd . path , fileNode , { mtime : now , ctime : now } , return _nbytes ) ;
2014-03-18 18:16:12 +00:00
}
}
2014-05-23 18:14:06 +00:00
function update _file _node ( error ) {
if ( error ) {
callback ( error ) ;
} else {
2014-08-16 20:22:41 +00:00
context . putObject ( fileNode . id , fileNode , update _time ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function update _file _data ( error , result ) {
if ( error ) {
callback ( error ) ;
} else {
2014-08-16 21:02:18 +00:00
fileData = result ;
2014-06-25 17:13:55 +00:00
if ( ! fileData ) {
return callback ( new Errors . EIO ( 'Expected Buffer' ) ) ;
}
2014-05-23 18:14:06 +00:00
var _position = ( ! ( undefined === position || null === position ) ) ? position : ofd . position ;
var newSize = Math . max ( fileData . length , _position + length ) ;
2014-06-04 19:52:08 +00:00
var newData = new Buffer ( newSize ) ;
2014-06-06 15:14:52 +00:00
newData . fill ( 0 ) ;
2014-05-23 18:14:06 +00:00
if ( fileData ) {
2014-06-06 15:14:52 +00:00
fileData . copy ( newData ) ;
2014-06-04 19:52:08 +00:00
}
2014-06-06 15:14:52 +00:00
buffer . copy ( newData , _position , offset , offset + length ) ;
2014-05-23 18:14:06 +00:00
if ( undefined === position ) {
ofd . position += length ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
fileNode . size = newSize ;
2018-05-24 19:41:54 +00:00
fileNode . version += 1 ;
2014-03-18 18:16:12 +00:00
2014-08-16 20:22:41 +00:00
context . putBuffer ( fileNode . data , newData , update _file _node ) ;
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
function read _file _data ( error , result ) {
if ( error ) {
callback ( error ) ;
} else {
fileNode = result ;
2014-08-16 20:22:41 +00:00
context . getBuffer ( fileNode . data , update _file _data ) ;
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
}
2014-08-16 20:22:41 +00:00
context . getObject ( ofd . id , read _file _data ) ;
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function read _data ( context , ofd , buffer , offset , length , position , callback ) {
var fileNode ;
var fileData ;
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function handle _file _data ( error , result ) {
if ( error ) {
callback ( error ) ;
2014-03-18 18:16:12 +00:00
} else {
2014-08-16 21:02:18 +00:00
fileData = result ;
2014-06-25 17:13:55 +00:00
if ( ! fileData ) {
return callback ( new Errors . EIO ( 'Expected Buffer' ) ) ;
}
2014-05-23 18:14:06 +00:00
var _position = ( ! ( undefined === position || null === position ) ) ? position : ofd . position ;
length = ( _position + length > buffer . length ) ? length - _position : length ;
2014-06-06 15:14:52 +00:00
fileData . copy ( buffer , offset , _position , _position + length ) ;
2014-05-23 18:14:06 +00:00
if ( undefined === position ) {
ofd . position += length ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
callback ( null , length ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function read _file _data ( error , result ) {
if ( error ) {
callback ( error ) ;
2018-05-24 18:32:27 +00:00
} else if ( result . type === NODE _TYPE _DIRECTORY ) {
2014-11-16 05:12:53 +00:00
callback ( new Errors . EISDIR ( 'the named file is a directory' , ofd . path ) ) ;
2014-05-23 18:14:06 +00:00
} else {
fileNode = result ;
2014-08-16 20:22:41 +00:00
context . getBuffer ( fileNode . data , handle _file _data ) ;
2014-03-18 18:16:12 +00:00
}
}
2014-08-16 20:22:41 +00:00
context . getObject ( ofd . id , read _file _data ) ;
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function stat _file ( context , path , callback ) {
path = normalize ( path ) ;
2014-09-27 15:22:15 +00:00
find _node ( context , path , callback ) ;
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function fstat _file ( context , ofd , callback ) {
2014-10-17 16:55:36 +00:00
ofd . getNode ( context , callback ) ;
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function lstat _file ( context , path , callback ) {
path = normalize ( path ) ;
var name = basename ( path ) ;
var parentPath = dirname ( path ) ;
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
var directoryNode ;
var directoryData ;
2014-03-18 18:16:12 +00:00
2018-06-25 12:26:59 +00:00
if ( ROOT _DIRECTORY _NAME === name ) {
2014-09-27 15:22:15 +00:00
find _node ( context , path , callback ) ;
2014-05-23 18:14:06 +00:00
} else {
find _node ( context , parentPath , read _directory _data ) ;
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function read _directory _data ( error , result ) {
if ( error ) {
callback ( error ) ;
} else {
directoryNode = result ;
2014-08-16 20:22:41 +00:00
context . getObject ( directoryNode . data , check _if _file _exists ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function check _if _file _exists ( error , result ) {
if ( error ) {
callback ( error ) ;
} else {
directoryData = result ;
2018-11-28 01:49:38 +00:00
if ( ! directoryData . hasOwnProperty ( name ) ) {
2014-08-18 23:13:50 +00:00
callback ( new Errors . ENOENT ( 'a component of the path does not name an existing file' , path ) ) ;
2014-03-18 18:16:12 +00:00
} else {
2014-09-27 15:22:15 +00:00
context . getObject ( directoryData [ name ] . id , callback ) ;
2014-03-18 18:16:12 +00:00
}
}
2014-05-23 18:14:06 +00:00
}
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function link _node ( context , oldpath , newpath , callback ) {
oldpath = normalize ( oldpath ) ;
var oldname = basename ( oldpath ) ;
var oldParentPath = dirname ( oldpath ) ;
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
newpath = normalize ( newpath ) ;
var newname = basename ( newpath ) ;
var newParentPath = dirname ( newpath ) ;
2018-05-22 18:16:20 +00:00
var ctime = Date . now ( ) ;
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
var oldDirectoryNode ;
var oldDirectoryData ;
var newDirectoryNode ;
var newDirectoryData ;
2018-05-26 20:57:57 +00:00
var fileNodeID ;
2014-05-23 18:14:06 +00:00
var fileNode ;
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function update _time ( error ) {
if ( error ) {
callback ( error ) ;
} else {
2018-05-22 18:16:20 +00:00
update _node _times ( context , newpath , fileNode , { ctime : ctime } , callback ) ;
2014-05-23 18:14:06 +00:00
}
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function update _file _node ( error , result ) {
if ( error ) {
callback ( error ) ;
} else {
2018-05-26 20:57:57 +00:00
fileNode = result ;
2014-05-23 18:14:06 +00:00
fileNode . nlinks += 1 ;
2014-08-16 20:22:41 +00:00
context . putObject ( fileNode . id , fileNode , update _time ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2018-07-27 15:23:06 +00:00
function read _file _node ( error ) {
2014-05-23 18:14:06 +00:00
if ( error ) {
callback ( error ) ;
} else {
2018-05-26 20:57:57 +00:00
context . getObject ( fileNodeID , update _file _node ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function check _if _new _file _exists ( error , result ) {
if ( error ) {
callback ( error ) ;
} else {
newDirectoryData = result ;
2018-11-28 01:49:38 +00:00
if ( newDirectoryData . hasOwnProperty ( newname ) ) {
2014-08-18 23:13:50 +00:00
callback ( new Errors . EEXIST ( 'newpath resolves to an existing file' , newname ) ) ;
2014-03-18 18:16:12 +00:00
} else {
2014-05-23 18:14:06 +00:00
newDirectoryData [ newname ] = oldDirectoryData [ oldname ] ;
2018-05-26 20:57:57 +00:00
fileNodeID = newDirectoryData [ newname ] . id ;
context . putObject ( newDirectoryNode . data , newDirectoryData , read _file _node ) ;
2014-03-18 18:16:12 +00:00
}
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function read _new _directory _data ( error , result ) {
if ( error ) {
callback ( error ) ;
} else {
newDirectoryNode = result ;
2014-08-16 20:22:41 +00:00
context . getObject ( newDirectoryNode . data , check _if _new _file _exists ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function check _if _old _file _exists ( error , result ) {
if ( error ) {
callback ( error ) ;
} else {
oldDirectoryData = result ;
2018-11-28 01:49:38 +00:00
if ( ! oldDirectoryData . hasOwnProperty ( oldname ) ) {
2014-08-18 23:13:50 +00:00
callback ( new Errors . ENOENT ( 'a component of either path prefix does not exist' , oldname ) ) ;
2018-05-24 18:15:09 +00:00
} else if ( oldDirectoryData [ oldname ] . type === NODE _TYPE _DIRECTORY ) {
2014-12-06 06:16:22 +00:00
callback ( new Errors . EPERM ( 'oldpath refers to a directory' ) ) ;
2014-03-18 18:16:12 +00:00
} else {
2014-05-23 18:14:06 +00:00
find _node ( context , newParentPath , read _new _directory _data ) ;
2014-03-18 18:16:12 +00:00
}
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function read _old _directory _data ( error , result ) {
if ( error ) {
callback ( error ) ;
} else {
oldDirectoryNode = result ;
2014-08-16 20:22:41 +00:00
context . getObject ( oldDirectoryNode . data , check _if _old _file _exists ) ;
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
find _node ( context , oldParentPath , read _old _directory _data ) ;
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function unlink _node ( context , path , callback ) {
path = normalize ( path ) ;
var name = basename ( path ) ;
var parentPath = dirname ( path ) ;
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
var directoryNode ;
var directoryData ;
var fileNode ;
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function update _directory _data ( error ) {
if ( error ) {
callback ( error ) ;
} else {
delete directoryData [ name ] ;
2014-08-16 20:22:41 +00:00
context . putObject ( directoryNode . data , directoryData , function ( error ) {
2018-07-27 15:23:06 +00:00
if ( error ) {
callback ( error ) ;
} else {
var now = Date . now ( ) ;
update _node _times ( context , parentPath , directoryNode , { mtime : now , ctime : now } , callback ) ;
}
2014-05-23 18:14:06 +00:00
} ) ;
2014-03-18 18:16:12 +00:00
}
}
2014-05-23 18:14:06 +00:00
function delete _file _data ( error ) {
if ( error ) {
callback ( error ) ;
2014-03-18 18:16:12 +00:00
} else {
2014-05-23 18:14:06 +00:00
context . delete ( fileNode . data , update _directory _data ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function update _file _node ( error , result ) {
if ( error ) {
callback ( error ) ;
} else {
fileNode = result ;
fileNode . nlinks -= 1 ;
if ( fileNode . nlinks < 1 ) {
context . delete ( fileNode . id , delete _file _data ) ;
2014-03-18 18:16:12 +00:00
} else {
2014-08-16 20:22:41 +00:00
context . putObject ( fileNode . id , fileNode , function ( error ) {
2018-07-27 15:23:06 +00:00
if ( error ) {
callback ( error ) ;
} else {
update _node _times ( context , path , fileNode , { ctime : Date . now ( ) } , update _directory _data ) ;
}
2014-05-23 18:14:06 +00:00
} ) ;
2014-03-18 18:16:12 +00:00
}
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-09-22 15:16:02 +00:00
function check _if _node _is _directory ( error , result ) {
if ( error ) {
callback ( error ) ;
2018-05-24 18:32:27 +00:00
} else if ( result . type === NODE _TYPE _DIRECTORY ) {
2014-09-24 15:22:29 +00:00
callback ( new Errors . EPERM ( 'unlink not permitted on directories' , name ) ) ;
2014-09-22 15:16:02 +00:00
} else {
update _file _node ( null , result ) ;
}
}
2014-05-23 18:14:06 +00:00
function check _if _file _exists ( error , result ) {
if ( error ) {
callback ( error ) ;
} else {
directoryData = result ;
2018-11-28 01:49:38 +00:00
if ( ! directoryData . hasOwnProperty ( name ) ) {
2014-08-18 23:13:50 +00:00
callback ( new Errors . ENOENT ( 'a component of the path does not name an existing file' , name ) ) ;
2014-03-18 18:16:12 +00:00
} else {
2014-09-22 15:16:02 +00:00
context . getObject ( directoryData [ name ] . id , check _if _node _is _directory ) ;
2014-03-18 18:16:12 +00:00
}
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function read _directory _data ( error , result ) {
if ( error ) {
callback ( error ) ;
} else {
directoryNode = result ;
2014-08-16 20:22:41 +00:00
context . getObject ( directoryNode . data , check _if _file _exists ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
find _node ( context , parentPath , read _directory _data ) ;
}
function read _directory ( context , path , callback ) {
path = normalize ( path ) ;
var directoryNode ;
var directoryData ;
function handle _directory _data ( error , result ) {
if ( error ) {
callback ( error ) ;
} else {
directoryData = result ;
var files = Object . keys ( directoryData ) ;
callback ( null , files ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function read _directory _data ( error , result ) {
if ( error ) {
callback ( error ) ;
2018-05-24 18:32:27 +00:00
} else if ( result . type !== NODE _TYPE _DIRECTORY ) {
2014-08-20 19:47:14 +00:00
callback ( new Errors . ENOTDIR ( null , path ) ) ;
2014-05-23 18:14:06 +00:00
} else {
directoryNode = result ;
2014-08-16 20:22:41 +00:00
context . getObject ( directoryNode . data , handle _directory _data ) ;
2014-03-18 18:16:12 +00:00
}
}
2014-05-23 18:14:06 +00:00
find _node ( context , path , read _directory _data ) ;
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function make _symbolic _link ( context , srcpath , dstpath , callback ) {
dstpath = normalize ( dstpath ) ;
var name = basename ( dstpath ) ;
var parentPath = dirname ( dstpath ) ;
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
var directoryNode ;
var directoryData ;
var fileNode ;
2018-06-25 12:26:59 +00:00
if ( ROOT _DIRECTORY _NAME === name ) {
2014-08-18 23:13:50 +00:00
callback ( new Errors . EEXIST ( null , name ) ) ;
2014-05-23 18:14:06 +00:00
} else {
2014-03-18 18:16:12 +00:00
find _node ( context , parentPath , read _directory _data ) ;
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function read _directory _data ( error , result ) {
if ( error ) {
callback ( error ) ;
} else {
directoryNode = result ;
2014-08-16 20:22:41 +00:00
context . getObject ( directoryNode . data , check _if _file _exists ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function check _if _file _exists ( error , result ) {
if ( error ) {
callback ( error ) ;
} else {
directoryData = result ;
2018-11-28 01:49:38 +00:00
if ( directoryData . hasOwnProperty ( name ) ) {
2014-08-18 23:13:50 +00:00
callback ( new Errors . EEXIST ( null , name ) ) ;
2014-03-18 18:16:12 +00:00
} else {
2014-05-23 18:14:06 +00:00
write _file _node ( ) ;
2014-03-18 18:16:12 +00:00
}
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function write _file _node ( ) {
2018-05-15 17:33:45 +00:00
Node . create ( {
guid : context . guid ,
2018-05-29 14:48:18 +00:00
type : NODE _TYPE _SYMBOLIC _LINK
2018-05-15 17:33:45 +00:00
} , function ( error , result ) {
2014-06-02 20:44:20 +00:00
if ( error ) {
callback ( error ) ;
return ;
}
fileNode = result ;
fileNode . nlinks += 1 ;
2018-05-29 14:48:18 +00:00
// If the srcpath isn't absolute, resolve it relative to the dstpath
// but store both versions, since we'll use the relative one in readlink().
if ( ! isAbsolutePath ( srcpath ) ) {
fileNode . symlink _relpath = srcpath ;
srcpath = Path . resolve ( parentPath , srcpath ) ;
}
2014-06-02 20:44:20 +00:00
fileNode . size = srcpath . length ;
fileNode . data = srcpath ;
2018-05-29 14:48:18 +00:00
2014-08-16 20:22:41 +00:00
context . putObject ( fileNode . id , fileNode , update _directory _data ) ;
2014-06-02 20:44:20 +00:00
} ) ;
2014-05-23 18:14:06 +00:00
}
function update _time ( error ) {
if ( error ) {
callback ( error ) ;
} else {
var now = Date . now ( ) ;
update _node _times ( context , parentPath , directoryNode , { mtime : now , ctime : now } , callback ) ;
2014-03-18 18:16:12 +00:00
}
}
2014-05-23 18:14:06 +00:00
function update _directory _data ( error ) {
if ( error ) {
callback ( error ) ;
} else {
2018-05-24 18:15:09 +00:00
directoryData [ name ] = new DirectoryEntry ( fileNode . id , NODE _TYPE _SYMBOLIC _LINK ) ;
2014-08-16 20:22:41 +00:00
context . putObject ( directoryNode . data , directoryData , update _time ) ;
2014-05-23 18:14:06 +00:00
}
}
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function read _link ( context , path , callback ) {
path = normalize ( path ) ;
var name = basename ( path ) ;
var parentPath = dirname ( path ) ;
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
var directoryNode ;
var directoryData ;
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
find _node ( context , parentPath , read _directory _data ) ;
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function read _directory _data ( error , result ) {
if ( error ) {
callback ( error ) ;
} else {
directoryNode = result ;
2014-08-16 20:22:41 +00:00
context . getObject ( directoryNode . data , check _if _file _exists ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function check _if _file _exists ( error , result ) {
if ( error ) {
callback ( error ) ;
} else {
directoryData = result ;
2018-11-28 01:49:38 +00:00
if ( ! directoryData . hasOwnProperty ( name ) ) {
2014-08-18 23:13:50 +00:00
callback ( new Errors . ENOENT ( 'a component of the path does not name an existing file' , name ) ) ;
2014-03-18 18:16:12 +00:00
} else {
2014-08-16 20:22:41 +00:00
context . getObject ( directoryData [ name ] . id , check _if _symbolic ) ;
2014-03-18 18:16:12 +00:00
}
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2018-05-29 14:48:18 +00:00
function check _if _symbolic ( error , fileNode ) {
2014-05-23 18:14:06 +00:00
if ( error ) {
callback ( error ) ;
2014-03-18 18:16:12 +00:00
} else {
2018-06-25 12:26:59 +00:00
if ( fileNode . type !== NODE _TYPE _SYMBOLIC _LINK ) {
2014-08-18 23:13:50 +00:00
callback ( new Errors . EINVAL ( 'path not a symbolic link' , path ) ) ;
2014-05-23 18:14:06 +00:00
} else {
2018-05-29 14:48:18 +00:00
// If we were originally given a relative path, return that now vs. the
// absolute path we've generated and use elsewhere internally.
var target = fileNode . symlink _relpath ? fileNode . symlink _relpath : fileNode . data ;
callback ( null , target ) ;
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
}
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function truncate _file ( context , path , length , callback ) {
path = normalize ( path ) ;
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
var fileNode ;
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function read _file _data ( error , node ) {
if ( error ) {
callback ( error ) ;
2018-06-25 12:26:59 +00:00
} else if ( node . type === NODE _TYPE _DIRECTORY ) {
2014-08-18 23:13:50 +00:00
callback ( new Errors . EISDIR ( null , path ) ) ;
2014-05-23 18:14:06 +00:00
} else {
fileNode = node ;
2014-08-16 21:02:18 +00:00
context . getBuffer ( fileNode . data , truncate _file _data ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function truncate _file _data ( error , fileData ) {
if ( error ) {
callback ( error ) ;
} else {
2014-06-25 17:13:55 +00:00
if ( ! fileData ) {
return callback ( new Errors . EIO ( 'Expected Buffer' ) ) ;
}
2018-10-09 17:53:26 +00:00
try {
validateInteger ( length , 'len' ) ;
}
catch ( error ) {
return callback ( error ) ;
}
2014-06-04 19:52:08 +00:00
var data = new Buffer ( length ) ;
2014-06-06 15:14:52 +00:00
data . fill ( 0 ) ;
2014-05-23 18:14:06 +00:00
if ( fileData ) {
2014-06-04 19:52:08 +00:00
fileData . copy ( data ) ;
2014-03-18 18:16:12 +00:00
}
2014-08-16 20:22:41 +00:00
context . putBuffer ( fileNode . data , data , update _file _node ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function update _time ( error ) {
if ( error ) {
callback ( error ) ;
2014-03-18 18:16:12 +00:00
} else {
2014-05-23 18:14:06 +00:00
var now = Date . now ( ) ;
update _node _times ( context , path , fileNode , { mtime : now , ctime : now } , callback ) ;
2014-03-18 18:16:12 +00:00
}
}
2014-05-23 18:14:06 +00:00
function update _file _node ( error ) {
if ( error ) {
callback ( error ) ;
} else {
fileNode . size = length ;
2018-05-24 19:41:54 +00:00
fileNode . version += 1 ;
2014-08-16 20:22:41 +00:00
context . putObject ( fileNode . id , fileNode , update _time ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
if ( length < 0 ) {
callback ( new Errors . EINVAL ( 'length cannot be negative' ) ) ;
} else {
find _node ( context , path , read _file _data ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function ftruncate _file ( context , ofd , length , callback ) {
var fileNode ;
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function read _file _data ( error , node ) {
if ( error ) {
callback ( error ) ;
2018-06-25 12:26:59 +00:00
} else if ( node . type === NODE _TYPE _DIRECTORY ) {
2014-05-23 18:14:06 +00:00
callback ( new Errors . EISDIR ( ) ) ;
} else {
fileNode = node ;
2014-08-16 21:02:18 +00:00
context . getBuffer ( fileNode . data , truncate _file _data ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function truncate _file _data ( error , fileData ) {
if ( error ) {
callback ( error ) ;
} else {
2014-06-04 19:52:08 +00:00
var data ;
2014-06-25 17:13:55 +00:00
if ( ! fileData ) {
return callback ( new Errors . EIO ( 'Expected Buffer' ) ) ;
}
2014-05-23 18:14:06 +00:00
if ( fileData ) {
2014-06-04 19:52:08 +00:00
data = fileData . slice ( 0 , length ) ;
} else {
data = new Buffer ( length ) ;
2014-06-06 15:14:52 +00:00
data . fill ( 0 ) ;
2014-05-23 18:14:06 +00:00
}
2014-08-16 20:22:41 +00:00
context . putBuffer ( fileNode . data , data , update _file _node ) ;
2014-03-18 18:16:12 +00:00
}
}
2014-05-23 18:14:06 +00:00
function update _time ( error ) {
if ( error ) {
callback ( error ) ;
} else {
var now = Date . now ( ) ;
update _node _times ( context , ofd . path , fileNode , { mtime : now , ctime : now } , callback ) ;
2014-03-18 18:16:12 +00:00
}
}
2014-05-23 18:14:06 +00:00
function update _file _node ( error ) {
if ( error ) {
callback ( error ) ;
} else {
fileNode . size = length ;
2018-05-24 19:41:54 +00:00
fileNode . version += 1 ;
2014-08-16 20:22:41 +00:00
context . putObject ( fileNode . id , fileNode , update _time ) ;
2014-03-18 18:16:12 +00:00
}
}
2014-05-23 18:14:06 +00:00
if ( length < 0 ) {
callback ( new Errors . EINVAL ( 'length cannot be negative' ) ) ;
} else {
2014-10-17 16:55:36 +00:00
ofd . getNode ( context , read _file _data ) ;
2014-05-23 18:14:06 +00:00
}
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function utimes _file ( context , path , atime , mtime , callback ) {
path = normalize ( path ) ;
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function update _times ( error , node ) {
if ( error ) {
callback ( error ) ;
} else {
update _node _times ( context , path , node , { atime : atime , ctime : mtime , mtime : mtime } , callback ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2018-06-25 12:26:59 +00:00
if ( typeof atime !== 'number' || typeof mtime !== 'number' ) {
2014-08-18 23:13:50 +00:00
callback ( new Errors . EINVAL ( 'atime and mtime must be number' , path ) ) ;
2014-05-23 18:14:06 +00:00
}
else if ( atime < 0 || mtime < 0 ) {
2014-08-18 23:13:50 +00:00
callback ( new Errors . EINVAL ( 'atime and mtime must be positive integers' , path ) ) ;
2014-05-23 18:14:06 +00:00
}
else {
find _node ( context , path , update _times ) ;
}
}
function futimes _file ( context , ofd , atime , mtime , callback ) {
function update _times ( error , node ) {
if ( error ) {
callback ( error ) ;
} else {
update _node _times ( context , ofd . path , node , { atime : atime , ctime : mtime , mtime : mtime } , callback ) ;
2014-03-18 18:16:12 +00:00
}
}
2018-06-25 12:26:59 +00:00
if ( typeof atime !== 'number' || typeof mtime !== 'number' ) {
2014-05-23 18:14:06 +00:00
callback ( new Errors . EINVAL ( 'atime and mtime must be a number' ) ) ;
}
else if ( atime < 0 || mtime < 0 ) {
callback ( new Errors . EINVAL ( 'atime and mtime must be positive integers' ) ) ;
}
else {
2014-10-17 16:55:36 +00:00
ofd . getNode ( context , update _times ) ;
2014-05-23 18:14:06 +00:00
}
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function setxattr _file ( context , path , name , value , flag , callback ) {
path = normalize ( path ) ;
2014-03-18 18:16:12 +00:00
2014-10-17 16:55:36 +00:00
function setxattr ( error , node ) {
if ( error ) {
return callback ( error ) ;
}
set _extended _attribute ( context , path , node , name , value , flag , callback ) ;
}
2018-06-25 12:26:59 +00:00
if ( typeof name !== 'string' ) {
2014-08-18 23:13:50 +00:00
callback ( new Errors . EINVAL ( 'attribute name must be a string' , path ) ) ;
2014-05-23 18:14:06 +00:00
}
else if ( ! name ) {
2014-08-18 23:13:50 +00:00
callback ( new Errors . EINVAL ( 'attribute name cannot be an empty string' , path ) ) ;
2014-05-23 18:14:06 +00:00
}
else if ( flag !== null &&
flag !== XATTR _CREATE && flag !== XATTR _REPLACE ) {
2014-08-18 23:13:50 +00:00
callback ( new Errors . EINVAL ( 'invalid flag, must be null, XATTR_CREATE or XATTR_REPLACE' , path ) ) ;
2014-05-23 18:14:06 +00:00
}
else {
2014-10-17 16:55:36 +00:00
find _node ( context , path , setxattr ) ;
2014-05-23 18:14:06 +00:00
}
}
function fsetxattr _file ( context , ofd , name , value , flag , callback ) {
2014-10-17 16:55:36 +00:00
function setxattr ( error , node ) {
if ( error ) {
return callback ( error ) ;
}
set _extended _attribute ( context , ofd . path , node , name , value , flag , callback ) ;
}
if ( typeof name !== 'string' ) {
2014-05-23 18:14:06 +00:00
callback ( new Errors . EINVAL ( 'attribute name must be a string' ) ) ;
}
else if ( ! name ) {
callback ( new Errors . EINVAL ( 'attribute name cannot be an empty string' ) ) ;
}
else if ( flag !== null &&
flag !== XATTR _CREATE && flag !== XATTR _REPLACE ) {
callback ( new Errors . EINVAL ( 'invalid flag, must be null, XATTR_CREATE or XATTR_REPLACE' ) ) ;
}
else {
2014-10-17 16:55:36 +00:00
ofd . getNode ( context , setxattr ) ;
2014-05-23 18:14:06 +00:00
}
}
function getxattr _file ( context , path , name , callback ) {
path = normalize ( path ) ;
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function get _xattr ( error , node ) {
2014-10-17 16:55:36 +00:00
if ( error ) {
return callback ( error ) ;
2014-03-18 18:16:12 +00:00
}
2014-10-17 16:55:36 +00:00
var xattrs = node . xattrs ;
if ( ! xattrs . hasOwnProperty ( name ) ) {
2014-08-18 23:13:50 +00:00
callback ( new Errors . ENOATTR ( null , path ) ) ;
2014-03-18 18:16:12 +00:00
}
else {
2014-10-17 16:55:36 +00:00
callback ( null , xattrs [ name ] ) ;
2014-03-18 18:16:12 +00:00
}
}
2018-06-25 12:26:59 +00:00
if ( typeof name !== 'string' ) {
2014-08-18 23:13:50 +00:00
callback ( new Errors . EINVAL ( 'attribute name must be a string' , path ) ) ;
2014-05-23 18:14:06 +00:00
}
else if ( ! name ) {
2014-08-18 23:13:50 +00:00
callback ( new Errors . EINVAL ( 'attribute name cannot be an empty string' , path ) ) ;
2014-05-23 18:14:06 +00:00
}
else {
find _node ( context , path , get _xattr ) ;
}
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function fgetxattr _file ( context , ofd , name , callback ) {
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function get _xattr ( error , node ) {
if ( error ) {
2014-10-17 16:55:36 +00:00
return callback ( error ) ;
2014-03-18 18:16:12 +00:00
}
2014-10-17 16:55:36 +00:00
var xattrs = node . xattrs ;
if ( ! xattrs . hasOwnProperty ( name ) ) {
2014-05-23 18:14:06 +00:00
callback ( new Errors . ENOATTR ( ) ) ;
2014-03-18 18:16:12 +00:00
}
else {
2014-10-17 16:55:36 +00:00
callback ( null , xattrs [ name ] ) ;
2014-03-18 18:16:12 +00:00
}
}
2018-06-25 12:26:59 +00:00
if ( typeof name !== 'string' ) {
2014-05-23 18:14:06 +00:00
callback ( new Errors . EINVAL ( ) ) ;
}
else if ( ! name ) {
callback ( new Errors . EINVAL ( 'attribute name cannot be an empty string' ) ) ;
}
else {
2014-10-17 16:55:36 +00:00
ofd . getNode ( context , get _xattr ) ;
2014-05-23 18:14:06 +00:00
}
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function removexattr _file ( context , path , name , callback ) {
path = normalize ( path ) ;
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function remove _xattr ( error , node ) {
2014-10-17 16:55:36 +00:00
if ( error ) {
return callback ( error ) ;
}
2014-05-23 18:14:06 +00:00
function update _time ( error ) {
if ( error ) {
2014-03-18 18:16:12 +00:00
callback ( error ) ;
2014-05-23 18:14:06 +00:00
} else {
update _node _times ( context , path , node , { ctime : Date . now ( ) } , callback ) ;
2014-03-18 18:16:12 +00:00
}
}
2014-10-17 16:55:36 +00:00
var xattrs = node . xattrs ;
if ( ! xattrs . hasOwnProperty ( name ) ) {
2014-08-18 23:13:50 +00:00
callback ( new Errors . ENOATTR ( null , path ) ) ;
2014-03-18 18:16:12 +00:00
}
else {
2014-10-17 16:55:36 +00:00
delete xattrs [ name ] ;
2014-08-16 20:22:41 +00:00
context . putObject ( node . id , node , update _time ) ;
2014-03-18 18:16:12 +00:00
}
}
2014-10-17 16:55:36 +00:00
if ( typeof name !== 'string' ) {
2014-08-18 23:13:50 +00:00
callback ( new Errors . EINVAL ( 'attribute name must be a string' , path ) ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
else if ( ! name ) {
2014-08-18 23:13:50 +00:00
callback ( new Errors . EINVAL ( 'attribute name cannot be an empty string' , path ) ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
else {
find _node ( context , path , remove _xattr ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function fremovexattr _file ( context , ofd , name , callback ) {
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function remove _xattr ( error , node ) {
2014-10-17 16:55:36 +00:00
if ( error ) {
return callback ( error ) ;
}
2014-05-23 18:14:06 +00:00
function update _time ( error ) {
2014-03-18 18:16:12 +00:00
if ( error ) {
callback ( error ) ;
} else {
2014-05-23 18:14:06 +00:00
update _node _times ( context , ofd . path , node , { ctime : Date . now ( ) } , callback ) ;
2014-03-18 18:16:12 +00:00
}
}
2014-10-17 16:55:36 +00:00
var xattrs = node . xattrs ;
if ( ! xattrs . hasOwnProperty ( name ) ) {
2014-05-23 18:14:06 +00:00
callback ( new Errors . ENOATTR ( ) ) ;
}
else {
2014-10-17 16:55:36 +00:00
delete xattrs [ name ] ;
2014-08-16 20:22:41 +00:00
context . putObject ( node . id , node , update _time ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2018-06-25 12:26:59 +00:00
if ( typeof name !== 'string' ) {
2014-05-23 18:14:06 +00:00
callback ( new Errors . EINVAL ( 'attribute name must be a string' ) ) ;
}
else if ( ! name ) {
callback ( new Errors . EINVAL ( 'attribute name cannot be an empty string' ) ) ;
}
else {
2014-10-17 16:55:36 +00:00
ofd . getNode ( context , remove _xattr ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function validate _flags ( flags ) {
2018-11-28 01:49:38 +00:00
return O _FLAGS . hasOwnProperty ( flags ) ? O _FLAGS [ flags ] : null ;
2014-05-23 18:14:06 +00:00
}
function validate _file _options ( options , enc , fileMode ) {
if ( ! options ) {
options = { encoding : enc , flag : fileMode } ;
2018-07-15 17:25:35 +00:00
} else if ( typeof options === 'function' ) {
2014-05-23 18:14:06 +00:00
options = { encoding : enc , flag : fileMode } ;
2018-07-15 17:25:35 +00:00
} else if ( typeof options === 'string' ) {
2014-05-23 18:14:06 +00:00
options = { encoding : options , flag : fileMode } ;
2014-05-13 22:10:11 +00:00
}
2014-05-23 18:14:06 +00:00
return options ;
}
2014-03-18 18:16:12 +00:00
2018-05-29 14:48:18 +00:00
function pathCheck ( path , allowRelative , callback ) {
2014-05-23 18:14:06 +00:00
var err ;
2014-08-21 18:53:57 +00:00
2018-05-29 14:48:18 +00:00
if ( typeof allowRelative === 'function' ) {
callback = allowRelative ;
allowRelative = false ;
}
2014-08-21 18:53:57 +00:00
if ( ! path ) {
err = new Errors . EINVAL ( 'Path must be a string' , path ) ;
} else if ( isNullPath ( path ) ) {
2014-08-18 23:13:50 +00:00
err = new Errors . EINVAL ( 'Path must be a string without null bytes.' , path ) ;
2018-05-29 14:48:18 +00:00
} else if ( ! allowRelative && ! isAbsolutePath ( path ) ) {
2014-08-21 18:53:57 +00:00
err = new Errors . EINVAL ( 'Path must be absolute.' , path ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
if ( err ) {
callback ( err ) ;
return false ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
return true ;
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function open ( fs , context , path , flags , mode , callback ) {
2018-10-10 00:25:19 +00:00
if ( arguments . length < 6 ) {
2018-09-24 21:46:01 +00:00
callback = arguments [ arguments . length - 1 ] ;
2018-09-25 03:28:56 +00:00
mode = 0o644 ;
2018-09-24 21:46:01 +00:00
}
else {
mode = validateAndMaskMode ( mode , FULL _READ _WRITE _EXEC _PERMISSIONS , callback ) ;
}
2018-09-23 17:49:00 +00:00
2014-05-23 18:14:06 +00:00
if ( ! pathCheck ( path , callback ) ) return ;
function check _result ( error , fileNode ) {
if ( error ) {
callback ( error ) ;
} else {
var position ;
2018-11-28 01:49:38 +00:00
if ( flags . includes ( O _APPEND ) ) {
2014-05-23 18:14:06 +00:00
position = fileNode . size ;
2014-03-18 18:16:12 +00:00
} else {
2014-05-23 18:14:06 +00:00
position = 0 ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
var openFileDescription = new OpenFileDescription ( path , fileNode . id , flags , position ) ;
var fd = fs . allocDescriptor ( openFileDescription ) ;
callback ( null , fd ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
flags = validate _flags ( flags ) ;
if ( ! flags ) {
2014-08-18 23:13:50 +00:00
callback ( new Errors . EINVAL ( 'flags is not valid' ) , path ) ;
2014-03-18 18:16:12 +00:00
}
2018-09-24 23:10:09 +00:00
open _file ( context , path , flags , mode , check _result ) ;
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function close ( fs , context , fd , callback ) {
2018-11-28 01:49:38 +00:00
if ( ! fs . openFiles [ fd ] ) {
2014-05-23 18:14:06 +00:00
callback ( new Errors . EBADF ( ) ) ;
} else {
fs . releaseDescriptor ( fd ) ;
callback ( null ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2018-05-24 18:32:27 +00:00
function mknod ( fs , context , path , type , callback ) {
2014-05-23 18:14:06 +00:00
if ( ! pathCheck ( path , callback ) ) return ;
2018-05-24 18:32:27 +00:00
make _node ( context , path , type , callback ) ;
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function mkdir ( fs , context , path , mode , callback ) {
2018-05-28 19:03:34 +00:00
if ( arguments . length < 5 ) {
callback = mode ;
mode = FULL _READ _WRITE _EXEC _PERMISSIONS ;
} else {
mode = validateAndMaskMode ( mode , FULL _READ _WRITE _EXEC _PERMISSIONS , callback ) ;
if ( ! mode ) return ;
}
2014-05-23 18:14:06 +00:00
if ( ! pathCheck ( path , callback ) ) return ;
2014-09-27 15:22:15 +00:00
make _directory ( context , path , callback ) ;
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2018-11-17 20:31:20 +00:00
function access ( fs , context , path , mode , callback ) {
if ( typeof mode === 'function' ) {
callback = mode ;
mode = Constants . fsConstants . F _OK ;
}
if ( ! pathCheck ( path , callback ) ) return ;
mode = mode | 0 ;
access _file ( context , path , mode , callback ) ;
}
2014-05-23 18:14:06 +00:00
function rmdir ( fs , context , path , callback ) {
if ( ! pathCheck ( path , callback ) ) return ;
2014-09-27 15:22:15 +00:00
remove _directory ( context , path , callback ) ;
2014-05-23 18:14:06 +00:00
}
2014-03-18 20:34:47 +00:00
2014-05-23 18:14:06 +00:00
function stat ( fs , context , path , callback ) {
if ( ! pathCheck ( path , callback ) ) return ;
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function check _result ( error , result ) {
if ( error ) {
callback ( error ) ;
2014-03-18 18:16:12 +00:00
} else {
2018-05-26 20:57:57 +00:00
var stats = new Stats ( path , result , fs . name ) ;
2014-05-23 18:14:06 +00:00
callback ( null , stats ) ;
2014-03-18 18:16:12 +00:00
}
}
2014-05-23 18:14:06 +00:00
stat _file ( context , path , check _result ) ;
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function fstat ( fs , context , fd , callback ) {
function check _result ( error , result ) {
if ( error ) {
callback ( error ) ;
} else {
2018-05-26 21:45:28 +00:00
var stats = new Stats ( ofd . path , result , fs . name ) ;
2014-05-23 18:14:06 +00:00
callback ( null , stats ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
var ofd = fs . openFiles [ fd ] ;
if ( ! ofd ) {
callback ( new Errors . EBADF ( ) ) ;
} else {
fstat _file ( context , ofd , check _result ) ;
}
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function link ( fs , context , oldpath , newpath , callback ) {
if ( ! pathCheck ( oldpath , callback ) ) return ;
if ( ! pathCheck ( newpath , callback ) ) return ;
2014-09-27 15:22:15 +00:00
link _node ( context , oldpath , newpath , callback ) ;
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function unlink ( fs , context , path , callback ) {
if ( ! pathCheck ( path , callback ) ) return ;
2014-09-27 15:22:15 +00:00
unlink _node ( context , path , callback ) ;
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function read ( fs , context , fd , buffer , offset , length , position , callback ) {
// Follow how node.js does this
function wrapped _cb ( err , bytesRead ) {
// Retain a reference to buffer so that it can't be GC'ed too soon.
callback ( err , bytesRead || 0 , buffer ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
offset = ( undefined === offset ) ? 0 : offset ;
length = ( undefined === length ) ? buffer . length - offset : length ;
callback = arguments [ arguments . length - 1 ] ;
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
var ofd = fs . openFiles [ fd ] ;
if ( ! ofd ) {
callback ( new Errors . EBADF ( ) ) ;
2018-11-28 01:49:38 +00:00
} else if ( ! ofd . flags . includes ( O _READ ) ) {
2014-05-23 18:14:06 +00:00
callback ( new Errors . EBADF ( 'descriptor does not permit reading' ) ) ;
} else {
2014-09-27 15:22:15 +00:00
read _data ( context , ofd , buffer , offset , length , position , wrapped _cb ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function readFile ( fs , context , path , options , callback ) {
callback = arguments [ arguments . length - 1 ] ;
options = validate _file _options ( options , null , 'r' ) ;
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
if ( ! pathCheck ( path , callback ) ) return ;
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
var flags = validate _flags ( options . flag || 'r' ) ;
if ( ! flags ) {
2014-08-18 23:13:50 +00:00
return callback ( new Errors . EINVAL ( 'flags is not valid' , path ) ) ;
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
open _file ( context , path , flags , function ( err , fileNode ) {
if ( err ) {
return callback ( err ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
var ofd = new OpenFileDescription ( path , fileNode . id , flags , 0 ) ;
var fd = fs . allocDescriptor ( ofd ) ;
2014-03-18 18:16:12 +00:00
2014-08-18 15:03:46 +00:00
function cleanup ( ) {
fs . releaseDescriptor ( fd ) ;
}
fstat _file ( context , ofd , function ( err , fstatResult ) {
if ( err ) {
cleanup ( ) ;
return callback ( err ) ;
2014-03-18 18:16:12 +00:00
}
2018-05-26 20:57:57 +00:00
var stats = new Stats ( ofd . path , fstatResult , fs . name ) ;
2014-08-18 15:03:46 +00:00
if ( stats . isDirectory ( ) ) {
cleanup ( ) ;
2014-08-18 23:13:50 +00:00
return callback ( new Errors . EISDIR ( 'illegal operation on directory' , path ) ) ;
2014-08-18 15:03:46 +00:00
}
2014-05-23 18:14:06 +00:00
var size = stats . size ;
2014-06-04 19:52:08 +00:00
var buffer = new Buffer ( size ) ;
2014-06-06 15:14:52 +00:00
buffer . fill ( 0 ) ;
2014-05-23 18:14:06 +00:00
2018-07-27 15:23:06 +00:00
read _data ( context , ofd , buffer , 0 , size , 0 , function ( err ) {
2014-08-18 15:03:46 +00:00
cleanup ( ) ;
if ( err ) {
return callback ( err ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
var data ;
if ( options . encoding === 'utf8' ) {
2014-06-04 19:52:08 +00:00
data = Encoding . decode ( buffer ) ;
2014-05-23 18:14:06 +00:00
} else {
data = buffer ;
}
callback ( null , data ) ;
2014-03-18 18:16:12 +00:00
} ) ;
} ) ;
2014-05-23 18:14:06 +00:00
} ) ;
}
function write ( fs , context , fd , buffer , offset , length , position , callback ) {
callback = arguments [ arguments . length - 1 ] ;
offset = ( undefined === offset ) ? 0 : offset ;
length = ( undefined === length ) ? buffer . length - offset : length ;
var ofd = fs . openFiles [ fd ] ;
if ( ! ofd ) {
callback ( new Errors . EBADF ( ) ) ;
2018-11-28 01:49:38 +00:00
} else if ( ! ofd . flags . includes ( O _WRITE ) ) {
2014-05-23 18:14:06 +00:00
callback ( new Errors . EBADF ( 'descriptor does not permit writing' ) ) ;
} else if ( buffer . length - offset < length ) {
callback ( new Errors . EIO ( 'intput buffer is too small' ) ) ;
} else {
2014-09-27 15:22:15 +00:00
write _data ( context , ofd , buffer , offset , length , position , callback ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function writeFile ( fs , context , path , data , options , callback ) {
callback = arguments [ arguments . length - 1 ] ;
options = validate _file _options ( options , 'utf8' , 'w' ) ;
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
if ( ! pathCheck ( path , callback ) ) return ;
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
var flags = validate _flags ( options . flag || 'w' ) ;
if ( ! flags ) {
2014-08-18 23:13:50 +00:00
return callback ( new Errors . EINVAL ( 'flags is not valid' , path ) ) ;
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
data = data || '' ;
2018-07-15 17:25:35 +00:00
if ( typeof data === 'number' ) {
2014-05-23 18:14:06 +00:00
data = '' + data ;
}
2018-07-15 17:25:35 +00:00
if ( typeof data === 'string' && options . encoding === 'utf8' ) {
2014-06-04 19:52:08 +00:00
data = Encoding . encode ( data ) ;
2014-05-23 18:14:06 +00:00
}
open _file ( context , path , flags , function ( err , fileNode ) {
if ( err ) {
return callback ( err ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
var ofd = new OpenFileDescription ( path , fileNode . id , flags , 0 ) ;
var fd = fs . allocDescriptor ( ofd ) ;
2014-03-18 18:16:12 +00:00
2018-07-27 15:23:06 +00:00
replace _data ( context , ofd , data , 0 , data . length , function ( err ) {
2014-05-23 18:14:06 +00:00
fs . releaseDescriptor ( fd ) ;
2014-08-18 15:15:48 +00:00
if ( err ) {
return callback ( err ) ;
}
2014-05-23 18:14:06 +00:00
callback ( null ) ;
2014-03-18 18:16:12 +00:00
} ) ;
2014-05-23 18:14:06 +00:00
} ) ;
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function appendFile ( fs , context , path , data , options , callback ) {
callback = arguments [ arguments . length - 1 ] ;
options = validate _file _options ( options , 'utf8' , 'a' ) ;
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
if ( ! pathCheck ( path , callback ) ) return ;
var flags = validate _flags ( options . flag || 'a' ) ;
if ( ! flags ) {
2014-08-18 23:13:50 +00:00
return callback ( new Errors . EINVAL ( 'flags is not valid' , path ) ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
data = data || '' ;
2018-07-15 17:25:35 +00:00
if ( typeof data === 'number' ) {
2014-05-23 18:14:06 +00:00
data = '' + data ;
}
2018-07-15 17:25:35 +00:00
if ( typeof data === 'string' && options . encoding === 'utf8' ) {
2014-06-04 19:52:08 +00:00
data = Encoding . encode ( data ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
open _file ( context , path , flags , function ( err , fileNode ) {
if ( err ) {
return callback ( err ) ;
2014-03-18 20:34:47 +00:00
}
2014-05-23 18:14:06 +00:00
var ofd = new OpenFileDescription ( path , fileNode . id , flags , fileNode . size ) ;
var fd = fs . allocDescriptor ( ofd ) ;
2018-07-27 15:23:06 +00:00
write _data ( context , ofd , data , 0 , data . length , ofd . position , function ( err ) {
2014-05-23 18:14:06 +00:00
fs . releaseDescriptor ( fd ) ;
2014-08-18 15:15:48 +00:00
if ( err ) {
return callback ( err ) ;
}
2014-05-23 18:14:06 +00:00
callback ( null ) ;
} ) ;
} ) ;
}
2014-03-18 20:34:47 +00:00
2014-05-23 18:14:06 +00:00
function exists ( fs , context , path , callback ) {
2018-07-27 15:23:06 +00:00
function cb ( err ) {
2014-05-23 18:14:06 +00:00
callback ( err ? false : true ) ;
2014-03-18 18:16:12 +00:00
}
2018-08-27 23:50:41 +00:00
console . warn ( 'This method is deprecated. For more details see https://nodejs.org/api/fs.html#fs_fs_exists_path_callback' ) ; // eslint-disable-line no-console
2014-05-23 18:14:06 +00:00
stat ( fs , context , path , cb ) ;
}
2014-03-18 18:16:12 +00:00
2018-05-28 19:03:34 +00:00
// Based on https://github.com/nodejs/node/blob/c700cc42da9cf73af9fec2098520a6c0a631d901/lib/internal/validators.js#L21
var octalReg = /^[0-7]+$/ ;
function isUint32 ( value ) {
return value === ( value >>> 0 ) ;
}
// Validator for mode_t (the S_* constants). Valid numbers or octal strings
// will be masked with 0o777 to be consistent with the behavior in POSIX APIs.
function validateAndMaskMode ( value , def , callback ) {
if ( typeof def === 'function' ) {
callback = def ;
def = undefined ;
}
if ( isUint32 ( value ) ) {
return value & FULL _READ _WRITE _EXEC _PERMISSIONS ;
}
if ( typeof value === 'number' ) {
if ( ! Number . isInteger ( value ) ) {
callback ( new Errors . EINVAL ( 'mode not a valid an integer value' , value ) ) ;
return false ;
} else {
// 2 ** 32 === 4294967296
callback ( new Errors . EINVAL ( 'mode not a valid an integer value' , value ) ) ;
return false ;
}
}
if ( typeof value === 'string' ) {
if ( ! octalReg . test ( value ) ) {
callback ( new Errors . EINVAL ( 'mode not a valid octal string' , value ) ) ;
return false ;
}
var parsed = parseInt ( value , 8 ) ;
return parsed & FULL _READ _WRITE _EXEC _PERMISSIONS ;
}
2018-06-25 12:26:59 +00:00
// TODO(BridgeAR): Only return `def` in case `value === null`
2018-05-28 19:03:34 +00:00
if ( def !== undefined ) {
return def ;
}
callback ( new Errors . EINVAL ( 'mode not valid' , value ) ) ;
return false ;
}
function chmod _file ( context , path , mode , callback ) {
path = normalize ( path ) ;
function update _mode ( error , node ) {
if ( error ) {
callback ( error ) ;
} else {
2018-05-29 17:47:16 +00:00
Node . setMode ( mode , node ) ;
2018-05-28 19:03:34 +00:00
update _node _times ( context , path , node , { mtime : Date . now ( ) } , callback ) ;
}
}
2018-06-25 12:26:59 +00:00
if ( typeof mode !== 'number' ) {
2018-05-28 19:03:34 +00:00
callback ( new Errors . EINVAL ( 'mode must be number' , path ) ) ;
}
else {
find _node ( context , path , update _mode ) ;
}
}
function fchmod _file ( context , ofd , mode , callback ) {
function update _mode ( error , node ) {
if ( error ) {
callback ( error ) ;
} else {
node . mode = mode ;
update _node _times ( context , ofd . path , node , { mtime : Date . now ( ) } , callback ) ;
}
}
2018-06-25 12:26:59 +00:00
if ( typeof mode !== 'number' ) {
2018-05-28 19:03:34 +00:00
callback ( new Errors . EINVAL ( 'mode must be a number' ) ) ;
}
else {
ofd . getNode ( context , update _mode ) ;
}
}
function chown _file ( context , path , uid , gid , callback ) {
path = normalize ( path ) ;
function update _owner ( error , node ) {
if ( error ) {
callback ( error ) ;
} else {
node . uid = uid ;
node . gid = gid ;
update _node _times ( context , path , node , { mtime : Date . now ( ) } , callback ) ;
}
}
find _node ( context , path , update _owner ) ;
}
function fchown _file ( context , ofd , uid , gid , callback ) {
function update _owner ( error , node ) {
if ( error ) {
callback ( error ) ;
} else {
node . uid = uid ;
node . gid = gid ;
update _node _times ( context , ofd . path , node , { mtime : Date . now ( ) } , callback ) ;
}
}
ofd . getNode ( context , update _owner ) ;
}
2014-05-23 18:14:06 +00:00
function getxattr ( fs , context , path , name , callback ) {
if ( ! pathCheck ( path , callback ) ) return ;
2014-09-27 15:22:15 +00:00
getxattr _file ( context , path , name , callback ) ;
2014-05-23 18:14:06 +00:00
}
2014-03-18 20:34:47 +00:00
2014-05-23 18:14:06 +00:00
function fgetxattr ( fs , context , fd , name , callback ) {
var ofd = fs . openFiles [ fd ] ;
if ( ! ofd ) {
callback ( new Errors . EBADF ( ) ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
else {
2014-09-27 15:22:15 +00:00
fgetxattr _file ( context , ofd , name , callback ) ;
2014-05-23 18:14:06 +00:00
}
}
2018-06-25 12:26:59 +00:00
2014-05-23 18:14:06 +00:00
function setxattr ( fs , context , path , name , value , flag , callback ) {
if ( typeof flag === 'function' ) {
callback = flag ;
flag = null ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
if ( ! pathCheck ( path , callback ) ) return ;
2014-09-27 15:22:15 +00:00
setxattr _file ( context , path , name , value , flag , callback ) ;
2014-05-23 18:14:06 +00:00
}
function fsetxattr ( fs , context , fd , name , value , flag , callback ) {
if ( typeof flag === 'function' ) {
callback = flag ;
flag = null ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
var ofd = fs . openFiles [ fd ] ;
if ( ! ofd ) {
callback ( new Errors . EBADF ( ) ) ;
}
2018-11-28 01:49:38 +00:00
else if ( ! ofd . flags . includes ( O _WRITE ) ) {
2014-05-23 18:14:06 +00:00
callback ( new Errors . EBADF ( 'descriptor does not permit writing' ) ) ;
}
else {
2014-09-27 15:22:15 +00:00
fsetxattr _file ( context , ofd , name , value , flag , callback ) ;
2014-05-23 18:14:06 +00:00
}
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function removexattr ( fs , context , path , name , callback ) {
if ( ! pathCheck ( path , callback ) ) return ;
2014-09-27 15:22:15 +00:00
removexattr _file ( context , path , name , callback ) ;
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function fremovexattr ( fs , context , fd , name , callback ) {
var ofd = fs . openFiles [ fd ] ;
if ( ! ofd ) {
callback ( new Errors . EBADF ( ) ) ;
}
2018-11-28 01:49:38 +00:00
else if ( ! ofd . flags . includes ( O _WRITE ) ) {
2014-05-23 18:14:06 +00:00
callback ( new Errors . EBADF ( 'descriptor does not permit writing' ) ) ;
}
else {
2014-09-27 15:22:15 +00:00
fremovexattr _file ( context , ofd , name , callback ) ;
2014-05-23 18:14:06 +00:00
}
}
function lseek ( fs , context , fd , offset , whence , callback ) {
function update _descriptor _position ( error , stats ) {
if ( error ) {
callback ( error ) ;
} else {
if ( stats . size + offset < 0 ) {
2014-03-18 18:16:12 +00:00
callback ( new Errors . EINVAL ( 'resulting file offset would be negative' ) ) ;
} else {
2014-05-23 18:14:06 +00:00
ofd . position = stats . size + offset ;
2014-03-18 18:16:12 +00:00
callback ( null , ofd . position ) ;
}
}
}
2014-05-23 18:14:06 +00:00
var ofd = fs . openFiles [ fd ] ;
if ( ! ofd ) {
callback ( new Errors . EBADF ( ) ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
if ( 'SET' === whence ) {
if ( offset < 0 ) {
callback ( new Errors . EINVAL ( 'resulting file offset would be negative' ) ) ;
} else {
ofd . position = offset ;
callback ( null , ofd . position ) ;
}
} else if ( 'CUR' === whence ) {
if ( ofd . position + offset < 0 ) {
callback ( new Errors . EINVAL ( 'resulting file offset would be negative' ) ) ;
2014-03-18 18:16:12 +00:00
} else {
2014-05-23 18:14:06 +00:00
ofd . position += offset ;
callback ( null , ofd . position ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
} else if ( 'END' === whence ) {
fstat _file ( context , ofd , update _descriptor _position ) ;
} else {
callback ( new Errors . EINVAL ( 'whence argument is not a proper value' ) ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function readdir ( fs , context , path , callback ) {
if ( ! pathCheck ( path , callback ) ) return ;
2014-09-27 15:22:15 +00:00
read _directory ( context , path , callback ) ;
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function utimes ( fs , context , path , atime , mtime , callback ) {
if ( ! pathCheck ( path , callback ) ) return ;
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
var currentTime = Date . now ( ) ;
atime = ( atime ) ? atime : currentTime ;
mtime = ( mtime ) ? mtime : currentTime ;
2014-03-18 18:16:12 +00:00
2014-09-27 15:22:15 +00:00
utimes _file ( context , path , atime , mtime , callback ) ;
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function futimes ( fs , context , fd , atime , mtime , callback ) {
var currentTime = Date . now ( ) ;
atime = ( atime ) ? atime : currentTime ;
mtime = ( mtime ) ? mtime : currentTime ;
var ofd = fs . openFiles [ fd ] ;
if ( ! ofd ) {
callback ( new Errors . EBADF ( ) ) ;
2018-11-28 01:49:38 +00:00
} else if ( ! ofd . flags . includes ( O _WRITE ) ) {
2014-05-23 18:14:06 +00:00
callback ( new Errors . EBADF ( 'descriptor does not permit writing' ) ) ;
} else {
2014-09-27 15:22:15 +00:00
futimes _file ( context , ofd , atime , mtime , callback ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2018-05-28 19:03:34 +00:00
function chmod ( fs , context , path , mode , callback ) {
if ( ! pathCheck ( path , callback ) ) return ;
mode = validateAndMaskMode ( mode , 'mode' ) ;
if ( ! mode ) return ;
chmod _file ( context , path , mode , callback ) ;
}
function fchmod ( fs , context , fd , mode , callback ) {
mode = validateAndMaskMode ( mode , 'mode' ) ;
if ( ! mode ) return ;
var ofd = fs . openFiles [ fd ] ;
if ( ! ofd ) {
callback ( new Errors . EBADF ( ) ) ;
2018-11-28 01:49:38 +00:00
} else if ( ! ofd . flags . includes ( O _WRITE ) ) {
2018-05-28 19:03:34 +00:00
callback ( new Errors . EBADF ( 'descriptor does not permit writing' ) ) ;
} else {
fchmod _file ( context , ofd , mode , callback ) ;
}
}
function chown ( fs , context , path , uid , gid , callback ) {
if ( ! pathCheck ( path , callback ) ) return ;
if ( ! isUint32 ( uid ) ) {
return callback ( new Errors . EINVAL ( 'uid must be a valid integer' , uid ) ) ;
}
if ( ! isUint32 ( gid ) ) {
return callback ( new Errors . EINVAL ( 'gid must be a valid integer' , gid ) ) ;
}
chown _file ( context , path , uid , gid , callback ) ;
}
function fchown ( fs , context , fd , uid , gid , callback ) {
if ( ! isUint32 ( uid ) ) {
return callback ( new Errors . EINVAL ( 'uid must be a valid integer' , uid ) ) ;
}
if ( ! isUint32 ( gid ) ) {
return callback ( new Errors . EINVAL ( 'gid must be a valid integer' , gid ) ) ;
}
var ofd = fs . openFiles [ fd ] ;
if ( ! ofd ) {
callback ( new Errors . EBADF ( ) ) ;
2018-11-28 01:49:38 +00:00
} else if ( ! ofd . flags . includes ( O _WRITE ) ) {
2018-05-28 19:03:34 +00:00
callback ( new Errors . EBADF ( 'descriptor does not permit writing' ) ) ;
} else {
fchown _file ( context , ofd , uid , gid , callback ) ;
}
}
2014-05-23 18:14:06 +00:00
function rename ( fs , context , oldpath , newpath , callback ) {
if ( ! pathCheck ( oldpath , callback ) ) return ;
if ( ! pathCheck ( newpath , callback ) ) return ;
2014-03-18 18:16:12 +00:00
2015-05-12 19:16:32 +00:00
oldpath = normalize ( oldpath ) ;
newpath = normalize ( newpath ) ;
2014-10-16 02:04:03 +00:00
var oldParentPath = Path . dirname ( oldpath ) ;
var newParentPath = Path . dirname ( oldpath ) ;
var oldName = Path . basename ( oldpath ) ;
var newName = Path . basename ( newpath ) ;
var oldParentDirectory , oldParentData ;
var newParentDirectory , newParentData ;
2018-05-22 18:16:20 +00:00
var ctime = Date . now ( ) ;
var fileNode ;
2018-05-26 20:57:57 +00:00
function update _times ( error , result ) {
2018-05-22 18:16:20 +00:00
if ( error ) {
callback ( error ) ;
} else {
2018-05-26 20:57:57 +00:00
fileNode = result ;
2018-05-22 18:16:20 +00:00
update _node _times ( context , newpath , fileNode , { ctime : ctime } , callback ) ;
}
}
2014-10-16 02:04:03 +00:00
function read _new _directory ( error ) {
if ( error ) {
callback ( error ) ;
} else {
2018-05-26 20:57:57 +00:00
context . getObject ( newParentData [ newName ] . id , update _times ) ;
2014-10-16 02:04:03 +00:00
}
}
function update _old _parent _directory _data ( error ) {
if ( error ) {
callback ( error ) ;
} else {
2014-12-17 20:08:13 +00:00
if ( oldParentDirectory . id === newParentDirectory . id ) {
oldParentData = newParentData ;
}
2014-10-16 02:04:03 +00:00
delete oldParentData [ oldName ] ;
context . putObject ( oldParentDirectory . data , oldParentData , read _new _directory ) ;
}
}
function update _new _parent _directory _data ( error ) {
if ( error ) {
callback ( error ) ;
} else {
newParentData [ newName ] = oldParentData [ oldName ] ;
context . putObject ( newParentDirectory . data , newParentData , update _old _parent _directory _data ) ;
}
}
function check _if _new _directory _exists ( error , result ) {
if ( error ) {
callback ( error ) ;
} else {
newParentData = result ;
2018-11-28 01:49:38 +00:00
if ( newParentData . hasOwnProperty ( newName ) ) {
2014-10-16 02:04:03 +00:00
remove _directory ( context , newpath , update _new _parent _directory _data ) ;
} else {
update _new _parent _directory _data ( ) ;
}
}
}
function read _new _parent _directory _data ( error , result ) {
if ( error ) {
callback ( error ) ;
} else {
newParentDirectory = result ;
context . getObject ( newParentDirectory . data , check _if _new _directory _exists ) ;
}
}
function get _new _parent _directory ( error , result ) {
if ( error ) {
callback ( error ) ;
} else {
oldParentData = result ;
find _node ( context , newParentPath , read _new _parent _directory _data ) ;
}
}
function read _parent _directory _data ( error , result ) {
if ( error ) {
callback ( error ) ;
} else {
oldParentDirectory = result ;
context . getObject ( result . data , get _new _parent _directory ) ;
}
}
function unlink _old _file ( error ) {
2014-05-23 18:14:06 +00:00
if ( error ) {
callback ( error ) ;
} else {
2014-09-27 15:22:15 +00:00
unlink _node ( context , oldpath , callback ) ;
2014-03-18 18:16:12 +00:00
}
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-10-16 02:04:03 +00:00
function check _node _type ( error , node ) {
if ( error ) {
callback ( error ) ;
2018-05-24 18:32:27 +00:00
} else if ( node . type === NODE _TYPE _DIRECTORY ) {
2014-10-16 02:04:03 +00:00
find _node ( context , oldParentPath , read _parent _directory _data ) ;
} else {
link _node ( context , oldpath , newpath , unlink _old _file ) ;
}
}
find _node ( context , oldpath , check _node _type ) ;
2014-05-23 18:14:06 +00:00
}
function symlink ( fs , context , srcpath , dstpath , type , callback ) {
// NOTE: we support passing the `type` arg, but ignore it.
callback = arguments [ arguments . length - 1 ] ;
2018-05-29 14:48:18 +00:00
// Special Case: allow srcpath to be relative, which we normally don't permit.
// If the srcpath is relative, we assume it's relative to the dirpath of
// dstpath.
if ( ! pathCheck ( srcpath , true , callback ) ) return ;
2014-05-23 18:14:06 +00:00
if ( ! pathCheck ( dstpath , callback ) ) return ;
2018-05-29 14:48:18 +00:00
2014-09-27 15:22:15 +00:00
make _symbolic _link ( context , srcpath , dstpath , callback ) ;
2014-05-23 18:14:06 +00:00
}
2014-03-18 18:16:12 +00:00
2014-05-23 18:14:06 +00:00
function readlink ( fs , context , path , callback ) {
if ( ! pathCheck ( path , callback ) ) return ;
2014-09-27 15:22:15 +00:00
read _link ( context , path , callback ) ;
2014-05-23 18:14:06 +00:00
}
function lstat ( fs , context , path , callback ) {
if ( ! pathCheck ( path , callback ) ) return ;
function check _result ( error , result ) {
if ( error ) {
callback ( error ) ;
} else {
2018-05-26 20:57:57 +00:00
var stats = new Stats ( path , result , fs . name ) ;
2014-05-23 18:14:06 +00:00
callback ( null , stats ) ;
}
}
lstat _file ( context , path , check _result ) ;
}
function truncate ( fs , context , path , length , callback ) {
// NOTE: length is optional
callback = arguments [ arguments . length - 1 ] ;
length = length || 0 ;
if ( ! pathCheck ( path , callback ) ) return ;
2014-09-27 15:22:15 +00:00
truncate _file ( context , path , length , callback ) ;
2014-05-23 18:14:06 +00:00
}
function ftruncate ( fs , context , fd , length , callback ) {
// NOTE: length is optional
callback = arguments [ arguments . length - 1 ] ;
length = length || 0 ;
var ofd = fs . openFiles [ fd ] ;
if ( ! ofd ) {
callback ( new Errors . EBADF ( ) ) ;
2018-11-28 01:49:38 +00:00
} else if ( ! ofd . flags . includes ( O _WRITE ) ) {
2014-05-23 18:14:06 +00:00
callback ( new Errors . EBADF ( 'descriptor does not permit writing' ) ) ;
} else {
2014-09-27 15:22:15 +00:00
ftruncate _file ( context , ofd , length , callback ) ;
2014-05-23 18:14:06 +00:00
}
}
module . exports = {
2014-07-07 21:02:42 +00:00
ensureRootDirectory : ensure _root _directory ,
2014-05-23 18:14:06 +00:00
open : open ,
2018-05-28 19:03:34 +00:00
chmod : chmod ,
2018-11-17 20:31:20 +00:00
access : access ,
2018-05-28 19:03:34 +00:00
fchmod : fchmod ,
chown : chown ,
fchown : fchown ,
2014-05-23 18:14:06 +00:00
close : close ,
mknod : mknod ,
mkdir : mkdir ,
rmdir : rmdir ,
unlink : unlink ,
stat : stat ,
fstat : fstat ,
link : link ,
read : read ,
readFile : readFile ,
write : write ,
writeFile : writeFile ,
appendFile : appendFile ,
exists : exists ,
getxattr : getxattr ,
fgetxattr : fgetxattr ,
setxattr : setxattr ,
fsetxattr : fsetxattr ,
removexattr : removexattr ,
fremovexattr : fremovexattr ,
lseek : lseek ,
readdir : readdir ,
utimes : utimes ,
futimes : futimes ,
rename : rename ,
symlink : symlink ,
readlink : readlink ,
lstat : lstat ,
truncate : truncate ,
ftruncate : ftruncate
} ;