blob: 3abe6e1d03462ce0a58d87d2af9ab1a6cd295fcc [file] [log] [blame]
var common = require('./common');
var fs = require('fs');
// Recursively removes 'dir'
// Adapted from https://github.com/ryanmcgrath/wrench-js
//
// Copyright (c) 2010 Ryan McGrath
// Copyright (c) 2012 Artur Adib
//
// Licensed under the MIT License
// http://www.opensource.org/licenses/mit-license.php
function rmdirSyncRecursive(dir, force) {
var files;
files = fs.readdirSync(dir);
// Loop through and delete everything in the sub-tree after checking it
for(var i = 0; i < files.length; i++) {
var file = dir + "/" + files[i],
currFile = fs.lstatSync(file);
if(currFile.isDirectory()) { // Recursive function back to the beginning
rmdirSyncRecursive(file, force);
}
else if(currFile.isSymbolicLink()) { // Unlink symlinks
if (force || isWriteable(file)) {
try {
common.unlinkSync(file);
} catch (e) {
common.error('could not remove file (code '+e.code+'): ' + file, true);
}
}
}
else // Assume it's a file - perhaps a try/catch belongs here?
if (force || isWriteable(file)) {
try {
common.unlinkSync(file);
} catch (e) {
common.error('could not remove file (code '+e.code+'): ' + file, true);
}
}
}
// Now that we know everything in the sub-tree has been deleted, we can delete the main directory.
// Huzzah for the shopkeep.
var result;
try {
result = fs.rmdirSync(dir);
} catch(e) {
common.error('could not remove directory (code '+e.code+'): ' + dir, true);
}
return result;
} // rmdirSyncRecursive
// Hack to determine if file has write permissions for current user
// Avoids having to check user, group, etc, but it's probably slow
function isWriteable(file) {
var writePermission = true;
try {
var __fd = fs.openSync(file, 'a');
fs.closeSync(__fd);
} catch(e) {
writePermission = false;
}
return writePermission;
}
//@
//@ ### rm([options ,] file [, file ...])
//@ ### rm([options ,] file_array)
//@ Available options:
//@
//@ + `-f`: force
//@ + `-r, -R`: recursive
//@
//@ Examples:
//@
//@ ```javascript
//@ rm('-rf', '/tmp/*');
//@ rm('some_file.txt', 'another_file.txt');
//@ rm(['some_file.txt', 'another_file.txt']); // same as above
//@ ```
//@
//@ Removes files. The wildcard `*` is accepted.
function _rm(options, files) {
options = common.parseOptions(options, {
'f': 'force',
'r': 'recursive',
'R': 'recursive'
});
if (!files)
common.error('no paths given');
if (typeof files === 'string')
files = [].slice.call(arguments, 1);
// if it's array leave it as it is
files = common.expand(files);
files.forEach(function(file) {
if (!fs.existsSync(file)) {
// Path does not exist, no force flag given
if (!options.force)
common.error('no such file or directory: '+file, true);
return; // skip file
}
// If here, path exists
var stats = fs.lstatSync(file);
if (stats.isFile() || stats.isSymbolicLink()) {
// Do not check for file writing permissions
if (options.force) {
common.unlinkSync(file);
return;
}
if (isWriteable(file))
common.unlinkSync(file);
else
common.error('permission denied: '+file, true);
return;
} // simple file
// Path is an existing directory, but no -r flag given
if (stats.isDirectory() && !options.recursive) {
common.error('path is a directory', true);
return; // skip path
}
// Recursively remove existing directory
if (stats.isDirectory() && options.recursive) {
rmdirSyncRecursive(file, options.force);
}
}); // forEach(file)
} // rm
module.exports = _rm;