Mount only onto non-existent paths, existent parent

If mountpoint already exists, then we're silently making its children
inaccessible which may not be what we expected/intended.

Create a new forwarder inode upon mounting.
This commit is contained in:
Ernest Wong 2018-08-14 12:55:06 +12:00 committed by Fabian
parent 3fe75a9130
commit e683e812fd
4 changed files with 41 additions and 13 deletions

View file

@ -18,6 +18,7 @@ const VIRTIO_9P_MAX_TAGLEN = 254;
var EPERM = 1; /* Operation not permitted */
var ENOENT = 2; /* No such file or directory */
var EEXIST = 17; /* File exists */
var EINVAL = 22; /* Invalid argument */
var EOPNOTSUPP = 95; /* Operation is not supported */
var ENOTEMPTY = 39; /* Directory not empty */

View file

@ -1489,8 +1489,6 @@ FS.prototype.set_forwarder = function(idx, mount_id, foreign_id)
*/
FS.prototype.create_forwarder = function(mount_id, foreign_id)
{
dbg_assert(foreign_id !== 0, "Filesystem: root forwarder should not be created.");
const inode = this.CreateInode();
const idx = this.inodes.length;
@ -1578,9 +1576,10 @@ FS.prototype.follow_fs = function(inode)
};
/**
* Mount another filesystem onto an existing directory.
* @param {string} path Path to existing directrory relative to this filesystem.
* Mount another filesystem to given path.
* @param {string} path
* @param {FS} fs
* @return {number} inode id of mount point if successful, or -errno if mounting failed.
*/
FS.prototype.Mount = function(path, fs)
{
@ -1589,23 +1588,30 @@ FS.prototype.Mount = function(path, fs)
const path_infos = this.SearchPath(path);
if(path_infos.id === -1)
if(path_infos.parentid === -1)
{
dbg_log("Mount failed: path not found: " + path, LOG_9P);
return -1;
dbg_log("Mount failed: parent for path not found: " + path, LOG_9P);
return -ENOENT;
}
if(path_infos.id !== -1)
{
dbg_log("Mount failed: file already exists at path: " + path, LOG_9P);
return -EEXIST;
}
if(path_infos.forward_path)
{
const parent = this.inodes[path_infos.parentid];
this.follow_fs(parent).Mount(path_infos.forward_path, fs);
return;
const ret = this.follow_fs(parent).Mount(path_infos.forward_path, fs);
if(ret < 0) return ret;
return this.get_forwarder(parent.mount_id, ret);
}
const mount_id = this.mounts.length;
this.mounts.push(new FSMountInfo(fs));
// Existing inode is already linked. Just set forwarding information.
this.set_forwarder(path_infos.id, mount_id, 0);
const idx = this.create_forwarder(mount_id, 0);
this.inodes[idx].name = path_infos.name;
this.link_under_dir(idx, path_infos.parentid);
return path_infos.id;
return idx;
};

View file

@ -1089,10 +1089,18 @@ V86Starter.prototype.mount_fs = function(path, baseurl, basefs, callback)
{
return;
}
if(idx === -1)
if(idx === -ENOENT)
{
callback(new FileNotFoundError());
}
if(idx === -EEXIST)
{
callback(new FileExistsError());
}
if(idx < 0)
{
callback(new Error("Failed to mount. Error number: " + (-idx)));
}
else
{
callback(null);
@ -1204,6 +1212,18 @@ V86Starter.prototype.read_file = function(file, callback)
}
};
/**
* @ignore
* @constructor
*
* @param {string=} message
*/
function FileExistsError(message)
{
this.message = message || "File already exists";
}
FileNotFoundError.prototype = Error.prototype;
/**
* @ignore
* @constructor

View file

@ -1337,6 +1337,7 @@ function do_mounts()
{
const path = tests[test_num].mounts[mount_num].path;
emulator.serial0_send("mkdir -p /mnt" + path + "\n");
emulator.serial0_send("rmdir /mnt" + path + "\n");
emulator.serial0_send("echo done-premount\n");
next_trigger = "done-premount";
next_trigger_handler = () => mount(mount_num);