diff --git a/.gitignore b/.gitignore index a826c87..e8fde75 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ *.o xrxs +realms/ diff --git a/aux.h b/aux.h index d926712..b492f9f 100644 --- a/aux.h +++ b/aux.h @@ -1,4 +1,14 @@ -typedef enum { CTL = 1, USERS, CARTS, SLOT, DATA, REALMS, UNIVERSE } FileType; +typedef enum { + CTL = 1, + USERS, + CARTS, + SLOT, + SPRITE_DATA, + AUDIO_DATA, + TEXT_DATA, + REALMS, + UNIVERSE +} FileType; typedef struct Aux { FileType type; diff --git a/realm.c b/realm.c index 38678fe..d079c9d 100644 --- a/realm.c +++ b/realm.c @@ -35,10 +35,14 @@ Realm* parse_realm(char* name) { scat(file, "/realm"); f = fopen(file, "r"); - if (fgets(buf, 256, f)) { - self = malloc(sizeof(Realm)); - sscanf(buf, "%hu %llu", &(self->max), &(self->password)); - fclose(f); + if (f != nil) { + if (fgets(buf, 256, f)) { + self = malloc(sizeof(Realm)); + sscanf(buf, "%hu %llu", &(self->max), &(self->password)); + fclose(f); + } else { + return nil; + } } else { return nil; } @@ -58,6 +62,32 @@ Realm* find_realm(UserInfo* table, char* name) { return u->realm; u++; } + return nil; } -void save_realm(Realm* self) {} \ No newline at end of file +void save_realm(Realm* self) { + FILE* f; + char path[64]; + char file[64]; + scat(path, "realms/"); + scat(path, self->name); + scpy(path, file, 64); + + scat(file, "/realm"); + f = fopen(file, "w"); + if (f != nil) { + fprintf(f, "%hu %llu", self->max, self->password); + fclose(f); + save_universe(self->universe, self->name); + } +} + +void destroy_realm(Realm* self) { + if (self != nil) { + if (self->universe != nil) { + destroy_universe(self->universe); + } + free(self); + self = nil; + } +} \ No newline at end of file diff --git a/user.c b/user.c index e69de29..616bcc0 100644 --- a/user.c +++ b/user.c @@ -0,0 +1,100 @@ +#include +#include +#include "util.h" +#include "cart.h" +#include "realm.h" +#include "user.h" + +extern UserInfo users_table[64]; + +UserInfo* find_user(UserInfo* table, char* uname) { + UserInfo* u = table; + int i; + for (i = 0; i < 64; i++) { + if (scmp(uname, u->name)) + return u; + u++; + } + return nil; +} + +int load_cart(UserInfo* table, char* uname, char* cart_name) { + Cart* c = find_cart(table, cart_name); + UserInfo* u = find_user(table, uname); + + if (u == nil) + return 0; + + if (c != nil) { + u->cart = c; + return 1; + } else { + u->cart = create_cart(cart_name); + if (u->cart == nil) + return 0; + else + return 1; + } +} + +int enter_realm(UserInfo* table, char* uname, char* realm_name) { + Realm* r = find_realm(table, realm_name); + UserInfo* u = find_user(table, uname); + int i, j; + + if (u == nil || u->cart == nil) + return 0; + + for (i = j = 0; i < 64; i++) { + if (table[i].realm != nil && scmp(table[i].realm->name, realm_name)) + j++; + } + if (j >= r->max) + return 0; + + if (r != nil) { + u->realm = r; + return 1; + } else { + u->realm = parse_realm(realm_name); + if (u->realm == nil) + return 0; + else + return 1; + } +} + +int leave_realm(UserInfo* table, char* uname) { + UserInfo* u = find_user(table, uname); + Realm* r; + + if (u == nil) + return 0; + + r = u->realm; + if (r == nil) + return 0; + + save_realm(r); + u->realm = nil; + if (find_realm(table, r->name) == nil) + destroy_realm(r); + return 1; +} + +int unload_cart(UserInfo* table, char* uname) { + UserInfo* u = find_user(table, uname); + Cart* c; + + if (u == nil) + return 0; + + c = u->cart; + if (c == nil) + return 0; + + u->cart = nil; + if (find_cart(table, c->name) == nil) + destroy_cart(c); + return 1; +} \ No newline at end of file diff --git a/user.h b/user.h index 4b6a390..09c5cb3 100644 --- a/user.h +++ b/user.h @@ -7,7 +7,8 @@ typedef struct UserInfo { Realm* realm; } UserInfo; -int load_cart(char* uname, char* cart_name); -int enter_realm(char* uname, char* realm_name); -int leave_realm(char* uname, Realm* realm); -int unload_cart(char* uname, Cart* cart); +UserInfo* find_user(UserInfo* table, char* uname); +int load_cart(UserInfo* table, char* uname, char* cart_name); +int enter_realm(UserInfo* table, char* uname, char* realm_name); +int leave_realm(UserInfo* table, char* uname); +int unload_cart(UserInfo* table, char* uname); diff --git a/util.c b/util.c index 5a9d080..c56a5c5 100644 --- a/util.c +++ b/util.c @@ -138,4 +138,49 @@ char* read_chars(char* path) { fclose(f); return buf; } +} + +void strreverse(char* begin, char* end) { + + char aux; + + while (end > begin) + + aux = *end, *end-- = *begin, *begin++ = aux; +} + +void itoa(int value, char* str, int base) { + + static char num[] = "0123456789abcdefghijklmnopqrstuvwxyz"; + + char* wstr = str; + + int sign; + + // Validate base + + if (base < 2 || base > 35) { + *wstr = '\0'; + return; + } + + // Take care of sign + + if ((sign = value) < 0) + value = -value; + + // Conversion. Number is reversed. + + do + *wstr++ = num[value % base]; + while (value /= base); + + if (sign < 0) + *wstr++ = '-'; + + *wstr = '\0'; + + // Reverse string + + strreverse(str, wstr - 1); } \ No newline at end of file diff --git a/util.h b/util.h index 349f31c..e36dd0b 100644 --- a/util.h +++ b/util.h @@ -14,4 +14,5 @@ char* scat(char* dst, const char* src); int ssin(char* str, char* substr); char* ccat(char* dst, char c); char* read_bytes(char* path); -char* read_chars(char* path); \ No newline at end of file +char* read_chars(char* path); +void itoa(int, char*, int); \ No newline at end of file diff --git a/xrxs.c b/xrxs.c index 887f7f5..39fff16 100644 --- a/xrxs.c +++ b/xrxs.c @@ -6,6 +6,7 @@ #include #include #include +#include #include "err.h" #include "command.h" #include "util.h" @@ -15,6 +16,9 @@ #include "realm.h" #include "user.h" +#define CARTSPATH "./carts" +#define REALMSPATH "./realms" + int chatty9p = 1; static Tree* tree; @@ -67,95 +71,29 @@ void login(char* uname, char* password) { int logout(char* uname) { int i; - fprintf(stderr, uname); + UserInfo* u = users_table; + for (i = 0; i < 64; i++) { - if (scmp(uname, users_table[i].name)) { - *(users_table[i].name) = 0; - users_table[i].password = 0; - /* free cart */ - /* free realm */ + if (scmp(uname, u->name)) { + *(u->name) = 0; + u->password = 0; + if (u->realm != nil) + leave_realm(users_table, uname); + if (u->cart != nil) + unload_cart(users_table, uname); return 1; } + u++; } return 0; } -int load(char* uname, char* cart) { - /* 1. get file handle to cartridge file - * 2. make cartridge file available in CART.data for this user - * 3. add cartridge name to user's UserInfo - * 4. if cartridge data dir is not empty, walk it - * 5. for each file in data dir, create corresponding - * data file in DATA/ for this user, grab a file handle, and make - * the data available in DATA.data - */ - return 1; -} +void protect(char* uname, char* password) { + UserInfo* u = find_user(users_table, uname); -int rcreate(char* realm) { // create is taken in the libc header! - /* 1. split input by space -- if 2+ elements, second element - * is the max number of members (default 4) - * 2. check if realm exists; return 0 if it does - * 3. create real files in the realms directory and fill as - * appropriate - */ - return 1; -} - -int protect(char* password) { - /* 1. if current realm has a password already, return 0; - * 2. otherwise, hash the password and put it after the - * member limit in the realm file - */ - return 1; -} - -int enter(char* uname, char* realm) { - /* 1. get password for realm; if none, skip to 3 - * 2. check password for current user against it; - * return 0 if different - * 3. if member limit already met, return 0 - * 4. otherwise, insert username in the realm - * and the realm name in the user's UserInfo - */ - return 1; -} - -int leave(char* uname) { - /* 1. if not in a realm, return 0; - * 2. else remove self from realm file - * and remove realm from user's UserInfo - */ - return 1; -} - -int save(char* uname) { - /* 1. flush this user's universe to the realm; - * maybe this is not needed - */ - return 1; -} - -int reset(char* uname) { - /* 1. save - * 2. leave - * 3. clear this user's password - * 4. the client should now be able to restart execution - * of the cartridge safely - */ - return 1; -} - -int unload(char* uname) { - /* 1. reset - * 2. clear cartridge data from CART->data for this user - * 3. destroy all files in DATA/ for this user - * 4. remove cartridge from UserInfo for thi user - * 5. the client should now be able to unload - * the cartridge from memory safely and restart - * the 'firmware' ROM execution - */ - return 1; + if (u != nil && u->realm != nil) { + u->realm->password = hash(password, 0); + } } void write_ctl(Req* r) { @@ -166,6 +104,9 @@ void write_ctl(Req* r) { for (i = 0; i < r->ifcall.count && *c != ' ' && *c != '\n'; i++) { ccat(cmd, *c++); } + if (*c == ' ') + c++; + fprintf(stderr, cmd); uvlong const cmd_hashv = hash(cmd, 0); switch (cmd_hashv) { @@ -173,19 +114,19 @@ void write_ctl(Req* r) { login(r->fid->uid, c); break; case LOAD: - // load(r->fid->uid, c); + load_cart(users_table, r->fid->uid, c); break; case CREATE: - // rcreate(c); + create_realm(c); break; case PROTECT: - // protect(c); + protect(r->fid->uid, c); break; case ENTER: - // enter(r->fid->uid, c); + enter_realm(users_table, r->fid->uid, c); break; case LEAVE: - // leave(r->fid->uid); + leave_realm(users_table, r->fid->uid); break; case LOGOUT: logout(r->fid->uid); @@ -197,7 +138,7 @@ void write_ctl(Req* r) { // reset(r->fid->uid); break; case UNLOAD: - // unload(r->fid->uid); + unload_cart(users_table, r->fid->uid); break; } r->ofcall.count = r->ifcall.count; @@ -205,6 +146,39 @@ void write_ctl(Req* r) { respond(r, nil); } +void write_universe(Req* r) { + char key[16] = {0}; + char value[64] = {0}; + char* c = r->ifcall.data; + UserInfo* u = find_user(users_table, r->fid->uid); + Atom* a; + int i; + + for (i = 0; i < 15 && i < r->ifcall.count && *c != ' ' && *c != '\n'; i++) { + ccat(key, *c++); + } + c++; + for (i = 0; i < 63 && i < r->ifcall.count && *c != ' ' && *c != '\n'; i++) { + ccat(value, *c++); + } + + if (u != nil && u->realm != nil && u->realm->universe != nil) { + a = get_atom(u->realm->universe, key); + if (a != nil) { + scpy(value, a->value, 64); + } else { + a = malloc(sizeof(Atom)); + scpy(key, a->name, 16); + scpy(value, a->value, 64); + a->next = nil; + set_atom(u->realm->universe, a); + } + } + r->ofcall.count = r->ifcall.count; + r->fid->file->dir.length = r->ifcall.count; + respond(r, nil); +} + void xrxs_write(Req* r) { Aux* a = r->fid->file->aux; switch (a->type) { @@ -212,7 +186,7 @@ void xrxs_write(Req* r) { write_ctl(r); break; case UNIVERSE: - // write_universe(r); + write_universe(r); break; default: respond(r, nil); @@ -244,44 +218,7 @@ void read_users(Req* r) { respond(r, nil); } -void xrxs_read(Req* r) { - Aux* a = r->fid->file->aux; - switch (a->type) { - case USERS: - read_users(r); - break; - case CARTS: - // read_carts(r); - break; - case SLOT: - // read_slot(r); - break; - case DATA: - // read_data(r); - break; - case REALMS: - // read_realms(r); - break; - case UNIVERSE: - // read_universe(r); - break; - default: - respond(r, nil); - break; - } -} - -void fs_destroy_file(File* f) { - Aux* a = f->aux; - if (a && a->data) { - free(a->data); - free(a); - } else if (a) { - free(a); - } -} - -String** listdir(char* path) { +String** list_dir(char* path) { String** self = malloc(128 * sizeof(String*)); DIR* dir; struct dirent* ent; @@ -306,6 +243,131 @@ String** listdir(char* path) { return self; } +void read_carts(Req* r) { + String** carts = list_dir(CARTSPATH); + String** c = carts; + char data[4096] = {0}; + while (*c != nil) { + scat(data, (*c)->base); + ccat(data, '\n'); + c++; + } + readstr(r, data); + respond(r, nil); +} + +void read_slot(Req* r) { + UserInfo* u = find_user(users_table, r->fid->uid); + if (u == nil) + goto end; + + if (u->cart == nil) + goto end; + + readstr(r, u->cart->rom); +end: + respond(r, nil); +} + +void read_data(Req* r, FileType t) { + UserInfo* u = find_user(users_table, r->fid->uid); + + if (u->cart == nil) + goto end; + + switch (t) { + case SPRITE_DATA: + readstr(r, u->cart->sprite_data); + break; + case AUDIO_DATA: + readstr(r, u->cart->audio_data); + break; + case TEXT_DATA: + readstr(r, u->cart->txt_data); + break; + } +end: + respond(r, nil); +} + +void read_realms(Req* r) { + String** realms = list_dir(REALMSPATH); + String** rr = realms; + Realm* realm; + char data[4096] = {0}; + int i, u, m, p; + char ubuf[8] = {0}; + char mbuf[8] = {0}; + char pbuf[2] = {0}; + + while (*rr != nil) { + scat(data, (*rr)->base); + ccat(data, ' '); + + realm = parse_realm((*rr)->base); + m = realm->max; + p = realm->password ? 1 : 0; + + for (i = u = 0; i < 64; i++) { + if ( + users_table[i].realm != nil && + scmp(users_table[i].realm->name, realm->name)) + u++; + } + itoa(u, ubuf, 10); + scat(data, ubuf); + ccat(data, ' '); + itoa(m, mbuf, 10); + scat(data, mbuf); + ccat(data, ' '); + itoa(p, pbuf, 10); + scat(data, pbuf); + ccat(data, '\n'); + rr++; + } + readstr(r, data); + respond(r, nil); +} + +void xrxs_read(Req* r) { + Aux* a = r->fid->file->aux; + switch (a->type) { + case USERS: + read_users(r); + break; + case CARTS: + read_carts(r); + break; + case SLOT: + read_slot(r); + break; + case SPRITE_DATA: + case AUDIO_DATA: + case TEXT_DATA: + read_data(r, a->type); + break; + case REALMS: + read_realms(r); + break; + case UNIVERSE: + // read_universe(r); + break; + default: + respond(r, nil); + break; + } +} + +void fs_destroy_file(File* f) { + Aux* a = f->aux; + if (a && a->data) { + free(a->data); + free(a); + } else if (a) { + free(a); + } +} + Srv fs = {.attach = xrxs_attach, .read = xrxs_read, .write = xrxs_write}; int threadmaybackground(void) { return 1; } @@ -314,7 +376,6 @@ void threadmain(int argc, char* argv[]) { char* mtpt = nil; char* usocket = nil; int i; - String** cart; /* if -h CMD is given, print the hash value of CMD */ if (argc == 3 && scmp(argv[1], "-h")) { @@ -348,16 +409,31 @@ void threadmain(int argc, char* argv[]) { closefile(createfile(tree->root, "users", nil, 0400, create_aux(USERS))); closefile(createfile(tree->root, "slot", nil, 0400, create_aux(SLOT))); closefile(createfile(tree->root, "data", nil, DMDIR | 0500, nil)); + closefile(createfile( + walkfile(tree->root, "data"), + "sprite", + nil, + 0400, + create_aux(SPRITE_DATA))); + closefile(createfile( + walkfile(tree->root, "data"), + "audio", + nil, + 0400, + create_aux(AUDIO_DATA))); + closefile(createfile( + walkfile(tree->root, "data"), + "text", + nil, + 0400, + create_aux(TEXT_DATA))); closefile(createfile(tree->root, "realms", nil, 0400, create_aux(REALMS))); - closefile( - createfile(tree->root, "universe", nil, 0600, create_aux(UNIVERSE))); - /*String** carts = listdir("carts/"); - cart = carts; - - while (*cart) { - // just concatenate the carts into a multiline string, and put it in - CARTS.data - }*/ + closefile(createfile( + tree->root, + "universe", + nil, + DMAPPEND | 0600, + create_aux(UNIVERSE))); if (argc >= 3) { if (mtpt != nil && access(mtpt, AEXIST) < 0 && access(mtpt, AEXIST) < 0)