/*
* Copyright 2011-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
if (typeof __vertxload === 'string') {
throw "Use require() to load Vert.x API modules";
}
var Buffer = require('vertx/buffer');
var jfs = __jvertx.fileSystem();
/**
* File system operations are handled asynchronously. The result of the operations
* are given to a <code>ResultHandler</code>. The <code>ResultHandler</code> is
* just a {@linkcode Handler} that accepts two parameters: 1) an exception object
* if an error occurred; and 2) the result of the operation, the type of which is
* determined by the firing event.
*
* @typedef {function} ResultHandler
* @param {Exception} cause This will be <code>null</code> if the operation succeeded
* @param {{}} result The result of the operation event this handler cares about
*/
/**
* @exports vertx/file_system
*/
var fileSystem = {};
var streams = require('vertx/streams');
var helpers = require('vertx/helpers.js');
var wrapHandler = helpers.adaptAsyncResultHandler;
function propsHandler(handler) {
return wrapHandler(handler, function(result) {
return convertProps(result);
});
}
function asyncFileHandler(handler) {
return wrapHandler(handler, function(result) {
return new fileSystem.AsyncFile(result);
});
}
function arrayResultHandler(handler) {
return wrapHandler(handler, function(result) {
var arry = [];
for (var i = 0; i < result.length; i++) {
arry.push(result[i]);
}
return arry;
});
}
function convertProps(j_props) {
/**
* @typedef {{}} FileProps
* @property {date} creationTime The date the file was created
* @property {date} lastAccessTime The date the file was last accessed
* @property {date} lastModifiedTime The date the file was last modified
* @property {boolean} isDirectory is the file a directory?
* @property {boolean} isOther Is the file some other type? I.e. not a directory, regular file or symbolic link
* @property {boolean} isRegularFile is the file a regular file?
* @property {boolean} isSymbolicLink is the file a symlink?
* @property {number} size the size of the file in bytes
* */
return {
creationTime: j_props.creationTime().getTime(),
lastAccessTime: j_props.lastAccessTime().getTime(),
lastModifiedTime: j_props.lastModifiedTime().getTime(),
isDirectory: j_props.isDirectory(),
isOther: j_props.isOther(),
isRegularFile: j_props.isRegularFile(),
isSymbolicLink: j_props.isSymbolicLink(),
size: j_props.size()
};
}
/**
* Copy a file, asynchronously. The copy will fail if <code>from</code>
* does not exist, or if <code>to</code> already exists.
*
* @param {string} from path of file to copy
* @param {string} to path of file to copy to
* @param {boolean} [recursive] copy recursively (default is false)
* @param {ResultHandler} handler the handler which is called on completion.
* @returns {module:vertx/file_system}
*/
fileSystem.copy = function(from, to, arg2, arg3) {
var handler;
var recursive;
if (arguments.length === 4) {
handler = arg3;
recursive = arg2;
} else {
handler = arg2;
recursive = false;
}
jfs.copy(from, to, recursive, wrapHandler(handler));
return fileSystem;
};
/**
* Synchronous version of copy
*
* @param {string} from the path of the file to copy
* @param {string} to the path to copy the file to
* @param {boolean} recursive copy recursively (default is false)
* @returns {module:vertx/file_system}
*/
fileSystem.copySync = function(from, to, recursive) {
if (!recursive) recursive = false;
jfs.copySync(from, to, recursive);
return fileSystem;
};
/**
* Move a file, asynchronously. The move will fail if <code>from</code>
* does not exist, or if <code>to</code> already exists.
*
* @param {string} from the path of file to move
* @param {string} to the path to move the file to
* @param {ResultHandler} handler the function to call when complete
* @returns {module:vertx/file_system}
*/
fileSystem.move = function(from, to, handler) {
jfs.move(from, to, wrapHandler(handler));
return fileSystem;
};
/**
* Synchronous version of move.
*
* @param {string} from the path of file to move
* @param {string} to the path to move the file to
* @returns {module:vertx/file_system}
*/
fileSystem.moveSync = function(from, to) {
jfs.moveSync(from, to);
return fileSystem;
};
/**
* Truncate a file, asynchronously. The move will fail if path does not exist.
*
* @param {string} path Path of file to truncate
* @param {number} len Length to truncate file to. Will fail if len < 0. If len > file size then will do nothing.
* @param {ResultHandler} handler the function to call when complete
* @returns {module:vertx/file_system}
*/
fileSystem.truncate = function(path, len, handler) {
jfs.truncate(path, len, wrapHandler(handler));
return fileSystem;
};
/**
* Synchronous version of truncate.
*
* @param {string} path Path of file to truncate
* @param {number} len Length to truncate file to. Will fail if len < 0. If len > file size then will do nothing.
* @returns {module:vertx/file_system}
*/
fileSystem.truncateSync = function(path, len) {
jfs.truncateSync(path, len);
return fileSystem;
};
/**
* Change the permissions on a file, asynchronously. If the file is directory
* then all contents will also have their permissions changed recursively.
*
* @param {string} path path of file to change permissions
* @param {string} perms a permission string of the form rwxr-x--- as specified
* in http://download.oracle.com/javase/7/docs/api/java/nio/file/attribute/PosixFilePermissions.html.
* This is used to set the permissions for any regular files (not directories).
* @param {string} [dir_perms] similar to <code>perms</code> above, but refers only to directories.
* @param {ResultHandler} handler The handler to call when the operation has completed
*
* @returns {module:vertx/file_system}
*/
fileSystem.chmod = function(path, perms, arg2, arg3) {
var handler;
var dirPerms;
if (arguments.length === 4) {
handler = arg3;
dirPerms = arg2;
} else {
handler = arg2;
dirPerms = null;
}
jfs.chmod(path, perms, dirPerms, wrapHandler(handler));
return fileSystem;
};
/**
* Synchronous version of chmod.
*
* @param {string} path path of file to change permissions
* @param {string} perms a permission string of the form rwxr-x--- as specified
* in http://download.oracle.com/javase/7/docs/api/java/nio/file/attribute/PosixFilePermissions.html.
* This is used to set the permissions for any regular files (not directories).
* @param {string} [dir_perms] similar to <code>perms</code> above, but refers only to directories.
* @returns {module:vertx/file_system}
*/
fileSystem.chmodSync = function(path, perms, dirPerms) {
if (!dirPerms) dirPerms = null;
jfs.chmodSync(path, perms, dirPerms);
return fileSystem;
};
/**
* Change the ownership on the file represented by {@code path} to {@code user} and {code group}, asynchronously
*
* @param {string} path path of file to change permissions
* @param {string} user the username
* @param {string} [group] the groupname
* @param {ResultHandler} handler The handler to call when the operation has completed
*
* @returns {module:vertx/file_system}
*/
fileSystem.chown = function(path, user, arg1, arg2) {
var handler;
var group;
if (arguments.length === 4) {
handler = arg2;
group = arg1;
} else {
handler = arg1;
group = null;
}
jfs.chown(path, user, group, wrapHandler(handler));
return fileSystem;
};
/**
* Synchronous version of chown
*
* @param {string} path path of file to change permissions
* @param {string} user the username
* @param {string} [group] the groupname
*
* @returns {module:vertx/file_system}
*/
fileSystem.chownSync = function(path, user, group) {
if (!group) group = null;
jfs.chownSync(path, user, group);
return fileSystem;
};
/**
* Get file properties for a file, asynchronously.
*
* @param {string} path path to file
* @param {ResultHandler} handler the function to call when complete
* @returns {module:vertx/file_system}
*/
fileSystem.props = function(path, handler) {
jfs.props(path, propsHandler(handler));
return fileSystem;
};
/**
* Synchronous version of props.
* @param {string} path path to file
* @returns {FileProps}
*/
fileSystem.propsSync = function(path) {
var j_props = jfs.propsSync(path);
return convertProps(j_props);
};
/**
* Obtain properties for the link represented by <code>path</code>, asynchronously.
* The link will not be followed.
*
* @param {string} path path to file
* @param {ResultHandler} handler the function to call when complete
* @returns {module:vertx/file_system}
*/
fileSystem.lprops = function(path, handler) {
jfs.lprops(path, propsHandler(handler));
return fileSystem;
};
/**
* Synchronous version of lprops.
*
* @param {string} path path to file
* @returns {FileProps}
*/
fileSystem.lpropsSync = function(path) {
var j_props = jfs.lpropsSync(path);
return convertProps(j_props);
};
/**
* Create a hard link, asynchronously.
*
* @param {string} link path of the link to create.
* @param {string} existing path of where the link points to.
* @param {ResultHandler} handler the function to call when complete
* @returns {module:vertx/file_system}
*/
fileSystem.link = function(link, existing, handler) {
jfs.link(link, existing, wrapHandler(handler));
return fileSystem;
};
/**
* Synchronous version of link.
* @param {string} link path of the link to create.
* @param {string} existing path of where the link points to.
* @returns {module:vertx/file_system}
*/
fileSystem.linkSync = function(link, existing) {
jfs.linkSync(link, existing);
return fileSystem;
};
/**
* Create a symbolic link, asynchronously.
*
* @param {string} link Path of the link to create.
* @param {string} existing Path of where the link points to.
* @param {ResultHandler} handler the function to call when complete
* @returns {module:vertx/file_system}
*/
fileSystem.symlink = function(link, existing, handler) {
jfs.symlink(link, existing, wrapHandler(handler));
return fileSystem;
};
/**
* Synchronous version of symlink.
* @param {string} link Path of the link to create.
* @param {string} existing Path of where the link points to.
* @returns {module:vertx/file_system}
*/
fileSystem.symlinkSync = function(link, existing) {
jfs.symlinkSync(link, existing);
return fileSystem;
};
/**
* Unlink a hard link.
*
* @param {string} link path of the link to unlink.
* @param {ResultHandler} handler the handler to notify on completion.
* @returns {module:vertx/file_system}
*/
fileSystem.unlink = function(link, handler) {
jfs.unlink(link, wrapHandler(handler));
return fileSystem;
};
/**
* Synchronous version of unlink.
*
* @param {string} link path of the link to unlink.
* @returns {module:vertx/file_system}
*/
fileSystem.unlinkSync = function(link) {
jfs.unlinkSync(link);
return fileSystem;
};
/**
* Read a symbolic link, asynchronously. I.e. tells you where the symbolic link points.
*
* @param {string} link path of the link to read.
* @param {ResultHandler} handler the function to call when complete, the function will be
* called with a string representing the path of the file that the <code>link</code>
* symlink is linked to.
* @returns {module:vertx/file_system}
*/
fileSystem.readSymlink = function(link, handler) {
jfs.readSymlink(link, wrapHandler(handler));
return fileSystem;
};
/**
* Synchronous version of readSymlink.
*
* @param {string} link path of the link to read.
* @returns {string} the path of the file that the <code>link</code> symlink is linked to.
*/
fileSystem.readSymlinkSync = function(link) {
return jfs.readSymlinkSync(link);
};
/**
* Delete a file on the file system, asynchronously.
* The delete will fail if the file does not exist, or is a directory and is not empty.
*
* @param {string} path path of the file to delete.
* @param {boolean} [recursive] recurse into subdirectories (default: false)
* @param {ResultHandler} handler The handler to call when complete
* @returns {module:vertx/file_system}
*/
fileSystem.delete = function(path, arg1, arg2) {
var handler;
var recursive;
if (arguments.length === 3) {
handler = arg2;
recursive = arg1;
} else {
handler = arg1;
recursive = false;
}
jfs.delete(path, recursive, wrapHandler(handler));
return fileSystem;
};
/**
* Synchronous version of delete.
*
* @param {string} path path of the file to delete.
* @param {boolean} [recursive] recurse into subdirectories (default: false)
* @returns {module:vertx/file_system}
*/
fileSystem.deleteSync = function(path, recursive) {
if (!recursive) recursive = false;
jfs.deleteSync(path, recursive);
return fileSystem;
};
/**
* Create a directory, asynchronously. The create will fail if the directory
* already exists, or if it contains parent directories which do not already
* exist.
*
* @param {string} path path of the directory to create.
* @param {boolean} [createParents] create parent directories if necesssary (default is false)
* @param {string} [permString] the permissions of the directory being created
* @param {ResultHandler} handler the function to call when complete
* @returns {module:vertx/file_system}
*/
fileSystem.mkDir = function(path, arg1, arg2, arg3) {
var createParents;
var perms;
var handler;
switch (arguments.length) {
case 2:
createParents = false;
perms = null;
handler = arg1;
break;
case 3:
if (typeof(arg1) === 'boolean') {
createParents = arg1;
perms=null;
} else {
createParents = false;
perms = arg1;
}
handler = arg2;
break;
case 4:
createParents = arg1;
perms = arg2;
handler = arg3;
break;
default:
throw 'Invalid number of arguments';
}
jfs.mkdir(path, perms, createParents, wrapHandler(handler));
return fileSystem;
};
/**
* Synchronous version of mkdir.
*
* @param {string} path path of the directory to create.
* @param {boolean} [createParents] create parent directories if necesssary (default is false)
* @param {string} [permString] the permissions of the directory being created
* @returns {module:vertx/file_system}
*/
fileSystem.mkDirSync = function(path, arg1, arg2) {
var createParents;
var perms;
switch (arguments.length) {
case 1:
createParents = false;
perms = null;
break;
case 2:
createParents = arg1;
perms = null;
break;
case 3:
createParents = arg1;
perms = arg2;
break;
default:
throw 'Invalid number of arguments';
}
jfs.mkdirSync(path, perms, createParents);
return fileSystem;
};
/**
* Read a directory, i.e. list it's contents, asynchronously.
* The read will fail if the directory does not exist.
*
* @param {string} path path of the directory to read.
* @param {string} [filter] a regular expression. If supplied, only paths that match
* <code>filter</code> will be passed to the <code>handler</code>.
* @param {ResultHandler} handler the handler to call when complete. The handler will be
* passed an array of strings each representing a matched path name.
* @returns {module:vertx/file_system}
*/
fileSystem.readDir = function(path, arg1, arg2) {
var filter;
var handler;
if (arguments.length === 3) {
handler = arg2;
filter = arg1;
} else {
handler = arg1;
filter = null;
}
jfs.readDir(path, filter, arrayResultHandler(handler));
return fileSystem;
};
/**
* Synchronous version of readDir.
*
* @param {string} path path of the directory to read.
* @param {string} [filter] a regular expression. If supplied, only paths that match
* <code>filter</code> will be passed to the <code>handler</code>.
* @returns {Array} an array of strings, each representing a matched path name.
*/
fileSystem.readDirSync = function(path, filter) {
if (!filter) filter = null;
var result = jfs.readDirSync(path, filter);
var arry = [];
for (var i=0; i<result.length; i++) {
arry.push(result[i]);
}
return arry;
};
/**
* Read the contents of the entire file.
*
* @param {string} path path of the file to read.
* @param {ResultHandler} handler the function to call when complete. The handler function
* will receive a Buffer containing the contents of the file.
* @returns {module:vertx/file_system}
*/
fileSystem.readFile = function(path, handler) {
jfs.readFile(path, wrapHandler(handler));
return fileSystem;
};
/**
* Synchronous version of readFile.
*
* @param {string} path path of the file to read.
* @returns {Buffer} a Buffer containing the contents of the file.
*/
fileSystem.readFileSync = function(path) {
return jfs.readFileSync(path);
};
/**
* Write data to a file
*
* @param {string} path path of the file to write.
* @param {string|Buffer} data the data to write
* @param {ResultHandler} handler the function to call when complete
* @returns {module:vertx/file_system}
*/
fileSystem.writeFile = function(path, data, handler) {
if (typeof data === 'string') {
data = new org.vertx.java.core.buffer.Buffer(data);
} else {
data = data._to_java_buffer();
}
jfs.writeFile(path, data, wrapHandler(handler));
return fileSystem;
};
/**
* Synchronous version of writeFile.
*
* @param {string} path path of the file to write.
* @param {string|Buffer} data the data to write
* @returns {module:vertx/file_system}
*/
fileSystem.writeFileSync = function(path, data) {
if (typeof data === 'string') {
data = new org.vertx.java.core.buffer.Buffer(data);
}
jfs.writeFileSync(path, data);
return fileSystem;
};
/**
* Flags used when opening files working with the vert.x
* {@linkcode module:vertx/file_system|FileSystem}
* @typedef {number} Flag
* */
/** @property {Flag} OPEN_READ Open file for reading flag. */
fileSystem.OPEN_READ = 1;
/** @property {Flag} OPEN_WRITE Open file for writing flag. */
fileSystem.OPEN_WRITE = 2;
/** @property {Flag} CREATE_NEW Create new file flag. */
fileSystem.CREATE_NEW = 4;
function mapOpenArgs(args) {
var flags = fileSystem.OPEN_READ |
fileSystem.OPEN_WRITE |
fileSystem.CREATE_NEW;
var map = {
perms: null,
flush: false,
read: true,
write: true,
createNew: true,
};
switch (args.length) {
case 0:
break;
case 1:
flags = args[0];
break;
case 2:
flags = args[0];
map.flush = args[1];
break;
case 3:
flags = args[0];
map.flush = args[1];
map.perms = args[2];
break;
default:
throw 'Invalid number of arguments';
}
map.read = (flags & fileSystem.OPEN_READ) == fileSystem.OPEN_READ;
map.write = (flags & fileSystem.OPEN_WRITE) == fileSystem.OPEN_WRITE;
map.createNew = (flags & fileSystem.CREATE_NEW) == fileSystem.CREATE_NEW;
return map;
}
/**
* Synchronous version of open.
*
* @param {string} path the path of the file to open
* @param {Flag} [openFlags] an integer representing whether to open the file for
* reading, writing, creation, or some combination of these with bitwise or
* (e.g. <code>fileSystem.OPEN_READ | fileSystem.OPEN_WRITE</code>). If not
* specified the file will be opened for reading, wrting, and creation.
* @param {boolean} [flush] flush file writes immediately (default is false)
* @param {string} [permissions] the permissions to create the file with if the
* file is created when opened.
* @returns {module:vertx/file_system.AsyncFile}
*/
fileSystem.openSync = function(path) {
var rest = Array.prototype.slice.call(arguments, 1);
var opts = mapOpenArgs(rest);
return new fileSystem.AsyncFile(
jfs.openSync(path, opts.perms, opts.read, opts.write,
opts.createNew, opts.flush));
};
/**
* Open a file on the file system, asynchronously.
*
* @param {string} path the path of the file to open
* @param {Flag} [openFlags] an integer representing whether to open the file for
* reading, writing, creation, or some combination of these with bitwise or
* (e.g. <code>fileSystem.OPEN_READ | fileSystem.OPEN_WRITE</code>). If not
* specified the file will be opened for reading, wrting, and creation.
* @param {boolean} [flush] flush file writes immediately (default is false)
* @param {string} [permissions] the permissions to create the file with if the
* file is created when opened.
* @param {ResultHandler} handler the function to be called when the file is opened. The
* handler will receieve an AsyncFile as a parameter when called.
* @returns {module:vertx/file_system}
*/
fileSystem.open = function(path) {
var rest = Array.prototype.slice.call(arguments, 1);
var handler = asyncFileHandler(rest.pop());
var opts = mapOpenArgs(rest);
jfs.open(path, opts.perms, opts.read, opts.write,
opts.createNew, opts.flush, handler);
return fileSystem;
};
/**
* <p>
* An <code>AsyncFile</code> represents a file on the file-system which can be
* read from, or written to asynchronously. Methods also exist to get a
* <code>ReadStream</code> or a <code>WriteStream</code> on the file. This
* allows the data to be pumped to and from other streams. Instances of this
* class are not thread-safe
* </p>
* <p>
* These should not be created directly. Rather they are created internally
* by vert.x and provided to callback handlers and as return values from
* synchronous functions.
* </p>
* @constructor
* @param {org.vertx.java.core.file.AsyncFile} asyncFile the underlying java representation of this AsyncFile
* @augments module:vertx/streams~ReadStream
* @augments module:vertx/streams~WriteStream
*/
fileSystem.AsyncFile = function(jaf) {
var that = this;
streams.WriteStream.call(this, jaf);
streams.ReadStream.call(this, jaf);
/**
* Close the file asynchronously
* @param {ResultHandler} handler the handler to be called when the operation completes
*/
this.close = function(handler) {
if (handler) {
jaf.close(wrapHandler(handler));
} else {
jaf.close();
}
};
/**
* Write to the file asynchronously
* @param {Buffer|string} buffer the data to write
* @param {number} position the byte position from which to start writing
* @param {ResultHandler} handler the handler to call when the write has completed
* @returns {module:vertx/file_system}
*/
this.write = function(buffer, position, handler) {
if (buffer && typeof buffer === 'string') {
buffer = new Buffer(buffer);
}
if (position === null || position === undefined) {
// WriteStream interface
jaf.write(buffer._to_java_buffer());
} else {
// AsyncFile interface
jaf.write(buffer._to_java_buffer(), position, wrapHandler(handler));
}
return that;
};
/**
* Read from the file asynchronously
* @param {Buffer} buffer The buffer to fill with the contents of the file
* @param {number} offset The offset point in the Buffer from which to start writing
* @param {number} position The position in the file from which to begin reading
* @param {number} length the number of bytes to read
* @param {ResultHandler} handler the handler to call when close() has been completed and will
* be provided the filled Buffer as a parameter
*/
this.read = function(buffer, offset, position, length, handler) {
jaf.read(buffer._to_java_buffer(), offset, position, length, wrapHandler(handler));
return that;
};
/**
* Flush any writes made to this file to persistent storage.
* @param {ResultHandler} handler The handler to be called when the flush has completed
*/
this.flush = function(handler) {
if (handler) {
jaf.flush(wrapHandler(handler));
} else {
jaf.flush();
}
};
};
/**
* Create a new empty file, asynchronously.
*
* @param {string} path path of the file to create.
* @param {ResultHandler} handler the function to call when complete
* @returns {module:vertx/file_system}
*/
fileSystem.createFile = function(path, handler) {
jfs.createFile(path, wrapHandler(handler));
return fileSystem;
};
/**
* Synchronous version of createFile.
*
* @param {string} path path of the file to create.
* @returns {module:vertx/file_system}
*/
fileSystem.createFileSync = function(path) {
jfs.createFileSync(path);
return fileSystem;
};
/**
* Check if a file exists, asynchronously.
*
* @param {string} path Path of the file to check.
* @param {ResultHandler} handler the function to call when complete
* @returns {module:vertx/file_system}
*/
fileSystem.exists = function(path, handler) {
jfs.exists(path, wrapHandler(handler));
return fileSystem;
};
/**
* Synchronous version of exists.
*
* @param {string} path Path of the file to check.
* @returns {boolean} <code>true</code> if the file exists
*/
fileSystem.existsSync = function(path) {
return jfs.existsSync(path);
};
/**
* @typedef {{}} FileSystemProps
* @property {number} totalSpace The total space on the file system, in bytes
* @property {number} unallocatedSpace The total unallocated space on the file syste, in bytes
* @property {number} usableSpace The total usable space on the file system, in bytes
* */
/**
* Asynchronously get properties for the file system being used by the
* <code>path</code> specified.
*
* @param {string} path the path in the file system.
* @param {ResultHandler} handler the function to call with the FileSystemProps when complete
* @returns {module:vertx/file_system}
*/
fileSystem.fsProps = function(path, handler) {
jfs.fsProps(path, wrapHandler(handler));
return fileSystem;
};
/**
* Synchronous version of fsProps.
* @param {string} path Path in the file system.
* @returns {FileSystemProps}
*/
fileSystem.fsPropsSync = function(path) {
return jfs.fsPropsSync(path);
};
module.exports = fileSystem;