1623 lines
57 KiB
JavaScript
1623 lines
57 KiB
JavaScript
/**
|
|
** ==============================
|
|
** O O O OOOO
|
|
** O O O O O O
|
|
** O O O O O O
|
|
** OOOO OOOO O OOO OOOO
|
|
** O O O O O O O
|
|
** O O O O O O O
|
|
** OOOO OOOO O O OOOO
|
|
** ==============================
|
|
** Dr. Stefan Bosse http://www.bsslab.de
|
|
**
|
|
** COPYRIGHT: THIS SOFTWARE, EXECUTABLE AND SOURCE CODE IS OWNED
|
|
** BY THE AUTHOR(S).
|
|
** THIS SOURCE CODE MAY NOT BE COPIED, EXTRACTED,
|
|
** MODIFIED, OR OTHERWISE USED IN A CONTEXT
|
|
** OUTSIDE OF THE SOFTWARE SYSTEM.
|
|
**
|
|
** $AUTHORS: Stefan Bosse
|
|
** $INITIAL: (C) 2015-2017 bLAB
|
|
** $CREATED: 6-7-15.
|
|
** $VERSION: 1.2.2
|
|
**
|
|
** $INFO:
|
|
* AFS Server and RPC Interface
|
|
*
|
|
** $ENDOFINFO
|
|
*/
|
|
/*
|
|
*********************
|
|
** PUBLIC INTERFACE
|
|
*********************
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
var log = 0;
|
|
|
|
var util = Require('util');
|
|
var Io = Require('com/io');
|
|
var Net = Require('dos/network');
|
|
var Status = Net.Status;
|
|
var Command = Net.Command;
|
|
var Rights = Net.Rights;
|
|
var Std = Require('dos/std');
|
|
var Sch = Require('dos/scheduler');
|
|
var Buf = Require('dos/buf');
|
|
var Rpc = Require('dos/rpc');
|
|
var Fcache = Require('dos/fcache');
|
|
var Flist = Require('dos/freelist');
|
|
var Fs = Require('fs');
|
|
var Comp = Require('com/compat');
|
|
var String = Comp.string;
|
|
var Array = Comp.array;
|
|
var Perv = Comp.pervasives;
|
|
var Hashtbl = Comp.hashtbl;
|
|
var assert = Comp.assert;
|
|
var div = Comp.div;
|
|
var Afs = Require('dos/afs_srv_common');
|
|
var Afs_file_state = Afs.Afs_file_state;
|
|
var Afs_commit_flag= Afs.Afs_commit_flag;
|
|
/**
|
|
* @augments afs_server
|
|
* @augments afs_server_emb
|
|
* @see afs_server
|
|
* @see afs_server_emb
|
|
* @see afs_server_rpc~meth
|
|
* @constructor
|
|
*/
|
|
var afs_server_rpc = function() {
|
|
};
|
|
|
|
/**
|
|
* @typedef {{
|
|
* afs_create_file:afs_server_rpc.afs_create_file,
|
|
* afs_modify_file:afs_server_rpc.afs_modify_file,
|
|
* afs_read_file:afs_server_rpc.afs_read_file,
|
|
* afs_file_size:afs_server_rpc.afs_file_size,
|
|
* afs_touch_file:afs_server_rpc.afs_touch_file,
|
|
* afs_age:afs_server_rpc.afs_age,
|
|
* afs_insert_data:afs_server_rpc.afs_insert_data,
|
|
* afs_delete_data:afs_server_rpc.afs_delete_data,
|
|
* afs_destroy_file:afs_server_rpc.afs_destroy_file,
|
|
* afs_info:afs_server_rpc.afs_info,
|
|
* afs_exit:afs_server_rpc.afs_exit,
|
|
* afs_stat:afs_server_rpc.afs_stat,
|
|
* afs_start_server:afs_server_rpc.afs_start_server
|
|
* }} afs_server_rpc~meth
|
|
*/
|
|
|
|
/** AFS server create request.
|
|
** Create a new file.
|
|
**
|
|
** Args:
|
|
** priv: the request private field
|
|
** buf: the write buffer
|
|
** size: the initial file size [bytes] (can be 0: only object creation)
|
|
** commit: the commit flag
|
|
**
|
|
** Return:
|
|
** status
|
|
** newcap
|
|
**
|
|
*
|
|
* @param {privat} priv
|
|
* @param {buffer|rpcio} buf
|
|
* @param {number} size
|
|
* @param {Afs_commit_flag} commit
|
|
* @param {function((Status.STD_OK|*),capability|undefined)} callback
|
|
*/
|
|
afs_server_rpc.prototype.afs_create_file =function (priv,buf,size,commit,callback) {
|
|
|
|
var self=this;
|
|
var stat=Status.STD_UNKNOWN;
|
|
var file;
|
|
var obj = Net.prv_number(priv);
|
|
var rights = Net.prv_rights(priv);
|
|
Sch.ScheduleBlock([
|
|
function () {
|
|
if (obj > 0) {
|
|
/*
|
|
** It's a file, used only for authorization.
|
|
*/
|
|
self.acquire_file(obj, function (_stat, _file) {
|
|
stat = _stat;
|
|
file = _file;
|
|
});
|
|
} else {
|
|
file=undefined;
|
|
if (Net.prv_decode(priv, self.afs_super.afs_checkfield) == false ||
|
|
Net.rights_req(rights, [Rights.AFS_RGT_CREATE]) == false)
|
|
stat = Status.STD_DENIED;
|
|
else stat = Status.STD_OK;
|
|
}
|
|
},
|
|
function () {
|
|
if (stat != Status.STD_OK)
|
|
throw stat;
|
|
if (file!=undefined) {
|
|
if (Net.prv_decode(priv, file.ff_random) == false ||
|
|
Net.rights_req(rights, [Rights.AFS_RGT_CREATE]) == false) {
|
|
self.release_file(file, Afs_commit_flag.AFS_UNCOMMIT);
|
|
throw Status.STD_DENIED;
|
|
}
|
|
self.release_file(file, Afs_commit_flag.AFS_UNCOMMIT);
|
|
}
|
|
/*
|
|
** First get a new i-node==object number
|
|
*/
|
|
var objnew = self.get_freeobjnum();
|
|
file = Afs.Afs_file(objnew,Net.uniqport(),size, // initial size
|
|
self.time(),Afs.AFS_MAXLIVE,
|
|
Afs_file_state.FF_unlocked);
|
|
file.lock();
|
|
var final = commit > 0;
|
|
stat = self.create_file_inode(file,final);
|
|
if (stat != Status.STD_OK) {
|
|
file.unlock();
|
|
throw stat;
|
|
}
|
|
var cap =
|
|
Net.Capability(self.afs_super.afs_putport,
|
|
Net.prv_encode(objnew,Rights.PRV_ALL_RIGHTS,file.ff_random));
|
|
self.touch(file);
|
|
if (size>0) {
|
|
stat=self.modify_file(file,0,size,buf);
|
|
}
|
|
if (stat != Status.STD_OK) {
|
|
file.unlock();
|
|
throw stat;
|
|
}
|
|
stat = self.release_file(file,commit);
|
|
//Io.out(file.print());
|
|
if (stat != Status.STD_OK) {
|
|
file.unlock();
|
|
throw stat;
|
|
}
|
|
callback(stat,cap);
|
|
|
|
}
|
|
],function (e) {
|
|
if (typeof e != 'number') {Io.printstack(e,'Afs_server_rpc.afs_create_file');}
|
|
if (typeof e == 'number') callback(e,undefined); else callback(Status.STD_SYSERR,undefined);
|
|
});
|
|
};
|
|
|
|
/** AFS server modify request.
|
|
** Morify an existing file.
|
|
**
|
|
** Args:
|
|
** priv: the request private field
|
|
** buf: the write buffer
|
|
** size: the initial file size [bytes] (can be 0: only object creation)
|
|
** commit: the commit flag
|
|
**
|
|
** Return:
|
|
** status
|
|
** newcap
|
|
**
|
|
*
|
|
* @param {privat} priv
|
|
* @param {buffer|rpcio} buf
|
|
* @param {number} off
|
|
* @param {number} size
|
|
* @param {(Afs_commit_flag.AFS_UNCOMMIT|*)} commit
|
|
* @param {function((Status.STD_OK|*),capability|undefined)} callback
|
|
*/
|
|
|
|
afs_server_rpc.prototype.afs_modify_file =function (priv,buf,off,size,commit,callback) {
|
|
var self=this;
|
|
var stat=Status.STD_UNKNOWN;
|
|
var file=undefined;
|
|
var file2=undefined;
|
|
var obj = Net.prv_number(priv);
|
|
var rights = Net.prv_rights(priv);
|
|
|
|
|
|
Io.log((log<1)||('afs_server_rpc.afs_modify_file: obj='+obj+' off='+off+' size='+size+' commit='+Afs.Afs_commit_flag.print(commit)));
|
|
|
|
if (off<0 || size<0) callback(Status.STD_ARGBAD,undefined);
|
|
else Sch.ScheduleBlock([
|
|
function () {
|
|
if (obj > 0) {
|
|
/*
|
|
*/
|
|
self.acquire_file(obj, function (_stat, _file) {
|
|
stat = _stat;
|
|
file = _file;
|
|
});
|
|
} else {
|
|
stat = Status.STD_CAPBAD;
|
|
}
|
|
},
|
|
function () {
|
|
if (stat != Status.STD_OK)
|
|
throw stat;
|
|
if (Net.prv_decode(priv, file.ff_random) == false ||
|
|
Net.rights_req(rights, [Rights.AFS_RGT_MODIFY]) == false) {
|
|
throw Status.STD_DENIED;
|
|
}
|
|
var cap =
|
|
Net.Capability(self.afs_super.afs_putport,
|
|
Net.prv_encode(obj,Rights.PRV_ALL_RIGHTS,file.ff_random));
|
|
if (size==0 && file.ff_state == Afs.Afs_file_state.FF_unlocked) {
|
|
/*
|
|
** Only commit the file.
|
|
*/
|
|
stat = self.release_file(file, commit);
|
|
file=undefined;
|
|
} else if (size==0 && (file.ff_state == Afs.Afs_file_state.FF_locked||
|
|
file.ff_state == Afs.Afs_file_state.FF_commit)) {
|
|
/*
|
|
** Only unlocked files can be committed!
|
|
** Or must we create a copy here?
|
|
*/
|
|
throw Status.STD_ARGBAD;
|
|
} else {
|
|
/*
|
|
** The file exists, the request is authorized, modify content.
|
|
*/
|
|
if (file.ff_state == Afs.Afs_file_state.FF_unlocked) {
|
|
/*
|
|
** New data beyond the current file size ?
|
|
*/
|
|
if (file.ff_size < (off+size)) {
|
|
stat=self.modify_size(file,(off+size));
|
|
if (stat!=Status.STD_OK) throw stat;
|
|
}
|
|
stat=self.modify_file(file,off,size,buf);
|
|
if (stat!=Status.STD_OK) throw stat;
|
|
stat = self.release_file(file, commit);
|
|
if (stat!=Status.STD_OK) throw stat;
|
|
file=undefined;
|
|
|
|
} else {
|
|
/*
|
|
** Create a new file. Copy the content of the
|
|
** original one. Modify the new one.
|
|
*/
|
|
/*
|
|
** First get a new i-node==object number
|
|
*/
|
|
var objnew = self.get_freeobjnum();
|
|
var size2;
|
|
if (file.ff_size < off+size) size2=off+size; else size2=file.ff_size;
|
|
file2 = Afs.Afs_file(objnew,Net.uniqport(),size2, // initial size
|
|
self.time(),Afs.AFS_MAXLIVE,
|
|
Afs_file_state.FF_unlocked);
|
|
file2.lock();
|
|
if (stat != Status.STD_OK) {
|
|
file.unlock();
|
|
throw stat;
|
|
}
|
|
cap =
|
|
Net.Capability(self.afs_super.afs_putport,
|
|
Net.prv_encode(objnew,Rights.PRV_ALL_RIGHTS,file2.ff_random));
|
|
var buf2=Buf.Buffer();
|
|
var cs = Perv.min(file.ff_size,1000);
|
|
var co = 0;
|
|
while (cs>0) {
|
|
stat=self.read_file(file,co,cs,buf2);
|
|
if (stat!=Status.STD_OK) {
|
|
file.unlock();
|
|
throw stat;
|
|
}
|
|
stat=self.modify_file(file2,co,cs,buf2);
|
|
if (stat!=Status.STD_OK) {
|
|
file.unlock();
|
|
throw stat;
|
|
}
|
|
co=Perv.min(co+cs,file.ff_size);
|
|
cs=Perv.min(file.ff_size-co,1000);
|
|
}
|
|
stat=self.modify_file(file2,off,size,buf);
|
|
if (stat!=Status.STD_OK) {
|
|
file2.unlock();
|
|
throw stat;
|
|
}
|
|
stat = self.release_file(file,Afs_commit_flag.AFS_UNCOMMIT);
|
|
file=undefined;
|
|
stat = self.release_file(file2,commit);
|
|
if (stat!=Status.STD_OK) {
|
|
file2.unlock();
|
|
throw stat;
|
|
}
|
|
}
|
|
}
|
|
if (stat != Status.STD_OK) {
|
|
throw stat;
|
|
}
|
|
callback(stat,cap);
|
|
|
|
}
|
|
],function (e) {
|
|
if (file!=undefined) self.release_file(file,Afs_commit_flag.AFS_UNCOMMIT);
|
|
if (typeof e != 'number') {Io.printstack(e,'Afs_server_rpc.afs_modify_file');}
|
|
if (typeof e == 'number') callback(e,undefined); else callback(Status.STD_SYSERR,undefined);
|
|
});
|
|
};
|
|
|
|
/**
|
|
*
|
|
* @param {privat} priv
|
|
* @param {buffer|rpcio} buf
|
|
* @param off
|
|
* @param size
|
|
* @param {function((Status.STD_OK|*),number)} callback return status,size
|
|
*/
|
|
afs_server_rpc.prototype.afs_read_file =function (priv,buf,off,size,callback) {
|
|
var self = this;
|
|
var stat = Status.STD_UNKNOWN;
|
|
var file = undefined;
|
|
var size=size;
|
|
var obj = Net.prv_number(priv);
|
|
var rights = Net.prv_rights(priv);
|
|
Sch.ScheduleBlock([
|
|
function () {
|
|
if (obj > 0) {
|
|
/*
|
|
** It's a file
|
|
*/
|
|
self.acquire_file(obj, function (_stat, _file) {
|
|
stat = _stat;
|
|
file = _file;
|
|
});
|
|
} else
|
|
stat=Status.STD_CAPBAD;
|
|
},
|
|
function () {
|
|
if (stat != Status.STD_OK) {
|
|
throw stat;
|
|
}
|
|
if ((Net.prv_decode(priv, file.ff_random) == false) ||
|
|
(Net.rights_req(rights,[Rights.AFS_RGT_READ])== false)) {
|
|
throw Status.STD_DENIED;
|
|
}
|
|
Io.log((log<1)||('afs_read_file off='+off+' ff_size='+file.ff_size));
|
|
if (off > file.ff_size) {
|
|
throw Status.STD_ARGBAD;
|
|
}
|
|
if ((size+off) > file.ff_size) size=file.ff_size-off;
|
|
stat=self.read_file(file,off,size,buf);
|
|
self.release_file(file, Afs_commit_flag.AFS_UNCOMMIT);
|
|
file=undefined;
|
|
callback(stat,size);
|
|
}
|
|
],function (e) {
|
|
if (file!=undefined) self.release_file(file,Afs_commit_flag.AFS_UNCOMMIT);
|
|
if (typeof e != 'number') {Io.printstack(e,'Afs_server_rpc.afs_read_file');}
|
|
if (typeof e == 'number') callback(e,0); else callback(Status.STD_SYSERR,0);
|
|
});
|
|
};
|
|
|
|
/**
|
|
** AFS server size request.
|
|
**
|
|
**
|
|
*
|
|
* @param {private} priv
|
|
* @param {function((Status.STD_OK|*),number)} callback return status,size
|
|
*/
|
|
afs_server_rpc.prototype.afs_file_size =function (priv,callback) {
|
|
var self = this;
|
|
var stat = Status.STD_UNKNOWN;
|
|
var file = undefined;
|
|
var size=0;
|
|
var obj = Net.prv_number(priv);
|
|
var rights = Net.prv_rights(priv);
|
|
Sch.ScheduleBlock([
|
|
function () {
|
|
if (obj > 0) {
|
|
/*
|
|
** It's a file
|
|
*/
|
|
self.acquire_file(obj, function (_stat, _file) {
|
|
stat = _stat;
|
|
file = _file;
|
|
});
|
|
} else
|
|
stat=Status.STD_CAPBAD;
|
|
},
|
|
function () {
|
|
if (stat != Status.STD_OK) {
|
|
throw stat;
|
|
}
|
|
if ((Net.prv_decode(priv, file.ff_random) == false)) {
|
|
throw Status.STD_DENIED;
|
|
}
|
|
size=file.ff_size;
|
|
stat=Status.STD_OK;
|
|
self.release_file(file, Afs_commit_flag.AFS_UNCOMMIT);
|
|
file=undefined;
|
|
callback(stat,size);
|
|
}
|
|
],function (e) {
|
|
if (file!=undefined) self.release_file(file,Afs_commit_flag.AFS_UNCOMMIT);
|
|
if (typeof e != 'number') {Io.printstack(e,'Afs_server_rpc.afs_file_size');}
|
|
if (typeof e == 'number') callback(e,0); else callback(Status.STD_SYSERR,0);
|
|
});
|
|
};
|
|
/**
|
|
** Touch file (update live time)
|
|
*
|
|
* @param {private} priv
|
|
* @param {function((Status.STD_OK|*))} callback return status
|
|
*/
|
|
afs_server_rpc.prototype.afs_touch_file =function (priv,callback) {
|
|
var self = this;
|
|
var stat = Status.STD_UNKNOWN;
|
|
var file = undefined;
|
|
var obj = Net.prv_number(priv);
|
|
var rights = Net.prv_rights(priv);
|
|
Sch.ScheduleBlock([
|
|
function () {
|
|
self.acquire_file(obj,function (_stat,_file) {
|
|
stat=_stat;
|
|
file=_file;
|
|
});
|
|
},
|
|
function () {
|
|
if (stat != Status.STD_OK) {
|
|
throw stat;
|
|
}
|
|
if (Net.prv_decode(priv, file.ff_random) == false) {
|
|
throw Status.STD_DENIED;
|
|
}
|
|
self.touch(file);
|
|
stat=Status.STD_OK;
|
|
self.release_file(file, Afs_commit_flag.AFS_UNCOMMIT);
|
|
file=undefined;
|
|
callback(stat);
|
|
}
|
|
],function (e) {
|
|
if (file!=undefined) self.release_file(file,Afs_commit_flag.AFS_UNCOMMIT);
|
|
if (typeof e != 'number') {Io.printstack(e,'Afs_server_rpc.afs_touch_file');}
|
|
if (typeof e == 'number') callback(e); else callback(Status.STD_SYSERR);
|
|
});
|
|
|
|
};
|
|
|
|
/**
|
|
** Age a file (decrement live time)
|
|
*
|
|
* @param {private} priv
|
|
* @param {function((Status.STD_OK|*))} callback return status
|
|
*/
|
|
afs_server_rpc.prototype.afs_age_file =function (priv,callback) {
|
|
var self = this,
|
|
stat = Status.STD_UNKNOWN,
|
|
file = undefined,
|
|
obj = Net.prv_number(priv),
|
|
rights = Net.prv_rights(priv);
|
|
|
|
Sch.ScheduleBlock([
|
|
function () {
|
|
self.acquire_file(obj,function (_stat,_file) {
|
|
stat=_stat;
|
|
file=_file;
|
|
});
|
|
},
|
|
function () {
|
|
if (stat != Status.STD_OK) {
|
|
throw stat;
|
|
}
|
|
if (Net.prv_decode(priv, file.ff_random) == false) {
|
|
throw Status.STD_DENIED;
|
|
}
|
|
self.age_file(file);
|
|
stat=Status.STD_OK;
|
|
self.release_file(file, Afs_commit_flag.AFS_UNCOMMIT);
|
|
file=undefined;
|
|
callback(stat);
|
|
}
|
|
],function (e) {
|
|
if (file!=undefined) self.release_file(file,Afs_commit_flag.AFS_UNCOMMIT);
|
|
if (typeof e != 'number') {Io.printstack(e,'Afs_server_rpc.afs_age_file');}
|
|
if (typeof e == 'number') callback(e); else callback(Status.STD_SYSERR);
|
|
});
|
|
};
|
|
|
|
/**
|
|
** Age all files (decrement live time)
|
|
*
|
|
* @param {function((Status.STD_OK|*))} callback return status
|
|
*/
|
|
afs_server_rpc.prototype.afs_age =function (priv,callback) {
|
|
var self = this,
|
|
stat = Status.STD_UNKNOWN,
|
|
obj = Net.prv_number(priv),
|
|
rights = Net.prv_rights(priv);
|
|
|
|
|
|
if (obj!=0 || !Net.prv_rights_check(priv, self.afs_super.afs_checkfield, Rights.AFS_RGT_MODIFY))
|
|
callback(Status.STD_DENIED);
|
|
else self.age(callback);
|
|
};
|
|
|
|
|
|
/**
|
|
** Restrict file capability
|
|
*
|
|
* @param {private} priv
|
|
* @param {number} mask
|
|
* @param {function((Status.STD_OK|*),(privat|undefined))} callback return status
|
|
*/
|
|
afs_server_rpc.prototype.afs_restrict =function (priv,mask,callback) {
|
|
var self = this;
|
|
var privres=undefined;
|
|
var stat = Status.STD_UNKNOWN;
|
|
var file = undefined;
|
|
var obj = Net.prv_number(priv);
|
|
var rights = Net.prv_rights(priv);
|
|
if (obj==0) {
|
|
if (Net.prv_decode(priv, self.afs_super.afs_checkfield) == false) {
|
|
stat= Status.STD_DENIED;
|
|
} else {
|
|
stat=Status.STD_OK;
|
|
privres=Net.prv_encode(obj,mask,self.afs_super.afs_checkfield);
|
|
}
|
|
callback(stat,privres);
|
|
}
|
|
else Sch.ScheduleBlock([
|
|
function () {
|
|
self.acquire_file(obj,function (_stat,_file) {
|
|
stat=_stat;
|
|
file=_file;
|
|
});
|
|
},
|
|
function () {
|
|
if (stat != Status.STD_OK) {
|
|
throw stat;
|
|
}
|
|
if (Net.prv_decode(priv, file.ff_random) == false) {
|
|
throw Status.STD_DENIED;
|
|
}
|
|
stat=Status.STD_OK;
|
|
privres=Net.prv_encode(obj,mask,file.ff_random);
|
|
self.release_file(file, Afs_commit_flag.AFS_UNCOMMIT);
|
|
file=undefined;
|
|
callback(stat,privres);
|
|
}
|
|
],function (e) {
|
|
if (file!=undefined) self.release_file(file,Afs_commit_flag.AFS_UNCOMMIT);
|
|
if (typeof e != 'number') {Io.printstack(e,'Afs_server_rpc.afs_restrict');}
|
|
if (typeof e == 'number') callback(e,undefined); else callback(Status.STD_SYSERR,undefined);
|
|
});
|
|
|
|
};
|
|
/** AFS server Insert request.
|
|
**
|
|
** Args:
|
|
** server: the server structure
|
|
** priv: the request private field
|
|
** buf: the write buffer
|
|
** size: the requested size (<= file size) [bytes]
|
|
** off: the file offset (<= file size) [bytes]
|
|
** commit: the commit flag
|
|
**
|
|
** Return:
|
|
** status
|
|
** newcap (FF_unlocked -> oldcap)
|
|
*
|
|
* @param {privat} priv
|
|
* @param {buffer|rpcio} buf
|
|
* @param off
|
|
* @param size
|
|
* @param commit
|
|
* @param {function((Status.STD_OK|*),capability|undefined)} callback
|
|
*/
|
|
|
|
afs_server_rpc.prototype.afs_insert_data =function (priv,buf,off,size,commit,callback) {
|
|
var self = this;
|
|
var stat = Status.STD_UNKNOWN;
|
|
var cap=undefined;
|
|
var file;
|
|
var size2,buf2,off2,obj2,file2;
|
|
var obj = Net.prv_number(priv);
|
|
var rights = Net.prv_rights(priv);
|
|
Sch.ScheduleBlock([
|
|
function () {
|
|
if (obj > 0) {
|
|
self.acquire_file(obj,function (_stat,_file) {
|
|
stat = _stat;
|
|
file = _file;
|
|
});
|
|
} else stat=Status.STD_CAPBAD;
|
|
},
|
|
function () {
|
|
if (stat != Status.STD_OK) {
|
|
throw stat;
|
|
}
|
|
|
|
if ((Net.prv_decode(priv, file.ff_random) == false) ||
|
|
(Net.rights_req(rights, [Rights.AFS_RGT_MODIFY]) == false)) {
|
|
throw Status.STD_DENIED;
|
|
}
|
|
|
|
if (size == 0 && file.ff_state == Afs_file_state.FF_unlocked) {
|
|
/*
|
|
** Only commit the file.
|
|
*/
|
|
stat = self.release_file(file, commit);
|
|
if (stat != Status.STD_OK) {
|
|
throw stat;
|
|
}
|
|
cap =
|
|
Net.Capability(self.afs_super.afs_putport,
|
|
Net.prv_encode(obj, Rights.PRV_ALL_RIGHTS, file.ff_random));
|
|
stat = Status.STD_OK;
|
|
} else if (size == 0 && (file.ff_state == Afs_file_state.FF_locked ||
|
|
file.ff_state == Afs_file_state.FF_commit)) {
|
|
/*
|
|
** Only unlocked files can be committed!
|
|
** Or must we create a copy here?
|
|
*/
|
|
self.release_file(file,Afs_commit_flag.AFS_UNCOMMIT);
|
|
stat=Status.STD_ARGBAD;
|
|
} else {
|
|
/*
|
|
** The file exists, and the request is authorized.
|
|
*/
|
|
if (file.ff_state == Afs_file_state.FF_unlocked) {
|
|
/*
|
|
** Modify existing file.
|
|
*/
|
|
/*
|
|
** New data beyond the current file size ?
|
|
*/
|
|
|
|
if (file.ff_size < (off+size))
|
|
stat=self.modify_size(file,off+size);
|
|
else stat=Status.STD_OK;
|
|
if (stat != Status.STD_OK) {
|
|
self.release_file(file,Afs_commit_flag.AFS_UNCOMMIT);
|
|
throw stat;
|
|
}
|
|
cap =
|
|
Net.Capability(self.afs_super.afs_putport,
|
|
Net.prv_encode(obj, Rights.PRV_ALL_RIGHTS, file.ff_random));
|
|
if ((off+size) < file.ff_size) {
|
|
/*
|
|
** The data should be inserted in the middle
|
|
** or at the beginning of the file. Therefore, we must
|
|
** shift the data between this offset (off) and
|
|
** (off+size) to create the needed space.
|
|
*/
|
|
buf2 = Buf.Buffer(self.afs_super.afs_block_size);
|
|
size2 = Perv.min(self.afs_super.afs_block_size,size);
|
|
off2 = (file.ff_size - size2);
|
|
|
|
/*
|
|
** Start at the current end of the file position and
|
|
** work down to the specified insert offset (off).
|
|
*/
|
|
|
|
while ( off2 >= (off+size)) {
|
|
/*
|
|
** First the chunk to read
|
|
*/
|
|
stat = self.read_file(file, off2, size2, buf2);
|
|
|
|
if (stat != Status.STD_OK) {
|
|
self.release_file(file, Afs_commit_flag.AFS_UNCOMMIT);
|
|
throw stat;
|
|
}
|
|
/*
|
|
** Now write the buffer to the shifted
|
|
** position.
|
|
*/
|
|
|
|
stat = self.modify_file(file, (off2 + size), size2, buf2);
|
|
|
|
if (stat != Status.STD_OK) {
|
|
self.release_file(file, Afs_commit_flag.AFS_UNCOMMIT);
|
|
throw stat;
|
|
}
|
|
|
|
size2 = Perv.min((off2 - off), self.afs_super.afs_block_size);
|
|
off2 = Perv.max((off2 - size2), off);
|
|
}
|
|
}
|
|
/*
|
|
** Now write the data to be inserted.
|
|
*/
|
|
stat=self.modify_file(file,off,size,buf);
|
|
if (stat != Status.STD_OK) {
|
|
throw stat;
|
|
}
|
|
stat=self.release_file(file,commit);
|
|
file=undefined;
|
|
if (stat != Status.STD_OK) {
|
|
throw stat;
|
|
}
|
|
|
|
} else {
|
|
/*
|
|
** Create a new file, copy the content of the
|
|
** original one, but shift the part from (off)
|
|
** to (off+size).
|
|
*/
|
|
obj2 = self.get_freeobjnum();
|
|
size2 = file.ff_size< (off+size)?(off+size):file.ff_size;
|
|
file2 = Afs.Afs_file(obj2,Net.uniqport(),size2,self.time(),Afs.AFS_MAXLIVE,
|
|
Afs_file_state.FF_unlocked,Afs.Disk(),true);
|
|
// Non-blocking, we're the first one accessng this file
|
|
file2.lock();
|
|
stat= self.create_file_inode(file2,false);
|
|
if (stat != Status.STD_OK) {
|
|
file2.unlock();
|
|
throw stat;
|
|
}
|
|
cap =
|
|
Net.Capability(self.afs_super.afs_putport,
|
|
Net.prv_encode(obj2, Rights.PRV_ALL_RIGHTS, file2.ff_random));
|
|
/*
|
|
** Copy the original data
|
|
*/
|
|
buf2 = Buf.Buffer(self.afs_super.afs_block_size);
|
|
|
|
|
|
var co = 0;
|
|
var cs = Perv.min(off,self.afs_super.afs_block_size);
|
|
/*
|
|
** First the part up to the off position.
|
|
** (Not shifted).
|
|
*/
|
|
while (cs>0) {
|
|
/*
|
|
** First the chunk to read
|
|
*/
|
|
|
|
stat =self.read_file(file,co,cs,buf2);
|
|
|
|
if (stat != Status.STD_OK) {
|
|
file2.unlock();
|
|
throw stat;
|
|
}
|
|
/*
|
|
** Now write the buffer
|
|
*/
|
|
|
|
stat = self.modify_file(file2,co,cs,buf2);
|
|
if (stat != Status.STD_OK) {
|
|
file2.unlock();
|
|
throw stat;
|
|
}
|
|
|
|
|
|
co = co + cs;
|
|
cs = Perv.min((off - co),self.afs_super.afs_block_size);
|
|
}
|
|
/*
|
|
** Now the shifted part up to the end of the file.
|
|
*/
|
|
cs = Perv.min((file.ff_size - co), self.afs_super.afs_block_size);
|
|
|
|
while (cs > 0) {
|
|
|
|
/*
|
|
** First the chunk to read
|
|
*/
|
|
|
|
stat = self.read_file(file, co, cs, buf2);
|
|
|
|
if (stat != Status.STD_OK) {
|
|
file2.unlock();
|
|
throw stat;
|
|
}
|
|
/*
|
|
** Now write the buffer to the shifted position.
|
|
*/
|
|
|
|
stat = self.modify_file(file2, (co + off + size), cs, buf2);
|
|
|
|
if (stat != Status.STD_OK) {
|
|
file2.unlock();
|
|
throw stat;
|
|
}
|
|
|
|
co = co + cs;
|
|
cs = Perv.min((file.ff_size - co), self.afs_super.afs_block_size);
|
|
}
|
|
/*
|
|
** Now write the data to be inserted.
|
|
*/
|
|
stat = self.modify_file(file2,off,size,buf);
|
|
if (stat != Status.STD_OK) {
|
|
file2.unlock();
|
|
throw stat;
|
|
}
|
|
|
|
stat = self.release_file(file2,commit);
|
|
if (stat != Status.STD_OK) {
|
|
throw stat;
|
|
}
|
|
self.release_file(file,Afs_commit_flag.AFS_UNCOMMIT);
|
|
file=undefined;
|
|
}
|
|
}
|
|
callback(stat, cap);
|
|
|
|
}
|
|
],function (e) {
|
|
if (file!=undefined) self.release_file(file,Afs_commit_flag.AFS_UNCOMMIT);
|
|
if (typeof e != 'number') {Io.printstack(e,'Afs_server_rpc.afs_insert_data');}
|
|
if (typeof e == 'number') callback(e,undefined); else callback(Status.STD_SYSERR,undefined);
|
|
});
|
|
};
|
|
|
|
/** AFS server Delete (part of the file data) request.
|
|
*
|
|
* Args:
|
|
* server: the server structure
|
|
* priv: the request private field
|
|
* size: the requested size (<= file size) [bytes]
|
|
* off: the file offset (<= file size) [bytes]
|
|
* commit: the commit flag
|
|
*
|
|
* Return:
|
|
* status
|
|
* newcap (FF_unlocked -> oldcap)
|
|
*
|
|
* @param {privat} priv
|
|
* @param off
|
|
* @param size
|
|
* @param commit
|
|
* @param {function((Status.STD_OK|*),capability|undefined)} callback
|
|
*/
|
|
afs_server_rpc.prototype.afs_delete_data =function (priv,off,size,commit,callback) {
|
|
var self = this;
|
|
var stat = Status.STD_UNKNOWN;
|
|
var file=undefined;
|
|
var obj = Net.prv_number(priv);
|
|
var rights = Net.prv_rights(priv);
|
|
var cap;
|
|
var off2,size2,buf2,obj2,file2;
|
|
Sch.ScheduleBlock([
|
|
function () {
|
|
if (obj > 0) {
|
|
self.acquire_file(obj,function (_stat,_file) {
|
|
stat = _stat;
|
|
file = _file;
|
|
});
|
|
} else
|
|
stat=Status.STD_CAPBAD;
|
|
},
|
|
function () {
|
|
if (stat != Status.STD_OK) {
|
|
throw stat;
|
|
}
|
|
if ((Net.prv_decode(priv, file.ff_random) == false) ||
|
|
(Net.rights_req(rights,[Rights.AFS_RGT_MODIFY])== false)) {
|
|
throw Status.STD_DENIED;
|
|
}
|
|
if (file.ff_state == Afs_file_state.FF_unlocked) {
|
|
cap=
|
|
Net.Capability(self.afs_super.afs_putport,
|
|
Net.prv_encode(obj,Rights.PRV_ALL_RIGHTS,file.ff_random));
|
|
buf2=Buf.Buffer(self.afs_super.afs_block_size);
|
|
size2 = Perv.min(file.ff_size - off + size, self.afs_super.afs_block_size);
|
|
off2 = (off+size);
|
|
|
|
while (off2 < file.ff_size) {
|
|
/*
|
|
** First the chunk to read
|
|
*/
|
|
stat = self.read_file(file, off2, size2, buf2);
|
|
|
|
if (stat != Status.STD_OK) {
|
|
throw stat;
|
|
}
|
|
/*
|
|
** Now write the buffer to the shifted
|
|
** position.
|
|
*/
|
|
|
|
stat = self.modify_file(file, (off2 - size), size2, buf2);
|
|
|
|
if (stat != Status.STD_OK) {
|
|
throw stat;
|
|
}
|
|
off2 = off2 + size2;
|
|
size2 = Perv.min(file.ff_size - off2, self.afs_super.afs_block_size);
|
|
}
|
|
/*
|
|
** Adjust the new size.
|
|
*/
|
|
|
|
self.modify_size(file,(file.ff_size - size));
|
|
stat = self.release_file(file,commit);
|
|
file=undefined;
|
|
if (stat != Status.STD_OK) {
|
|
throw stat;
|
|
}
|
|
} else {
|
|
/*
|
|
** Create a new file, copy the content of the
|
|
** original one, but shift the part from (off+size)
|
|
** to (off).
|
|
*/
|
|
/*
|
|
** First get a new i-node==object number
|
|
*/
|
|
obj2=self.get_freeobjnum();
|
|
size2 = file.ff_size - size;
|
|
file2 = Afs.Afs_file(obj2,Net.uniqport(),size2,self.time(),Afs.AFS_MAXLIVE,
|
|
Afs_file_state.FF_unlocked,Afs.Disk(),true);
|
|
file2.lock();
|
|
stat = self.create_file_inode(file2,false);
|
|
if (stat != Status.STD_OK) {
|
|
file2.unlock();
|
|
throw stat;
|
|
}
|
|
cap=
|
|
Net.Capability(self.afs_super.afs_putport,
|
|
Net.prv_encode(obj2,Rights.PRV_ALL_RIGHTS,file2.ff_random));
|
|
/*
|
|
** Copy the original data
|
|
*/
|
|
buf2 = Buf.Buffer(self.afs_super.afs_block_size);
|
|
|
|
var co = 0;
|
|
var cs = Perv.min(off,self.afs_super.afs_block_size);
|
|
/*
|
|
** First the part up to the off position.
|
|
** (Not shifted).
|
|
*/
|
|
while (cs>0) {
|
|
/*
|
|
** First the chunk to read
|
|
*/
|
|
|
|
stat = self.read_file(file,co,cs,buf2);
|
|
|
|
if (stat != Status.STD_OK) {
|
|
file2.unlock();
|
|
throw stat;
|
|
}
|
|
/*
|
|
** Now write the buffer
|
|
*/
|
|
|
|
stat = self.modify_file(file2,co,cs,buf2);
|
|
if (stat != Status.STD_OK) {
|
|
file2.unlock();
|
|
throw stat;
|
|
}
|
|
co = co + cs;
|
|
cs = Perv.min((off - co),self.afs_super.afs_block_size);
|
|
}
|
|
/*
|
|
** Now the shifted part up to the end of the file.
|
|
*/
|
|
cs = Perv.min((file2.ff_size - co), self.afs_super.afs_block_size);
|
|
|
|
while (co < file2.ff_size) {
|
|
/*
|
|
** First the chunk to read
|
|
*/
|
|
|
|
stat = self.read_file(file, (co + size), cs, buf2);
|
|
if (stat != Status.STD_OK) {
|
|
file2.unlock();
|
|
throw stat;
|
|
}
|
|
/*
|
|
** Now write the buffer to the shifted position.
|
|
*/
|
|
|
|
stat = self.modify_file(file2, co, cs, buf2);
|
|
|
|
if (stat != Status.STD_OK) {
|
|
file2.unlock();
|
|
throw stat;
|
|
}
|
|
co = co + cs;
|
|
cs = Perv.min((file2.ff_size - co), self.afs_super.afs_block_size);
|
|
}
|
|
stat = self.release_file(file2, commit);
|
|
if (stat != Status.STD_OK) {
|
|
throw stat;
|
|
}
|
|
self.release_file(file, Afs_commit_flag.AFS_UNCOMMIT);
|
|
file=undefined;
|
|
}
|
|
stat=Status.STD_OK;
|
|
callback(stat,cap);
|
|
}
|
|
],function (e) {
|
|
if (file!=undefined) self.release_file(file,Afs_commit_flag.AFS_UNCOMMIT);
|
|
if (typeof e != 'number') {Io.printstack(e,'Afs_server_rpc.afs_delete_data');}
|
|
if (typeof e == 'number') callback(e,undefined); else callback(Status.STD_SYSERR,undefined);
|
|
});
|
|
};
|
|
|
|
/** Destroy a file object.
|
|
*
|
|
* @param {privat} priv
|
|
* @param {function((Status.STD_OK|*))} callback return status
|
|
*/
|
|
afs_server_rpc.prototype.afs_destroy_file =function (priv,callback) {
|
|
var self = this;
|
|
var stat = Status.STD_UNKNOWN;
|
|
var obj = Net.prv_number(priv);
|
|
var rights = Net.prv_rights(priv);
|
|
var file;
|
|
Sch.ScheduleBlock([
|
|
function () {
|
|
if (obj > 0) {
|
|
self.acquire_file(obj,function (_stat,_file) {
|
|
stat = _stat;
|
|
file = _file;
|
|
});
|
|
} else
|
|
stat=Status.STD_CAPBAD;
|
|
},
|
|
function () {
|
|
if ((Net.prv_decode(priv, file.ff_random) == false) ||
|
|
(Net.rights_req(rights,[Rights.AFS_RGT_DESTROY])== false)) {
|
|
throw Status.STD_DENIED;
|
|
}
|
|
if (file.ff_state == Afs_file_state.FF_unlocked) {
|
|
|
|
stat = self.delete_file_inode(file);
|
|
if (stat != Status.STD_OK) {
|
|
throw stat;
|
|
}
|
|
stat = Status.STD_OK;
|
|
} else {
|
|
stat = self.delete_file_inode(file);
|
|
if (stat != Status.STD_OK) {
|
|
throw stat;
|
|
}
|
|
self.release_file(file, Afs_commit_flag.AFS_UNCOMMIT);
|
|
file=undefined;
|
|
stat = Status.STD_OK;
|
|
}
|
|
callback(stat);
|
|
}
|
|
],function (e) {
|
|
if (file!=undefined) self.release_file(file,Afs_commit_flag.AFS_UNCOMMIT);
|
|
if (typeof e != 'number') {Io.printstack(e,'Afs_server_rpc.afs_destroy_file');}
|
|
if (typeof e == 'number') callback(e); else callback(Status.STD_SYSERR);
|
|
});
|
|
};
|
|
|
|
/** AFS Info Request
|
|
*
|
|
* @param {privat} priv
|
|
* @param {function((Status.STD_OK|*),string)} callback return status,info
|
|
*/
|
|
afs_server_rpc.prototype.afs_info =function (priv,callback) {
|
|
var self=this;
|
|
var stat;
|
|
var file;
|
|
var info='';
|
|
var obj = Net.prv_number(priv);
|
|
var rights = Net.prv_rights(priv);
|
|
Sch.ScheduleBlock([
|
|
function () {
|
|
if (obj > 0) {
|
|
self.acquire_file(obj,function (_stat,_file) {
|
|
stat = _stat;
|
|
file = _file;
|
|
});
|
|
} else {
|
|
file=undefined;
|
|
stat=Status.STD_OK;
|
|
}
|
|
},
|
|
function () {
|
|
if (stat != Status.STD_OK) {
|
|
throw stat;
|
|
}
|
|
if (file!=undefined) {
|
|
if ((Net.prv_decode(priv, file.ff_random) == false)) {
|
|
throw Status.STD_DENIED;
|
|
}
|
|
info = '- '+file.ff_size+' bytes';
|
|
self.release_file(file, Afs_commit_flag.AFS_UNCOMMIT);
|
|
file=undefined;
|
|
stat = Status.STD_OK;
|
|
} else {
|
|
/*
|
|
** Super capability
|
|
*/
|
|
if ((Net.prv_decode(priv, self.afs_super.afs_checkfield) == false)) {
|
|
throw Status.STD_DENIED;
|
|
}
|
|
info='Atomic Filesystem Server';
|
|
stat=Status.STD_OK;
|
|
}
|
|
callback(stat,info)
|
|
}
|
|
],function (e) {
|
|
if (file!=undefined) self.release_file(file,Afs_commit_flag.AFS_UNCOMMIT);
|
|
if (typeof e != 'number') {Io.printstack(e,'Afs_server_rpc.afs_info');}
|
|
if (typeof e == 'number') callback(e,''); else callback(Status.STD_SYSERR,'');
|
|
});
|
|
};
|
|
|
|
/** AFS Exit Request
|
|
* @param {privat} [priv]
|
|
*
|
|
* @returns {(Status.STD_OK|*)}
|
|
*/
|
|
afs_server_rpc.prototype.afs_exit =function (priv) {
|
|
var self=this;
|
|
var stat=Status.STD_OK;
|
|
if (priv!=undefined) {
|
|
var obj = Net.prv_number(priv);
|
|
var rights = Net.prv_rights(priv);
|
|
if (obj!=0 || !Net.prv_decode(priv,self.afs_super.afs_checkfield)) return Status.STD_DENIED;
|
|
}
|
|
Io.out('[AFS] Writing live table...');
|
|
stat=self.live_write();
|
|
return stat;
|
|
};
|
|
|
|
/** AFS Synchronize Request
|
|
*
|
|
* @returns {Status.STD_OK|*}
|
|
*/
|
|
afs_server_rpc.prototype.afs_sync =function () {
|
|
var self=this;
|
|
var stat,stat1,stat2;
|
|
Io.out('[AFS] Syncing discs...');
|
|
self.afs_super.lock();
|
|
self.inode_cache_entry.fse_state = Afs_file_state.FF_locked;
|
|
stat1=self.cache_inode.cache_sync();
|
|
stat2=self.cache_data.cache_sync();
|
|
self.inode_cache_entry.fse_state = Afs_file_state.FF_unlocked;
|
|
Io.out('[AFS] Compacting freelist...');
|
|
self.freeblocks.free_compact();
|
|
/*
|
|
** Synchronize disk
|
|
*/
|
|
self.disk_sync();
|
|
self.afs_super.unlock();
|
|
if (stat1 != Status.STD_OK) return stat1; else return stat2;
|
|
|
|
};
|
|
|
|
|
|
/** AFS Status Request
|
|
*
|
|
* @param {privat} [priv]
|
|
* @param {function((Status.STD_OK|*),string)} [callback] return status,info
|
|
* @returns {string}
|
|
*/
|
|
afs_server_rpc.prototype.afs_stat = function (priv,callback) {
|
|
var self=this;
|
|
var stat;
|
|
|
|
function printstat() {
|
|
var block_size = self.afs_super.afs_block_size;
|
|
var str = '';
|
|
var res = self.freeblocks.free_info();
|
|
var holes = res[0];
|
|
var freespace = res[1];
|
|
var holestat = res[2];
|
|
var usedspace = self.afs_super.afs_nblocks - freespace;
|
|
var uncomm = 0;
|
|
var unlock = 0;
|
|
Hashtbl.iter(self.cache_data.fsc_table, function (addr, fse) {
|
|
if (fse.fse_state == Afs_file_state.FF_unlocked) unlock++;
|
|
if (fse.fse_state == Afs_file_state.FF_commit) uncomm++;
|
|
});
|
|
str = str + 'Cache statistics: Inode Cache\n' + self.cache_inode.cache_stat() + '\n';
|
|
str = str + 'Cache statistics: Data Cache\n' + self.cache_data.cache_stat() + '\n';
|
|
str = str + 'File system statistics\n';
|
|
str = str + ' Free: ' + (freespace * block_size) + ' bytes\n';
|
|
str = str + ' Used: ' + (usedspace * block_size) + ' bytes\n';
|
|
str = str + ' Files: ' + (self.afs_super.afs_nused) + '\n';
|
|
str = str + ' Uncommited: ' + (uncomm) + '\n';
|
|
str = str + ' Unlocked: ' + (unlock) + '\n';
|
|
str = str + 'Server statistics\n';
|
|
str = str + ' Read: ' + (self.stats.op_read) + '\n';
|
|
str = str + ' Modify: ' + (self.stats.op_modify) + '\n';
|
|
str = str + ' Create: ' + (self.stats.op_create) + '\n';
|
|
str = str + ' Touch: ' + (self.stats.op_touch) + '\n';
|
|
str = str + ' Age: ' + (self.stats.op_age) + '\n';
|
|
str = str + ' Destroy: ' + (self.stats.op_destroy) + '\n';
|
|
str = str + 'Free list statistics\n';
|
|
str = str + ' Comp. Thr.: ' + (self.freeblocks.fbs_compacthres) + '\n';
|
|
str = str + ' Holes: ' + (holes) + '\n';
|
|
for (var i = 0; i < holestat.length; i++) {
|
|
var hole = holestat[i];
|
|
var low, high, count;
|
|
low = hole[0];
|
|
high = hole[1];
|
|
count = hole[2];
|
|
str = str + ' Free holes from ' + (low * block_size) + ' to ' + (high * block_size) + ' bytes: ' + count + '\n';
|
|
}
|
|
self.afs_super.unlock();
|
|
return str;
|
|
}
|
|
if (!self.afs_super.try_lock()) {
|
|
if (callback) {
|
|
callback(Status.STD_NOTNOW,'');
|
|
return '';
|
|
}
|
|
else return '';
|
|
}
|
|
if (priv!=undefined) {
|
|
var obj = Net.prv_number(priv);
|
|
var rights = Net.prv_rights(priv);
|
|
var file;
|
|
Sch.ScheduleBlock([
|
|
function () {
|
|
if (obj > 0) {
|
|
self.acquire_file(obj,function (_stat,_file) {
|
|
stat = _stat;
|
|
file = _file;
|
|
});
|
|
} else {
|
|
file=undefined;
|
|
stat=Status.STD_OK;
|
|
}
|
|
},
|
|
function () {
|
|
if (stat != Status.STD_OK) {
|
|
throw stat;
|
|
}
|
|
if (file!=undefined) {
|
|
if ((Net.prv_decode(priv, file.ff_random) == false)) {
|
|
self.release_file(file, Afs_commit_flag.AFS_UNCOMMIT);
|
|
throw Status.STD_DENIED;
|
|
}
|
|
self.release_file(file,Afs_commit_flag.AFS_UNCOMMIT);
|
|
file=undefined;
|
|
} else {
|
|
if ((Net.prv_decode(priv, self.afs_super.afs_checkfield) == false)) {
|
|
throw Status.STD_DENIED;
|
|
}
|
|
}
|
|
callback(stat,printstat());
|
|
}
|
|
],function (e) {
|
|
if (file!=undefined) self.release_file(file,Afs_commit_flag.AFS_UNCOMMIT);
|
|
if (typeof e == 'number') callback(e,''); else {
|
|
Io.printstack(e,'afs_srv_rpc.afs_stat');
|
|
callback(Status.STD_SYSERR,'');
|
|
}
|
|
});
|
|
return '';
|
|
} else {
|
|
return printstat();
|
|
}
|
|
};
|
|
|
|
|
|
/** AFS Start the RPC server
|
|
*
|
|
* @param {number} index
|
|
* @param {taskscheduler} scheduler
|
|
*/
|
|
afs_server_rpc.prototype.afs_start_server = function (index,scheduler) {
|
|
var afs = this;
|
|
var server = function () {
|
|
// Server
|
|
var self = this;
|
|
var rpc = afs.rpc;
|
|
var port = afs.afs_super.afs_getport;
|
|
var router = rpc.router;
|
|
var rpcio = router.pkt_get();
|
|
var dying=false;
|
|
|
|
this.init = function () {
|
|
Io.out('[AFS'+index+'] Starting RPC Server with public port '+Net.Print.port(afs.afs_super.afs_putport));
|
|
router.add_port(port);
|
|
};
|
|
|
|
this.request = function () {
|
|
Io.log((log<10)||('[AFS'+index+'] request'));
|
|
rpcio.init();
|
|
rpcio.operation = Rpc.Operation.GETREQ;
|
|
rpcio.header.h_port = port;
|
|
rpcio.header.h_status=undefined;
|
|
rpcio.header.h_command=undefined;
|
|
rpcio.header.h_priv=undefined;
|
|
rpc.getreq(rpcio);
|
|
};
|
|
|
|
this.service = function () {
|
|
var ss,sc,stat,info,size,flag,off,buf;
|
|
buf=Buf.Buffer();
|
|
Io.log((log<1)||('[AFS'+index+'] service: '+Net.Print.header(rpcio.header)));
|
|
assert((rpcio.index!=-1) ||'RPCIO invalid');
|
|
switch (rpcio.header.h_command) {
|
|
case Command.AFS_SIZE:
|
|
/*
|
|
** +---
|
|
* |===
|
|
* | size(int32)
|
|
* +---
|
|
*/
|
|
Sch.ScheduleBlock([
|
|
function () {
|
|
afs.afs_file_size(rpcio.header.h_priv,function (_stat,_size) {
|
|
rpcio.header.h_status=_stat;
|
|
Buf.buf_init(rpcio);
|
|
Buf.buf_put_int32(rpcio,_size);
|
|
});
|
|
}
|
|
]);
|
|
break;
|
|
case Command.AFS_CREATE:
|
|
/*
|
|
* +---
|
|
* | off(int32)
|
|
* | size(int32)
|
|
* | flag(int16)
|
|
* | data
|
|
* |===
|
|
* +---
|
|
*/
|
|
rpcio.pos=0;
|
|
off = Buf.buf_get_int32(rpcio);
|
|
size = Buf.buf_get_int32(rpcio);
|
|
flag = Buf.buf_get_int16(rpcio);
|
|
Buf.buf_init(buf);
|
|
Buf.buf_get_buf(rpcio,buf,0,size);
|
|
Buf.buf_init(rpcio);
|
|
Sch.ScheduleBlock([
|
|
function () {
|
|
afs.afs_create_file(rpcio.header.h_priv, buf, size, flag, function (_stat, _cap) {
|
|
if (_stat == Status.STD_OK) Net.Copy.private(_cap.cap_priv, rpcio.header.h_priv);
|
|
rpcio.header.h_status = _stat;
|
|
});
|
|
}]);
|
|
break;
|
|
case Command.AFS_MODIFY:
|
|
/*
|
|
* +---
|
|
* | off(int32)
|
|
* | size(int32)
|
|
* | flag(int16)
|
|
* | data
|
|
* |===
|
|
* +---
|
|
*/
|
|
rpcio.pos=0;
|
|
off = Buf.buf_get_int32(rpcio);
|
|
size = Buf.buf_get_int32(rpcio);
|
|
flag = Buf.buf_get_int16(rpcio);
|
|
Buf.buf_init(buf);
|
|
Buf.buf_get_buf(rpcio,buf,0,size);
|
|
Buf.buf_init(rpcio);
|
|
Sch.ScheduleBlock([
|
|
function () {
|
|
afs.afs_modify_file(rpcio.header.h_priv, buf, off, size, flag, function (_stat, _cap) {
|
|
if (_stat == Status.STD_OK) Net.Copy.private(_cap.cap_priv, rpcio.header.h_priv);
|
|
rpcio.header.h_status = _stat;
|
|
});
|
|
}]);
|
|
break;
|
|
case Command.AFS_READ:
|
|
/*
|
|
** +---
|
|
* | off(int32)
|
|
* | size(int32)
|
|
* |===
|
|
* | size(int32)
|
|
* | data
|
|
* +---
|
|
*/
|
|
rpcio.pos=0;
|
|
off = Buf.buf_get_int32(rpcio);
|
|
size = Buf.buf_get_int32(rpcio);
|
|
Io.log((log<1)||('AFS_READ: off='+off+' size='+size));
|
|
Buf.buf_init(rpcio);
|
|
Buf.buf_init(buf);
|
|
Sch.ScheduleBlock([
|
|
function () {
|
|
afs.afs_read_file(rpcio.header.h_priv,buf,off,size,function (_stat,_size) {
|
|
Buf.buf_put_int32(rpcio,_size);
|
|
Buf.buf_put_buf(rpcio,buf);
|
|
rpcio.header.h_status=_stat;
|
|
});
|
|
}]);
|
|
break;
|
|
case Command.AFS_INSERT:
|
|
/*
|
|
** +---
|
|
* | off(int32)
|
|
* | size(int32)
|
|
* | flag(int16)
|
|
* | data
|
|
* |===
|
|
* +---
|
|
*/
|
|
rpcio.pos=0;
|
|
off = Buf.buf_get_int32(rpcio);
|
|
size = Buf.buf_get_int32(rpcio);
|
|
flag = Buf.buf_get_int16(rpcio);
|
|
Buf.buf_init(buf);
|
|
Buf.buf_get_buf(rpcio,buf,0,size);
|
|
Buf.buf_init(rpcio);
|
|
Sch.ScheduleBlock([
|
|
function () {
|
|
afs.afs_insert_data(rpcio.header.h_priv, buf, off, size, flag, function (_stat, _cap) {
|
|
if (_stat == Status.STD_OK) Net.Copy.private(_cap.cap_priv, rpcio.header.h_priv);
|
|
rpcio.header.h_status = _stat;
|
|
});
|
|
}]);
|
|
break;
|
|
case Command.AFS_DELETE:
|
|
/*
|
|
** +---
|
|
* | off(int32)
|
|
* | size(int32)
|
|
* | flag(int16)
|
|
* |===
|
|
* +---
|
|
*/
|
|
rpcio.pos=0;
|
|
off = Buf.buf_get_int32(rpcio);
|
|
size = Buf.buf_get_int32(rpcio);
|
|
flag = Buf.buf_get_int16(rpcio);
|
|
Buf.buf_init(rpcio);
|
|
Sch.ScheduleBlock([
|
|
function () {
|
|
afs.afs_delete_data(rpcio.header.h_priv,off,size,flag,function(_stat,_cap) {
|
|
if (_stat==Status.STD_OK) Net.Copy.private(_cap.cap_priv,rpcio.header.h_priv);
|
|
rpcio.header.h_status=sc.stat;
|
|
});
|
|
}]);
|
|
break;
|
|
case Command.AFS_SYNC:
|
|
/*
|
|
** +---
|
|
* |===
|
|
* +---
|
|
*/
|
|
stat = afs.afs_sync();
|
|
rpcio.header.h_status=stat;
|
|
break;
|
|
case Command.STD_DESTROY:
|
|
/*
|
|
** +---
|
|
* |===
|
|
* +---
|
|
*/
|
|
Buf.buf_init(rpcio);
|
|
Sch.ScheduleBlock([
|
|
function () {
|
|
afs.afs_destroy_file(rpcio.header.h_priv, function (_stat) {
|
|
rpcio.header.h_status = _stat;
|
|
});
|
|
}]);
|
|
break;
|
|
case Command.STD_INFO:
|
|
/*
|
|
** +---
|
|
* |===
|
|
* | info(string)
|
|
* +---
|
|
*/
|
|
Buf.buf_init(rpcio);
|
|
Sch.ScheduleBlock([
|
|
function () {
|
|
afs.afs_info(rpcio.header.h_priv, function (_stat, _info) {
|
|
rpcio.header.h_status = _stat;
|
|
if (_stat == Status.STD_OK) Buf.buf_put_string(rpcio, _info);
|
|
});
|
|
}]);
|
|
break;
|
|
case Command.STD_STATUS:
|
|
/*
|
|
** +---
|
|
* |===
|
|
* | info(string)
|
|
* +---
|
|
*/
|
|
Buf.buf_init(rpcio);
|
|
Sch.ScheduleBlock([
|
|
function () {
|
|
afs.afs_stat(rpcio.header.h_priv, function (_stat, _info) {
|
|
rpcio.header.h_status = _stat;
|
|
if (_stat == Status.STD_OK) Buf.buf_put_string(rpcio, _info);
|
|
});
|
|
}]);
|
|
break;
|
|
case Command.STD_RESTRICT:
|
|
/*
|
|
* ----------
|
|
* mask (int16)
|
|
* ----------
|
|
* priv (privat)
|
|
* ----------
|
|
*/
|
|
var mask = Buf.buf_get_int16(rpcio);
|
|
Buf.buf_init(rpcio);
|
|
Sch.ScheduleBlock([
|
|
function () {
|
|
afs.afs_restrict(rpcio.header.h_priv, mask, function (_stat, _priv) {
|
|
rpcio.header.h_status = _stat;
|
|
if (_stat == Status.STD_OK) Buf.buf_put_priv(rpcio, _priv);
|
|
});
|
|
}]);
|
|
break;
|
|
|
|
case Command.STD_TOUCH:
|
|
/*
|
|
** +---
|
|
* |===
|
|
* +---
|
|
*/
|
|
Buf.buf_init(rpcio);
|
|
Sch.ScheduleBlock([
|
|
function () {
|
|
afs.afs_touch_file(rpcio.header.h_priv, function (_stat) {
|
|
rpcio.header.h_status = _stat;
|
|
});
|
|
}]);
|
|
break;
|
|
|
|
case Command.STD_AGE:
|
|
/*
|
|
** +---
|
|
* |===
|
|
* +---
|
|
*/
|
|
Buf.buf_init(rpcio);
|
|
Sch.ScheduleBlock([
|
|
function () {
|
|
afs.afs_age(rpcio.header.h_priv, function (_stat) {
|
|
rpcio.header.h_status = _stat;
|
|
});
|
|
}]);
|
|
break;
|
|
case Command.STD_EXIT:
|
|
/*
|
|
** +---
|
|
* |===
|
|
* +---
|
|
*/
|
|
Buf.buf_init(rpcio);
|
|
stat=afs.afs_exit(rpcio.header.h_priv);
|
|
rpcio.header.h_status=stat;
|
|
if (stat==Status.STD_OK) dying=true;
|
|
break;
|
|
default:
|
|
rpcio.header.h_status=Status.STD_COMBAD;
|
|
Buf.buf_init(rpcio);
|
|
}
|
|
|
|
};
|
|
|
|
this.reply = function () {
|
|
Io.log((log<1)||('[AFS'+index+'] reply: '+Net.Print.header(rpcio.header)));
|
|
rpc.putrep(rpcio);
|
|
assert((rpcio.index!=-1) ||'RPCIO invalid');
|
|
};
|
|
|
|
this.onexit = function () {
|
|
// TODO exit context?
|
|
};
|
|
|
|
this.transitions = function () {
|
|
var trans;
|
|
trans =
|
|
[
|
|
[undefined, this.init],
|
|
[this.init, this.request],
|
|
[this.request, this.service],
|
|
[this.service, this.reply],
|
|
[this.reply, this.request, function (self) {return !dying}],
|
|
[this.reply, this.onexit, function (self) {return dying}]
|
|
];
|
|
return trans;
|
|
};
|
|
this.context = Sch.TaskContext('AFS'+index+' '+Net.Print.port(port), self);
|
|
};
|
|
var proc1 = new server();
|
|
scheduler.Add(proc1.context);
|
|
};
|
|
|
|
module.exports = {
|
|
afs_server_rpc:afs_server_rpc
|
|
};
|