From d28100c422d44dcda842b4cdb106614ca0df2d87 Mon Sep 17 00:00:00 2001 From: gideonthomas Date: Wed, 15 Oct 2014 22:04:03 -0400 Subject: [PATCH] Fix #308 - fs.rename does not work on directories --- src/filesystem/implementation.js | 95 +++++++++++++++++++++++++++- tests/spec/fs.rename.spec.js | 104 +++++++++++++++++++++++++++++++ 2 files changed, 197 insertions(+), 2 deletions(-) diff --git a/src/filesystem/implementation.js b/src/filesystem/implementation.js index 6d9c183..5bed6e5 100644 --- a/src/filesystem/implementation.js +++ b/src/filesystem/implementation.js @@ -1974,7 +1974,88 @@ function rename(fs, context, oldpath, newpath, callback) { if(!pathCheck(oldpath, callback)) return; if(!pathCheck(newpath, callback)) return; - function unlink_old_node(error) { + 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; + + function update_times(error, newNode) { + if(error) { + callback(error); + } else { + update_node_times(context, newpath, newNode, { ctime: Date.now() }, callback); + } + } + + function read_new_directory(error) { + if(error) { + callback(error); + } else { + context.getObject(newParentData[newName].id, update_times); + } + } + + function update_old_parent_directory_data(error) { + if(error) { + callback(error); + } else { + 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; + if(_(newParentData).has(newName)) { + 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) { if(error) { callback(error); } else { @@ -1982,7 +2063,17 @@ function rename(fs, context, oldpath, newpath, callback) { } } - link_node(context, oldpath, newpath, unlink_old_node); + function check_node_type(error, node) { + if(error) { + callback(error); + } else if(node.mode === 'DIRECTORY') { + find_node(context, oldParentPath, read_parent_directory_data); + } else { + link_node(context, oldpath, newpath, unlink_old_file); + } + } + + find_node(context, oldpath, check_node_type); } function symlink(fs, context, srcpath, dstpath, type, callback) { diff --git a/tests/spec/fs.rename.spec.js b/tests/spec/fs.rename.spec.js index 73bdac5..dcbd131 100644 --- a/tests/spec/fs.rename.spec.js +++ b/tests/spec/fs.rename.spec.js @@ -47,4 +47,108 @@ describe('fs.rename', function() { }); }); }); + + it('should rename an existing directory', function(done) { + var fs = util.fs(); + + fs.mkdir('/mydir', function(error) { + if(error) throw error; + + fs.rename('/mydir', '/myotherdir', function(error) { + expect(error).not.to.exist; + fs.stat('/mydir', function(error) { + expect(error).to.exist; + expect(error.code).to.equal('ENOENT'); + + fs.stat('/myotherdir', function(error, result) { + expect(error).not.to.exist; + expect(result.nlinks).to.equal(1); + done(); + }); + }); + }); + }); + }); + + it('should rename an existing directory if the new path points to an existing directory', function(done) { + var fs = util.fs(); + + fs.mkdir('/mydir', function(error) { + if(error) throw error; + + fs.mkdir('/myotherdir', function(error) { + if(error) throw error; + + fs.rename('/mydir', '/myotherdir', function(error) { + expect(error).not.to.exist; + fs.stat('/mydir', function(error) { + expect(error).to.exist; + expect(error.code).to.equal('ENOENT'); + + fs.stat('/myotherdir', function(error, result) { + expect(error).not.to.exist; + expect(result.nlinks).to.equal(1); + done(); + }); + }); + }); + }); + }); + }); + + it('should fail to rename an existing directory if the new path points to an existing directory that is not empty', function(done) { + var fs = util.fs(); + + fs.mkdir('/mydir', function(error) { + if(error) throw error; + + fs.mkdir('/myotherdir', function(error) { + if(error) throw error; + + fs.writeFile('/myotherdir/myfile', 'This is a file', function(error) { + if(error) throw error; + + fs.rename('/mydir', '/myotherdir', function(error) { + expect(error).to.exist; + expect(error.code).to.equal('ENOTEMPTY'); + + fs.stat('/mydir', function(error) { + expect(error).not.to.exist; + + fs.stat('/myotherdir', function(error) { + expect(error).not.to.exist; + done(); + }); + }); + }); + }); + }); + }); + }); + + it('should fail to rename an existing directory if the new path points to an existing file', function(done) { + var fs = util.fs(); + + fs.mkdir('/mydir', function(error) { + if(error) throw error; + + fs.writeFile('/myfile', 'This is a file', function(error) { + if(error) throw error; + + fs.rename('/mydir', '/myfile', function(error) { + expect(error).to.exist; + expect(error.code).to.equal('ENOTDIR'); + + fs.stat('/mydir', function(error) { + expect(error).not.to.exist; + + fs.stat('/myfile', function(error) { + expect(error).not.to.exist; + done(); + }); + }); + }); + }); + }); + }); });