Backport filesystem and 9p changes from jor1k. Thanks @s-macke

This commit is contained in:
copy 2016-01-04 04:16:00 +01:00
parent 9404fb29d5
commit b1d6fab094
6 changed files with 320 additions and 266 deletions

230
lib/9p.js
View file

@ -59,7 +59,7 @@ function Virtio9p(filesystem, bus) {
/** @const @type {BusConnector} */
this.bus = bus;
this.SendReply = function(x) {};
this.SendReply = function(x, y) {};
this.deviceid = 0x9; // 9p filesystem
this.hostfeature = 0x1; // mountpoint
//this.configspace = [0x0, 0x4, 0x68, 0x6F, 0x73, 0x74]; // length of string and "host" string
@ -106,17 +106,18 @@ Virtio9p.prototype.set_state = function(state)
};
Virtio9p.prototype.Createfid = function(inode, type, uid) {
return {inodeid: inode, type: type, uid: uid};
return {inodeid: inode, type: type, uid: uid};
}
Virtio9p.prototype.Reset = function() {
this.fids = [];
}
Virtio9p.prototype.BuildReply = function(id, tag, payloadsize) {
Marshall(["w", "b", "h"], [payloadsize+7, id+1, tag], this.replybuffer, 0);
marshall.Marshall(["w", "b", "h"], [payloadsize+7, id+1, tag], this.replybuffer, 0);
if ((payloadsize+7) >= this.replybuffer.length) {
DebugMessage("Error in 9p: payloadsize exceeds maximum length");
message.Debug("Error in 9p: payloadsize exceeds maximum length");
}
//for(var i=0; i<payload.length; i++)
// this.replybuffer[7+i] = payload[i];
@ -125,22 +126,22 @@ Virtio9p.prototype.BuildReply = function(id, tag, payloadsize) {
}
Virtio9p.prototype.SendError = function (tag, errormsg, errorcode) {
//var size = Marshall(["s", "w"], [errormsg, errorcode], this.replybuffer, 7);
var size = Marshall(["w"], [errorcode], this.replybuffer, 7);
//var size = marshall.Marshall(["s", "w"], [errormsg, errorcode], this.replybuffer, 7);
var size = marshall.Marshall(["w"], [errorcode], this.replybuffer, 7);
this.BuildReply(6, tag, size);
}
Virtio9p.prototype.ReceiveRequest = function (index, GetByte) {
var header = Unmarshall2(["w", "b", "h"], GetByte);
//var size = header[0];
var header = marshall.Unmarshall2(["w", "b", "h"], GetByte);
var size = header[0];
var id = header[1];
var tag = header[2];
//DebugMessage("size:" + size + " id:" + id + " tag:" + tag);
//message.Debug("size:" + size + " id:" + id + " tag:" + tag);
switch(id)
{
case 8: // statfs
var size = this.fs.GetTotalSize(); // size used by all files
size = this.fs.GetTotalSize(); // size used by all files
var space = this.fs.GetSpace();
var req = [];
req[0] = 0x01021997;
@ -153,43 +154,41 @@ Virtio9p.prototype.ReceiveRequest = function (index, GetByte) {
req[7] = 0; // file system id?
req[8] = 256; // maximum length of filenames
size = Marshall(["w", "w", "d", "d", "d", "d", "d", "d", "w"], req, this.replybuffer, 7);
size = marshall.Marshall(["w", "w", "d", "d", "d", "d", "d", "d", "w"], req, this.replybuffer, 7);
this.BuildReply(id, tag, size);
this.SendReply(index);
this.SendReply(0, index);
break;
case 112: // topen
case 12: // tlopen
var req = Unmarshall2(["w", "w"], GetByte);
var req = marshall.Unmarshall2(["w", "w"], GetByte);
var fid = req[0];
var mode = req[1];
DebugMessage("[open] fid=" + fid + ", mode=" + mode);
var inode = this.fs.GetInode(this.fids[fid].inodeid);
req[0] = inode.qid;
req[1] = this.msize - 24;
Marshall(["Q", "w"], req, this.replybuffer, 7);
this.BuildReply(id, tag, 13+4);
DebugMessage("file open " + inode.name);
message.Debug("[open] fid=" + fid + ", mode=" + mode);
var idx = this.fids[fid].inodeid;
var inode = this.fs.GetInode(idx);
message.Debug("file open " + inode.name);
//if (inode.status == STATUS_LOADING) return;
var ret = this.fs.OpenInode(this.fids[fid].inodeid, mode);
var ret = this.fs.OpenInode(idx, mode);
this.fs.AddEvent(this.fids[fid].inodeid,
function() {
DebugMessage("file opened " + inode.name + " tag:"+tag);
message.Debug("file opened " + inode.name + " tag:"+tag);
req[0] = inode.qid;
req[1] = this.msize - 24;
Marshall(["Q", "w"], req, this.replybuffer, 7);
marshall.Marshall(["Q", "w"], req, this.replybuffer, 7);
this.BuildReply(id, tag, 13+4);
this.SendReply(index);
this.SendReply(0, index);
}.bind(this)
);
break;
case 70: // link (just copying)
var req = Unmarshall2(["w", "w", "s"], GetByte);
var req = marshall.Unmarshall2(["w", "w", "s"], GetByte);
var dfid = req[0];
var fid = req[1];
var name = req[2];
DebugMessage("[link] dfid=" + dfid + ", name=" + name);
message.Debug("[link] dfid=" + dfid + ", name=" + name);
var inode = this.fs.CreateInode();
var inodetarget = this.fs.GetInode(this.fids[fid].inodeid);
var targetdata = this.fs.inodedata[this.fids[fid].inodeid];
@ -198,7 +197,6 @@ Virtio9p.prototype.ReceiveRequest = function (index, GetByte) {
inode.size = inodetarget.size;
inode.symlink = inodetarget.symlink;
var data = this.fs.inodedata[this.fs.inodes.length] = new Uint8Array(inode.size);
//inode.waswritten = true;
for(var i=0; i<inode.size; i++) {
data[i] = targetdata[i];
}
@ -210,81 +208,81 @@ Virtio9p.prototype.ReceiveRequest = function (index, GetByte) {
//inode.gid = inodetarget.gid;
//inode.mode = inodetarget.mode | S_IFLNK;
this.BuildReply(id, tag, 0);
this.SendReply(index);
this.SendReply(0, index);
break;
case 16: // symlink
var req = Unmarshall2(["w", "s", "s", "w"], GetByte);
var req = marshall.Unmarshall2(["w", "s", "s", "w"], GetByte);
var fid = req[0];
var name = req[1];
var symgt = req[2];
var gid = req[3];
DebugMessage("[symlink] fid=" + fid + ", name=" + name + ", symgt=" + symgt + ", gid=" + gid);
message.Debug("[symlink] fid=" + fid + ", name=" + name + ", symgt=" + symgt + ", gid=" + gid);
var idx = this.fs.CreateSymlink(name, this.fids[fid].inodeid, symgt);
var inode = this.fs.GetInode(idx);
inode.uid = this.fids[fid].uid;
inode.gid = gid;
Marshall(["Q"], [inode.qid], this.replybuffer, 7);
marshall.Marshall(["Q"], [inode.qid], this.replybuffer, 7);
this.BuildReply(id, tag, 13);
this.SendReply(index);
this.SendReply(0, index);
break;
case 18: // mknod
var req = Unmarshall2(["w", "s", "w", "w", "w", "w"], GetByte);
var req = marshall.Unmarshall2(["w", "s", "w", "w", "w", "w"], GetByte);
var fid = req[0];
var name = req[1];
var mode = req[2];
var major = req[3];
var minor = req[4];
var gid = req[5];
DebugMessage("[mknod] fid=" + fid + ", name=" + name + ", major=" + major + ", minor=" + minor+ "");
message.Debug("[mknod] fid=" + fid + ", name=" + name + ", major=" + major + ", minor=" + minor+ "");
var idx = this.fs.CreateNode(name, this.fids[fid].inodeid, major, minor);
var inode = this.fs.GetInode(idx);
inode.mode = mode;
inode.uid = this.fids[fid].uid;
inode.gid = gid;
Marshall(["Q"], [inode.qid], this.replybuffer, 7);
marshall.Marshall(["Q"], [inode.qid], this.replybuffer, 7);
this.BuildReply(id, tag, 13);
this.SendReply(index);
this.SendReply(0, index);
break;
case 22: // TREADLINK
var req = Unmarshall2(["w"], GetByte);
var req = marshall.Unmarshall2(["w"], GetByte);
var fid = req[0];
DebugMessage("[readlink] fid=" + fid);
message.Debug("[readlink] fid=" + fid);
var inode = this.fs.GetInode(this.fids[fid].inodeid);
var size = Marshall(["s"], [inode.symlink], this.replybuffer, 7);
size = marshall.Marshall(["s"], [inode.symlink], this.replybuffer, 7);
this.BuildReply(id, tag, size);
this.SendReply(index);
this.SendReply(0, index);
break;
case 72: // tmkdir
var req = Unmarshall2(["w", "s", "w", "w"], GetByte);
var req = marshall.Unmarshall2(["w", "s", "w", "w"], GetByte);
var fid = req[0];
var name = req[1];
var mode = req[2];
var gid = req[3];
DebugMessage("[mkdir] fid=" + fid + ", name=" + name + ", mode=" + mode + ", gid=" + gid);
message.Debug("[mkdir] fid=" + fid + ", name=" + name + ", mode=" + mode + ", gid=" + gid);
var idx = this.fs.CreateDirectory(name, this.fids[fid].inodeid);
var inode = this.fs.GetInode(idx);
inode.mode = mode | S_IFDIR;
inode.uid = this.fids[fid].uid;
inode.gid = gid;
Marshall(["Q"], [inode.qid], this.replybuffer, 7);
marshall.Marshall(["Q"], [inode.qid], this.replybuffer, 7);
this.BuildReply(id, tag, 13);
this.SendReply(index);
this.SendReply(0, index);
break;
case 14: // tlcreate
var req = Unmarshall2(["w", "s", "w", "w", "w"], GetByte);
var req = marshall.Unmarshall2(["w", "s", "w", "w", "w"], GetByte);
var fid = req[0];
var name = req[1];
var flags = req[2];
var mode = req[3];
var gid = req[4];
DebugMessage("[create] fid=" + fid + ", name=" + name + ", flags=" + flags + ", mode=" + mode + ", gid=" + gid);
message.Debug("[create] fid=" + fid + ", name=" + name + ", flags=" + flags + ", mode=" + mode + ", gid=" + gid);
var idx = this.fs.CreateFile(name, this.fids[fid].inodeid);
this.fids[fid].inodeid = idx;
this.fids[fid].type = FID_INODE;
@ -292,16 +290,16 @@ Virtio9p.prototype.ReceiveRequest = function (index, GetByte) {
inode.uid = this.fids[fid].uid;
inode.gid = gid;
inode.mode = mode;
Marshall(["Q", "w"], [inode.qid, this.msize - 24], this.replybuffer, 7);
marshall.Marshall(["Q", "w"], [inode.qid, this.msize - 24], this.replybuffer, 7);
this.BuildReply(id, tag, 13+4);
this.SendReply(index);
this.SendReply(0, index);
break;
case 52: // lock always suceed
DebugMessage("lock file\n");
Marshall(["w"], [0], this.replybuffer, 7);
message.Debug("lock file\n");
marshall.Marshall(["w"], [0], this.replybuffer, 7);
this.BuildReply(id, tag, 1);
this.SendReply(index);
this.SendReply(0, index);
break;
/*
@ -310,10 +308,10 @@ Virtio9p.prototype.ReceiveRequest = function (index, GetByte) {
*/
case 24: // getattr
var req = Unmarshall2(["w", "d"], GetByte);
var req = marshall.Unmarshall2(["w", "d"], GetByte);
var fid = req[0];
var inode = this.fs.GetInode(this.fids[fid].inodeid);
DebugMessage("[getattr]: fid=" + fid + " name=" + inode.name + " request mask=" + req[1]);
message.Debug("[getattr]: fid=" + fid + " name=" + inode.name + " request mask=" + req[1]);
req[0] |= 0x1000; // P9_STATS_GEN
req[0] = req[1]; // request mask
@ -338,7 +336,7 @@ Virtio9p.prototype.ReceiveRequest = function (index, GetByte) {
req[17] = 0x0;
req[18] = 0x0; // st_gen
req[19] = 0x0; // data_version
Marshall([
marshall.Marshall([
"d", "Q",
"w",
"w", "w",
@ -351,11 +349,11 @@ Virtio9p.prototype.ReceiveRequest = function (index, GetByte) {
"d", "d",
], req, this.replybuffer, 7);
this.BuildReply(id, tag, 8 + 13 + 4 + 4+ 4 + 8*15);
this.SendReply(index);
this.SendReply(0, index);
break;
case 26: // setattr
var req = Unmarshall2(["w", "w",
var req = marshall.Unmarshall2(["w", "w",
"w", // mode
"w", "w", // uid, gid
"d", // size
@ -364,7 +362,7 @@ Virtio9p.prototype.ReceiveRequest = function (index, GetByte) {
, GetByte);
var fid = req[0];
var inode = this.fs.GetInode(this.fids[fid].inodeid);
DebugMessage("[setattr]: fid=" + fid + " request mask=" + req[1] + " name=" +inode.name);
message.Debug("[setattr]: fid=" + fid + " request mask=" + req[1] + " name=" +inode.name);
if (req[1] & P9_SETATTR_MODE) {
inode.mode = req[2];
}
@ -393,38 +391,38 @@ Virtio9p.prototype.ReceiveRequest = function (index, GetByte) {
this.fs.ChangeSize(this.fids[fid].inodeid, req[5]);
}
this.BuildReply(id, tag, 0);
this.SendReply(index);
this.SendReply(0, index);
break;
case 50: // fsync
var req = Unmarshall2(["w", "d"], GetByte);
var req = marshall.Unmarshall2(["w", "d"], GetByte);
var fid = req[0];
this.BuildReply(id, tag, 0);
this.SendReply(index);
this.SendReply(0, index);
break;
case 40: // TREADDIR
case 116: // read
var req = Unmarshall2(["w", "d", "w"], GetByte);
var req = marshall.Unmarshall2(["w", "d", "w"], GetByte);
var fid = req[0];
var offset = req[1];
var count = req[2];
var inode = this.fs.GetInode(this.fids[fid].inodeid);
if (id == 40) DebugMessage("[treaddir]: fid=" + fid + " offset=" + offset + " count=" + count);
if (id == 116) DebugMessage("[read]: fid=" + fid + " (" + inode.name + ") offset=" + offset + " count=" + count + " fidtype=" + this.fids[fid].type);
if (id == 40) message.Debug("[treaddir]: fid=" + fid + " offset=" + offset + " count=" + count);
if (id == 116) message.Debug("[read]: fid=" + fid + " (" + inode.name + ") offset=" + offset + " count=" + count + " fidtype=" + this.fids[fid].type);
if (this.fids[fid].type == FID_XATTR) {
if (inode.caps.length < offset+count) count = inode.caps.length - offset;
for(var i=0; i<count; i++)
this.replybuffer[7+4+i] = inode.caps[offset+i];
Marshall(["w"], [count], this.replybuffer, 7);
marshall.Marshall(["w"], [count], this.replybuffer, 7);
this.BuildReply(id, tag, 4 + count);
this.SendReply(index);
this.SendReply(0, index);
} else {
var file = this.fs.inodes[this.fids[fid].inodeid];
this.bus.send("9p-read-start");
this.fs.OpenInode(this.fids[fid].inodeid, undefined);
this.fs.AddEvent(this.fids[fid].inodeid,
this.fs.AddEvent(this.fids[fid].inodeid,
function() {
this.bus.send("9p-read-end", [file.name, count]);
@ -434,167 +432,167 @@ Virtio9p.prototype.ReceiveRequest = function (index, GetByte) {
for(var i=0; i<count; i++)
this.replybuffer[7+4+i] = data[offset+i];
}
Marshall(["w"], [count], this.replybuffer, 7);
marshall.Marshall(["w"], [count], this.replybuffer, 7);
this.BuildReply(id, tag, 4 + count);
this.SendReply(index);
this.SendReply(0, index);
}.bind(this)
);
}
break;
case 118: // write
var req = Unmarshall2(["w", "d", "w"], GetByte);
var req = marshall.Unmarshall2(["w", "d", "w"], GetByte);
var fid = req[0];
var offset = req[1];
var count = req[2];
DebugMessage("[write]: fid=" + fid + " (" + this.fs.inodes[this.fids[fid].inodeid].name + ") offset=" + offset + " count=" + count);
message.Debug("[write]: fid=" + fid + " (" + this.fs.inodes[this.fids[fid].inodeid].name + ") offset=" + offset + " count=" + count);
this.fs.Write(this.fids[fid].inodeid, offset, count, GetByte);
var file = this.fs.inodes[this.fids[fid].inodeid];
this.bus.send("9p-write-end", [file.name, count]);
Marshall(["w"], [count], this.replybuffer, 7);
marshall.Marshall(["w"], [count], this.replybuffer, 7);
this.BuildReply(id, tag, 4);
this.SendReply(index);
this.SendReply(0, index);
break;
case 74: // RENAMEAT
var req = Unmarshall2(["w", "s", "w", "s"], GetByte);
var req = marshall.Unmarshall2(["w", "s", "w", "s"], GetByte);
var olddirfid = req[0];
var oldname = req[1];
var newdirfid = req[2];
var newname = req[3];
DebugMessage("[renameat]: oldname=" + oldname + " newname=" + newname);
message.Debug("[renameat]: oldname=" + oldname + " newname=" + newname);
var ret = this.fs.Rename(this.fids[olddirfid].inodeid, oldname, this.fids[newdirfid].inodeid, newname);
if (ret == false) {
this.SendError(tag, "No such file or directory", ENOENT);
this.SendReply(index);
this.SendReply(0, index);
break;
}
this.BuildReply(id, tag, 0);
this.SendReply(index);
this.SendReply(0, index);
break;
case 76: // TUNLINKAT
var req = Unmarshall2(["w", "s", "w"], GetByte);
var req = marshall.Unmarshall2(["w", "s", "w"], GetByte);
var dirfd = req[0];
var name = req[1];
var flags = req[2];
DebugMessage("[unlink]: dirfd=" + dirfd + " name=" + name + " flags=" + flags);
message.Debug("[unlink]: dirfd=" + dirfd + " name=" + name + " flags=" + flags);
var fid = this.fs.Search(this.fids[dirfd].inodeid, name);
if (fid == -1) {
this.SendError(tag, "No such file or directory", ENOENT);
this.SendReply(index);
this.SendReply(0, index);
break;
}
var ret = this.fs.Unlink(fid);
if (!ret) {
this.SendError(tag, "Directory not empty", ENOTEMPTY);
this.SendReply(index);
this.SendReply(0, index);
break;
}
this.BuildReply(fid, tag, 0);
this.SendReply(index);
this.BuildReply(id, tag, 0);
this.SendReply(0, index);
break;
case 100: // version
var version = Unmarshall2(["w", "s"], GetByte);
DebugMessage("[version]: msize=" + version[0] + " version=" + version[1]);
var version = marshall.Unmarshall2(["w", "s"], GetByte);
message.Debug("[version]: msize=" + version[0] + " version=" + version[1]);
this.msize = version[0];
var size = Marshall(["w", "s"], [this.msize, this.VERSION], this.replybuffer, 7);
size = marshall.Marshall(["w", "s"], [this.msize, this.VERSION], this.replybuffer, 7);
this.BuildReply(id, tag, size);
this.SendReply(index);
this.SendReply(0, index);
break;
case 104: // attach
// return root directorie's QID
var req = Unmarshall2(["w", "w", "s", "s", "w"], GetByte);
var req = marshall.Unmarshall2(["w", "w", "s", "s", "w"], GetByte);
var fid = req[0];
var uid = req[4];
DebugMessage("[attach]: fid=" + fid + " afid=" + hex8(req[1]) + " uname=" + req[2] + " aname=" + req[3]);
message.Debug("[attach]: fid=" + fid + " afid=" + hex8(req[1]) + " uname=" + req[2] + " aname=" + req[3]);
this.fids[fid] = this.Createfid(0, FID_INODE, uid);
var inode = this.fs.GetInode(this.fids[fid].inodeid);
Marshall(["Q"], [inode.qid], this.replybuffer, 7);
marshall.Marshall(["Q"], [inode.qid], this.replybuffer, 7);
this.BuildReply(id, tag, 13);
this.SendReply(index);
this.SendReply(0, index);
break;
case 108: // tflush
var req = Unmarshall2(["h"], GetByte);
var req = marshall.Unmarshall2(["h"], GetByte);
var oldtag = req[0];
DebugMessage("[flush] " + tag);
//Marshall(["Q"], [inode.qid], this.replybuffer, 7);
message.Debug("[flush] " + tag);
//marshall.Marshall(["Q"], [inode.qid], this.replybuffer, 7);
this.BuildReply(id, tag, 0);
this.SendReply(index);
this.SendReply(0, index);
break;
case 110: // walk
var req = Unmarshall2(["w", "w", "h"], GetByte);
var req = marshall.Unmarshall2(["w", "w", "h"], GetByte);
var fid = req[0];
var nwfid = req[1];
var nwname = req[2];
DebugMessage("[walk]: fid=" + req[0] + " nwfid=" + req[1] + " nwname=" + nwname);
message.Debug("[walk]: fid=" + req[0] + " nwfid=" + req[1] + " nwname=" + nwname);
if (nwname == 0) {
this.fids[nwfid] = this.Createfid(this.fids[fid].inodeid, FID_INODE, this.fids[fid].uid);
//this.fids[nwfid].inodeid = this.fids[fid].inodeid;
Marshall(["h"], [0], this.replybuffer, 7);
marshall.Marshall(["h"], [0], this.replybuffer, 7);
this.BuildReply(id, tag, 2);
this.SendReply(index);
this.SendReply(0, index);
break;
}
var wnames = [];
for(var i=0; i<nwname; i++) {
wnames.push("s");
}
var walk = Unmarshall2(wnames, GetByte);
var walk = marshall.Unmarshall2(wnames, GetByte);
var idx = this.fids[fid].inodeid;
var offset = 7+2;
var nwidx = 0;
//console.log(idx, this.fs.inodes[idx]);
DebugMessage("walk in dir " + this.fs.inodes[idx].name + " to: " + walk.toString());
message.Debug("walk in dir " + this.fs.inodes[idx].name + " to: " + walk.toString());
for(var i=0; i<nwname; i++) {
idx = this.fs.Search(idx, walk[i]);
if (idx == -1) {
DebugMessage("Could not find: " + walk[i]);
message.Debug("Could not find: " + walk[i]);
break;
}
offset += Marshall(["Q"], [this.fs.inodes[idx].qid], this.replybuffer, offset);
offset += marshall.Marshall(["Q"], [this.fs.inodes[idx].qid], this.replybuffer, offset);
nwidx++;
//DebugMessage(this.fids[nwfid].inodeid);
//message.Debug(this.fids[nwfid].inodeid);
//this.fids[nwfid].inodeid = idx;
//this.fids[nwfid].type = FID_INODE;
this.fids[nwfid] = this.Createfid(idx, FID_INODE, this.fids[fid].uid);
}
Marshall(["h"], [nwidx], this.replybuffer, 7);
marshall.Marshall(["h"], [nwidx], this.replybuffer, 7);
this.BuildReply(id, tag, offset-7);
this.SendReply(index);
this.SendReply(0, index);
break;
case 120: // clunk
var req = Unmarshall2(["w"], GetByte);
DebugMessage("[clunk]: fid=" + req[0]);
var req = marshall.Unmarshall2(["w"], GetByte);
message.Debug("[clunk]: fid=" + req[0]);
if (this.fids[req[0]] && this.fids[req[0]].inodeid >= 0) {
this.fs.CloseInode(this.fids[req[0]].inodeid);
this.fids[req[0]].inodeid = -1;
this.fids[req[0]].type = FID_NONE;
}
this.BuildReply(id, tag, 0);
this.SendReply(index);
this.SendReply(0, index);
break;
case 32:
this.SendError(tag, "Operation i not supported", ENOTSUPP);
this.SendReply(index);
this.SendReply(0, index);
break;
case 30: // xattrwalk
var req = Unmarshall2(["w", "w", "s"], GetByte);
var req = marshall.Unmarshall2(["w", "w", "s"], GetByte);
var fid = req[0];
var newfid = req[1];
var name = req[2];
DebugMessage("[xattrwalk]: fid=" + req[0] + " newfid=" + req[1] + " name=" + req[2]);
message.Debug("[xattrwalk]: fid=" + req[0] + " newfid=" + req[1] + " name=" + req[2]);
this.fids[newfid] = this.Createfid(this.fids[fid].inodeid, FID_NONE, this.fids[fid].uid);
//this.fids[newfid].inodeid = this.fids[fid].inodeid;
//this.fids[newfid].type = FID_NONE;
@ -603,16 +601,16 @@ Virtio9p.prototype.ReceiveRequest = function (index, GetByte) {
length = this.fs.PrepareCAPs(this.fids[fid].inodeid);
this.fids[newfid].type = FID_XATTR;
}
Marshall(["d"], [length], this.replybuffer, 7);
marshall.Marshall(["d"], [length], this.replybuffer, 7);
this.BuildReply(id, tag, 8);
this.SendReply(index);
this.SendReply(0, index);
break;
default:
DebugMessage("Error in Virtio9p: Unknown id " + id + " received");
abort();
message.Debug("Error in Virtio9p: Unknown id " + id + " received");
message.Abort();
//this.SendError(tag, "Operation i not supported", ENOTSUPP);
//this.SendReply(index);
//this.SendReply(0, index);
break;
}

View file

@ -84,25 +84,30 @@ function FS(baseurl) {
// -----------------------------------------------------
FS.prototype.AddEvent = function(id, OnEvent) {
var inode = this.inodes[id];
var inode = this.GetInode(id);
if (inode.status == STATUS_OK) {
OnEvent();
return;
}
this.events.push({id: id, OnEvent: OnEvent});
this.events.push({id: id, OnEvent: OnEvent});
}
FS.prototype.HandleEvent = function(id) {
if (this.filesinloadingqueue == 0) {
this.OnLoaded();
this.OnLoaded = function() {};
this.OnLoaded = function() {}
}
//DebugMessage("number of events: " + this.events.length);
for(var i = this.events.length - 1; i >= 0; i--) {
if (this.events[i].id != id) continue;
this.events[i].OnEvent();
this.events.splice(i, 1);
//message.Debug("number of events: " + this.events.length);
var newevents = [];
for(var i=0; i<this.events.length; i++) {
if (this.events[i].id == id) {
this.events[i].OnEvent();
} else {
newevents.push(this.events[i]);
}
}
this.events = newevents;
}
FS.prototype.OnJSONLoaded = function(fs)
@ -254,7 +259,6 @@ FS.prototype.PushInode = function(inode) {
if (inode.parentid != -1) {
this.inodes.push(inode);
inode.fid = this.inodes.length - 1;
var parent_node = this.inodes[inode.parentid];
parent_node.updatedir = true;
inode.nextid = parent_node.firstid;
@ -267,8 +271,9 @@ FS.prototype.PushInode = function(inode) {
}
}
DebugMessage("Error in Filesystem: Pushed inode with name = "+ inode.name + " has no parent");
abort();
message.Debug("Error in Filesystem: Pushed inode with name = "+ inode.name + " has no parent");
message.Abort();
}
/** @constructor */
@ -302,8 +307,6 @@ function Inode(qidnumber)
//this.qid_type = 0;
//this.qid_version = 0;
//this.qid_path = qidnumber;
//this.waswritten = false;
}
FS.prototype.CreateInode = function() {
@ -317,6 +320,7 @@ FS.prototype.CreateDirectory = function(name, parentid) {
x.name = name;
x.parentid = parentid;
x.mode = 0x01FF | S_IFDIR;
x.updatedir = true;
if (parentid >= 0) {
x.uid = this.inodes[parentid].uid;
x.gid = this.inodes[parentid].gid;
@ -324,6 +328,7 @@ FS.prototype.CreateDirectory = function(name, parentid) {
}
x.qid.type = S_IFDIR >> 8;
this.PushInode(x);
this.NotifyListeners(this.inodes.length-1, 'newdir');
return this.inodes.length-1;
}
@ -336,6 +341,7 @@ FS.prototype.CreateFile = function(filename, parentid) {
x.qid.type = S_IFREG >> 8;
x.mode = (this.inodes[parentid].mode & 0x1B6) | S_IFREG;
this.PushInode(x);
this.NotifyListeners(this.inodes.length-1, 'newfile');
return this.inodes.length-1;
}
@ -371,7 +377,6 @@ FS.prototype.CreateTextFile = function(filename, parentid, str) {
var id = this.CreateFile(filename, parentid);
var x = this.inodes[id];
var data = this.inodedata[id] = new Uint8Array(str.length);
//x.waswritten = true;
x.size = str.length;
for (var j = 0; j < str.length; j++) {
data[j] = str.charCodeAt(j);
@ -387,7 +392,6 @@ FS.prototype.CreateBinaryFile = function(filename, parentid, buffer) {
var x = this.inodes[id];
var data = this.inodedata[id] = new Uint8Array(buffer.length);
data.set(buffer);
//x.waswritten = true;
x.size = buffer.length;
return id;
}
@ -407,7 +411,7 @@ FS.prototype.OpenInode = function(id, mode) {
case S_IFCHR: type = "Character Device"; break;
}
*/
//DebugMessage("open:" + this.GetFullPath(id) + " status:" + inode.status);
//message.Debug("open:" + this.GetFullPath(id) + " type: " + inode.mode + " status:" + inode.status);
if (inode.status == STATUS_ON_SERVER) {
this.LoadFile(id);
return false;
@ -416,23 +420,23 @@ FS.prototype.OpenInode = function(id, mode) {
}
FS.prototype.CloseInode = function(id) {
//DebugMessage("close: " + this.GetFullPath(id));
//message.Debug("close: " + this.GetFullPath(id));
var inode = this.GetInode(id);
if (inode.status == STATUS_UNLINKED) {
//DebugMessage("Filesystem: Delete unlinked file");
//message.Debug("Filesystem: Delete unlinked file");
inode.status == STATUS_INVALID;
delete this.inodedata[id];
//inode.waswritten = true;
inode.size = 0;
}
}
FS.prototype.Rename = function(olddirid, oldname, newdirid, newname) {
//DebugMessage("Rename " + oldname + " to " + newname);
// message.Debug("Rename " + oldname + " to " + newname);
if ((olddirid == newdirid) && (oldname == newname)) {
return true;
}
var oldid = this.Search(olddirid, oldname);
var oldpath = this.GetFullPath(oldid);
if (oldid == -1) {
return false;
}
@ -450,8 +454,8 @@ FS.prototype.Rename = function(olddirid, oldname, newdirid, newname) {
} else {
var id = this.FindPreviousID(idx);
if (id == -1) {
//DebugMessage("Error in Filesystem: Cannot find previous id of inode");
abort();
message.Debug("Error in Filesystem: Cannot find previous id of inode");
message.Abort();
}
this.inodes[id].nextid = inode.nextid;
}
@ -465,13 +469,16 @@ FS.prototype.Rename = function(olddirid, oldname, newdirid, newname) {
this.inodes[olddirid].updatedir = true;
this.inodes[newdirid].updatedir = true;
this.NotifyListeners(idx, "rename", {oldpath: oldpath});
return true;
}
FS.prototype.Write = function(id, offset, count, GetByte) {
this.NotifyListeners(id, 'write');
var inode = this.inodes[id];
var data = this.inodedata[id];
//inode.waswritten = true;
if (!data || data.length < (offset+count)) {
this.ChangeSize(id, Math.floor(((offset+count)*3)/2) );
@ -489,7 +496,7 @@ FS.prototype.Search = function(parentid, name) {
var id = this.inodes[parentid].firstid;
while(id != -1) {
if (this.inodes[id].parentid != parentid) { // consistency check
DebugMessage("Error in Filesystem: Found inode with wrong parent id");
message.Debug("Error in Filesystem: Found inode with wrong parent id");
}
if (this.inodes[id].name == name) return id;
id = this.inodes[id].nextid;
@ -533,9 +540,10 @@ FS.prototype.FindPreviousID = function(idx) {
}
FS.prototype.Unlink = function(idx) {
this.NotifyListeners(idx, 'delete');
if (idx == 0) return false; // root node cannot be deleted
var inode = this.GetInode(idx);
//DebugMessage("Unlink " + inode.name);
//message.Debug("Unlink " + inode.name);
// check if directory is not empty
if ((inode.mode&S_IFMT) == S_IFDIR) {
@ -548,8 +556,8 @@ FS.prototype.Unlink = function(idx) {
} else {
var id = this.FindPreviousID(idx);
if (id == -1) {
DebugMessage("Error in Filesystem: Cannot find previous id of inode");
abort();
message.Debug("Error in Filesystem: Cannot find previous id of inode");
message.Abort();
}
this.inodes[id].nextid = inode.nextid;
}
@ -565,12 +573,12 @@ FS.prototype.Unlink = function(idx) {
FS.prototype.GetInode = function(idx)
{
if (isNaN(idx)) {
DebugMessage("Error in filesystem: id is not a number ");
message.Debug("Error in filesystem: id is not a number ");
return 0;
}
if ((idx < 0) || (idx > this.inodes.length)) {
DebugMessage("Error in filesystem: Attempt to get inode with id " + idx);
message.Debug("Error in filesystem: Attempt to get inode with id " + idx);
return 0;
}
return this.inodes[idx];
@ -580,11 +588,10 @@ FS.prototype.ChangeSize = function(idx, newsize)
{
var inode = this.GetInode(idx);
var temp = this.inodedata[idx];
//DebugMessage("change size to: " + newsize);
//message.Debug("change size to: " + newsize);
if (newsize == inode.size) return;
var data = this.inodedata[idx] = new Uint8Array(newsize);
inode.size = newsize;
//inode.waswritten = true;
if(!temp) return;
var size = Math.min(temp.length, inode.size);
for(var i=0; i<size; i++) {
@ -627,15 +634,63 @@ FS.prototype.GetRecursiveList = function(dirid, list) {
}
FS.prototype.MergeFile = function(file) {
throw "unimplemented";
//DebugMessage("Merge path:" + file.name);
//var ids = this.SearchPath(file.name);
//if (ids.parentid == -1) return; // not even the path seems to exist
//if (ids.id == -1) {
// ids.id = this.CreateFile(ids.name, ids.parentid);
message.Debug("Merge path:" + file.name);
var ids = this.SearchPath(file.name);
if (ids.parentid == -1) return; // not even the path seems to exist
if (ids.id == -1) {
ids.id = this.CreateFile(ids.name, ids.parentid);
}
this.inodes[ids.id].data = file.data;
this.inodes[ids.id].size = file.data.length;
}
FS.prototype.RecursiveDelete = function(path) {
var toDelete = []
var ids = this.SearchPath(path);
if (ids.parentid == -1 || ids.id == -1) return;
this.GetRecursiveList(ids.id, toDelete);
for(var i=toDelete.length-1; i>=0; i--)
this.Unlink(toDelete[i]);
}
FS.prototype.DeleteNode = function(path) {
var ids = this.SearchPath(path);
if (ids.parentid == -1 || ids.id == -1) return;
if ((this.inodes[ids.id].mode&S_IFMT) == S_IFREG){
this.Unlink(ids.id);
return;
}
if ((this.inodes[ids.id].mode&S_IFMT) == S_IFDIR){
var toDelete = []
this.GetRecursiveList(ids.id, toDelete);
for(var i=toDelete.length-1; i>=0; i--)
this.Unlink(toDelete[i]);
this.Unlink(ids.id);
return;
}
}
/** @param {*=} info */
FS.prototype.NotifyListeners = function(id, action, info) {
//if(info==undefined)
// info = {};
//var path = this.GetFullPath(id);
//if (this.watchFiles[path] == true && action=='write') {
// message.Send("WatchFileEvent", path);
//}
//for (var directory in this.watchDirectories) {
// if (this.watchDirectories.hasOwnProperty(directory)) {
// var indexOf = path.indexOf(directory)
// if(indexOf == 0 || indexOf == 1)
// message.Send("WatchDirectoryEvent", {path: path, event: action, info: info});
// }
//}
//this.inodes[ids.id].data = file.data;
//this.inodes[ids.id].size = file.data.length;
}
@ -644,23 +699,23 @@ FS.prototype.Check = function() {
{
if (this.inodes[i].status == STATUS_INVALID) continue;
if (this.inodes[i].nextid == i) {
DebugMessage("Error in filesystem: file points to itself");
abort();
message.Debug("Error in filesystem: file points to itself");
message.Abort();
}
var inode = this.GetInode(i);
if (inode.parentid < 0) {
DebugMessage("Error in filesystem: negative parent id " + i);
message.Debug("Error in filesystem: negative parent id " + i);
}
var n = inode.name.length;
if (n == 0) {
DebugMessage("Error in filesystem: inode with no name and id " + i);
message.Debug("Error in filesystem: inode with no name and id " + i);
}
for (var j in inode.name) {
var c = inode.name.charCodeAt(j);
if (c < 32) {
DebugMessage("Error in filesystem: Unallowed char in filename");
message.Debug("Error in filesystem: Unallowed char in filename");
}
}
}
@ -678,29 +733,28 @@ FS.prototype.FillDirectory = function(dirid) {
var size = 0;
var id = this.inodes[dirid].firstid;
while(id != -1) {
size += 13 + 8 + 1 + 2 + UTF8Length(this.inodes[id].name);
size += 13 + 8 + 1 + 2 + UTF8.UTF8Length(this.inodes[id].name);
id = this.inodes[id].nextid;
}
size += 13 + 8 + 1 + 2 + 1; // "." entry
size += 13 + 8 + 1 + 2 + 2; // ".." entry
//DebugMessage("size of dir entry: " + size);
//message.Debug("size of dir entry: " + size);
var data = this.inodedata[dirid] = new Uint8Array(size);
//inode.waswritten = true;
inode.size = size;
var offset = 0x0;
offset += Marshall(
offset += marshall.Marshall(
["Q", "d", "b", "s"],
[this.MakeQid(this.inodes[dirid]),
[this.inodes[dirid].qid,
offset+13+8+1+2+1,
this.inodes[dirid].mode >> 12,
"."],
data, offset);
offset += Marshall(
offset += marshall.Marshall(
["Q", "d", "b", "s"],
[this.MakeQid(this.inodes[parentid]),
[this.inodes[parentid].qid,
offset+13+8+1+2+2,
this.inodes[parentid].mode >> 12,
".."],
@ -708,10 +762,10 @@ FS.prototype.FillDirectory = function(dirid) {
id = this.inodes[dirid].firstid;
while(id != -1) {
offset += Marshall(
offset += marshall.Marshall(
["Q", "d", "b", "s"],
[this.MakeQid(this.inodes[id]),
offset+13+8+1+2+UTF8Length(this.inodes[id].name),
[this.inodes[id].qid,
offset+13+8+1+2+UTF8.UTF8Length(this.inodes[id].name),
this.inodes[id].mode >> 12,
this.inodes[id].name],
data, offset);
@ -756,23 +810,3 @@ FS.prototype.PrepareCAPs = function(id) {
return inode.caps.length;
}
//FS.prototype.ClearCache = function()
//{
// for(var id in this.inodedata)
// {
// if(!this.inodes[id].waswritten)
// {
// delete this.inodedata[id];
// }
// }
//};
FS.prototype.MakeQid = function(inode)
{
return inode.qid;
//return {
// type: inode.qid_type,
// version: inode.qid_version,
// path: inode.qid_path,
//};
};

View file

@ -29,17 +29,20 @@ var VRING_DESC_F_WRITE = 2; /* This marks a buffer as write-only (otherwise
var VRING_DESC_F_INDIRECT = 4; /* This means the buffer contains a list of buffer descriptors. */
function Swap16(x)
{
// OR1K is big endian, therefore no conversion needed for us
return x;
}
function Swap32(x)
{
return x;
function hex8(n)
{
return h(n);
}
function abort()
var message = {};
/** @param {...string} log */
message.Debug = function(log)
{
dbg_log([].slice.apply(arguments).join(" "), LOG_9P);
}
message.Abort = function()
{
if(DEBUG)
{
@ -47,63 +50,58 @@ function abort()
}
}
function hex8(n)
// XXX: Should go through emulator interface
var LoadBinaryResource;
if(typeof XMLHttpRequest !== "undefined")
{
return h(n);
}
/** @param {...string} log */
function DebugMessage(log)
{
dbg_log([].slice.apply(arguments).join(" "), LOG_9P);
}
function LoadXMLResource(url, OnSuccess, OnError) {
var req = new XMLHttpRequest();
req.open('GET', url, true);
//req.overrideMimeType('text/xml');
req.onreadystatechange = function () {
if (req.readyState != 4) {
return;
}
if ((req.status != 200) && (req.status != 0)) {
OnError("Error: Could not load XML file " + url);
return;
}
OnSuccess(req.responseText);
};
req.send(null);
}
function LoadBinaryResource(url, OnSuccess, OnError) {
var req = new XMLHttpRequest();
req.open('GET', url, true);
req.responseType = "arraybuffer";
req.onreadystatechange = function () {
if (req.readyState != 4) {
return;
}
if ((req.status != 200) && (req.status != 0)) {
OnError("Error: Could not load file " + url);
return;
}
var arrayBuffer = req.response;
if (arrayBuffer) {
OnSuccess(arrayBuffer);
} else {
OnError("Error: No data received from: " + url);
}
};
/*
req.onload = function(e)
{
var arrayBuffer = req.response;
if (arrayBuffer) {
OnLoadFunction(arrayBuffer);
}
LoadBinaryResource = function(url, OnSuccess, OnError) {
var req = new XMLHttpRequest();
req.open('GET', url, true);
req.responseType = "arraybuffer";
req.onreadystatechange = function () {
if (req.readyState != 4) {
return;
}
if ((req.status != 200) && (req.status != 0)) {
OnError("Error: Could not load file " + url);
return;
}
var arrayBuffer = req.response;
if (arrayBuffer) {
OnSuccess(arrayBuffer);
} else {
OnError("Error: No data received from: " + url);
}
};
*/
req.send(null);
/*
req.onload = function(e)
{
var arrayBuffer = req.response;
if (arrayBuffer) {
OnLoadFunction(arrayBuffer);
}
};
*/
req.send(null);
}
}
else
{
LoadBinaryResource = function(url, OnSuccess, OnError)
{
//console.log(url);
require("fs")["readFile"](url, function(err, data)
{
if(err)
{
OnError(err);
}
else
{
OnSuccess(new Uint8Array(data).buffer);
}
});
}
}

View file

@ -3,9 +3,11 @@
// -------------------------------------------------
// helper functions for virtio and 9p.
var marshall = {};
// Inserts data from an array to a byte aligned struct in memory
function Marshall(typelist, input, struct, offset) {
marshall.Marshall = function(typelist, input, struct, offset) {
var item;
var size = 0;
for (var i=0; i < typelist.length; i++) {
@ -56,12 +58,12 @@ function Marshall(typelist, input, struct, offset) {
struct[lengthoffset+1] = (length >> 8) & 0xFF;
break;
case "Q":
Marshall(["b", "w", "d"], [item.type, item.version, item.path], struct, offset)
marshall.Marshall(["b", "w", "d"], [item.type, item.version, item.path], struct, offset)
offset += 13;
size += 13;
break;
default:
DebugMessage("Marshall: Unknown type=" + typelist[i]);
message.Debug("Marshall: Unknown type=" + typelist[i]);
break;
}
}
@ -70,7 +72,7 @@ function Marshall(typelist, input, struct, offset) {
// Extracts data from a byte aligned struct in memory to an array
function Unmarshall(typelist, struct, offset) {
marshall.Unmarshall = function(typelist, struct, offset) {
var output = [];
for (var i=0; i < typelist.length; i++) {
switch (typelist[i]) {
@ -109,7 +111,7 @@ function Unmarshall(typelist, struct, offset) {
output.push(str);
break;
default:
DebugMessage("Error in Unmarshall: Unknown type=" + typelist[i]);
message.Debug("Error in Unmarshall: Unknown type=" + typelist[i]);
break;
}
}
@ -118,7 +120,7 @@ function Unmarshall(typelist, struct, offset) {
// Extracts data from a byte aligned struct in memory to an array
function Unmarshall2(typelist, GetByte) {
marshall.Unmarshall2 = function(typelist, GetByte) {
var output = [];
for (var i=0; i < typelist.length; i++) {
switch (typelist[i]) {
@ -157,7 +159,7 @@ function Unmarshall2(typelist, GetByte) {
output.push(str);
break;
default:
DebugMessage("Error in Unmarshall2: Unknown type=" + typelist[i]);
message.Debug("Error in Unmarshall2: Unknown type=" + typelist[i]);
break;
}
}

View file

@ -4,6 +4,8 @@
"use strict";
var UTF8 = {}
/** @constructor */
function UTF8StreamToUnicode() {
@ -50,7 +52,7 @@ function UnicodeToUTF8Stream(key)
if (key < 0x800) return [0xC0|((key>>6)&0x1F), 0x80|(key&0x3F)];
}
function UTF8Length(s)
UTF8.UTF8Length = function(s)
{
var length = 0;
for(var i=0; i<s.length; i++) {

View file

@ -32,6 +32,7 @@ function VirtIO(cpu, bus, filesystem)
io.register_read(0xA800, this, undefined, undefined, function()
{
// device features
dbg_log("Read device features", LOG_VIRTIO);
return 1;
});
@ -81,12 +82,31 @@ function VirtIO(cpu, bus, filesystem)
io.register_write(0xA812, this, function(data)
{
dbg_log("Write device status: " + h(data, 2), LOG_VIRTIO);
if(data === 0)
{
dbg_log("Reset", LOG_VIRTIO);
this.reset();
}
else if(data & 0x80)
{
dbg_log("Warning: Device status failed", LOG_VIRTIO);
}
else
{
dbg_log(((data & 1) ? "ACKNOWLEDGE " : "") +
((data & 2) ? "DRIVER " : "") +
((data & 4) ? "DRIVER_OK" : ""),
LOG_VIRTIO);
}
this.device_status = data;
});
io.register_read(0xA812, this, function()
{
dbg_log("Read device status", LOG_VIRTIO);
dbg_log("Read device status: " + h(this.device_status), LOG_VIRTIO);
return this.device_status;
});
@ -297,7 +317,7 @@ VirtIO.prototype.handle_descriptor = function(idx)
}.bind(this));
};
VirtIO.prototype.device_reply = function(infos)
VirtIO.prototype.device_reply = function(queueidx, infos)
{
if(infos.next === -1)
{