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 EPERM = 1; /* Operation not permitted */
var ENOENT = 2; /* No such file or directory */ var ENOENT = 2; /* No such file or directory */
var EEXIST = 17; /* File exists */
var EINVAL = 22; /* Invalid argument */ var EINVAL = 22; /* Invalid argument */
var EOPNOTSUPP = 95; /* Operation is not supported */ var EOPNOTSUPP = 95; /* Operation is not supported */
var ENOTEMPTY = 39; /* Directory not empty */ 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) 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 inode = this.CreateInode();
const idx = this.inodes.length; const idx = this.inodes.length;
@ -1578,9 +1576,10 @@ FS.prototype.follow_fs = function(inode)
}; };
/** /**
* Mount another filesystem onto an existing directory. * Mount another filesystem to given path.
* @param {string} path Path to existing directrory relative to this filesystem. * @param {string} path
* @param {FS} fs * @param {FS} fs
* @return {number} inode id of mount point if successful, or -errno if mounting failed.
*/ */
FS.prototype.Mount = function(path, fs) FS.prototype.Mount = function(path, fs)
{ {
@ -1589,23 +1588,30 @@ FS.prototype.Mount = function(path, fs)
const path_infos = this.SearchPath(path); 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); dbg_log("Mount failed: parent for path not found: " + path, LOG_9P);
return -1; 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) if(path_infos.forward_path)
{ {
const parent = this.inodes[path_infos.parentid]; const parent = this.inodes[path_infos.parentid];
this.follow_fs(parent).Mount(path_infos.forward_path, fs); const ret = this.follow_fs(parent).Mount(path_infos.forward_path, fs);
return; if(ret < 0) return ret;
return this.get_forwarder(parent.mount_id, ret);
} }
const mount_id = this.mounts.length; const mount_id = this.mounts.length;
this.mounts.push(new FSMountInfo(fs)); this.mounts.push(new FSMountInfo(fs));
// Existing inode is already linked. Just set forwarding information. const idx = this.create_forwarder(mount_id, 0);
this.set_forwarder(path_infos.id, 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; return;
} }
if(idx === -1) if(idx === -ENOENT)
{ {
callback(new FileNotFoundError()); callback(new FileNotFoundError());
} }
if(idx === -EEXIST)
{
callback(new FileExistsError());
}
if(idx < 0)
{
callback(new Error("Failed to mount. Error number: " + (-idx)));
}
else else
{ {
callback(null); 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 * @ignore
* @constructor * @constructor

View file

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