add config.h, ctl status codes, and delete realm command

This commit is contained in:
Iris Lightshard 2021-08-03 00:53:16 -06:00
parent e9839b1663
commit 4fab56e77f
Signed by: Iris Lightshard
GPG key ID: 3B7FBC22144E6398
12 changed files with 220 additions and 66 deletions

View file

@ -8,16 +8,18 @@ The client is intended to be a specialized [uxn](https://wiki.xxiivv.com/site/ux
This is the working structure of the 9p filesystem: This is the working structure of the 9p filesystem:
* `/ctl`: Write-only control file for inputing system commands * `/ctl`: Read/write control file for inputing system commands. Reading the file shows the status of the last input command: 1 for success, 0 for failure; `logout` is a special case, and the status code will be -1 if it was succesful. the following are valid command syntax:
* `login PW`: Authenticate with `xrxs` -- password is hashed against realm password hash * `login PW`: Authenticate with `xrxs` -- password is hashed against realm password hash.
* `load CART`: Load a cartridge * `logout`: Gracefully remove yourself from the users table.
* `chunk TYPE N`: Load data of type TYPE and chunk number N * `load CART`: Load a cartridge.
* `chunk TYPE N`: Load data of type TYPE and chunk number N.
* `create REALM`: Create a new realm (start a new game) -- must have a cartridge loaded * `create REALM`: Create a new realm (start a new game) -- must have a cartridge loaded
* `protect PW`: Protect the curent realm with a password if you are the master. * `protect PW`: Protect the curent realm with a password if you are the master.
* `transfer USER`: Transfer ownership of the realm to another user. * `transfer USER`: Transfer ownership of the realm to another user.
* `enter REALM`: Join an existing realm * `delete REALM`: Delete the realm off the server if you are the master and it is empty.
* `leave`: Leave the current realm * `enter REALM`: Join an existing realm.
* `unload`: Unload the cartridge * `leave`: Leave the current realm.
* `unload`: Unload the cartridge.
* `/users`: Read-only; Self and others in the realm are readable from here, one per line. It contains only yourself before joining a realm. Your username on your machine is used as your username in `xrxs` -- if your name is taken, you will get an error on attaching. * `/users`: Read-only; Self and others in the realm are readable from here, one per line. It contains only yourself before joining a realm. Your username on your machine is used as your username in `xrxs` -- if your name is taken, you will get an error on attaching.
@ -37,6 +39,13 @@ This is the working structure of the 9p filesystem:
* `/grandom`: Read-only, get a random number from 0 to 99 -- These are doled out on a per-realm basis, and the number stays the same until everyone in the realm has had a chance to read it. If you've already read it this round or aren't in a realm, it will be empty. * `/grandom`: Read-only, get a random number from 0 to 99 -- These are doled out on a per-realm basis, and the number stays the same until everyone in the realm has had a chance to read it. If you've already read it this round or aren't in a realm, it will be empty.
## configuration
`config.h` in the source contains the following configuration macros:
* `MAX_USERS`: the maximum number of simultaneous users able to attach to the `xrxs` service
* `DATA_DIR`: the path to the root of the cartridge and realm storage; can be absolute or relative to the `xrxs` executable, but must have the trailing `/`
## realm format ## realm format
Each realm directory on the server should have the following files: Each realm directory on the server should have the following files:

9
cart.c
View file

@ -1,18 +1,19 @@
#include <u.h> #include <u.h>
#include <libc.h> #include <libc.h>
#include "config.h"
#include "util.h" #include "util.h"
#include "user.h" #include "user.h"
#include "cart.h" #include "cart.h"
Cart* create_cart(char* name) { Cart* create_cart(char* name) {
char path[64] = {0}; char path[256] = {0};
char file[64] = {0}; char file[256] = {0};
Cart* cart; Cart* cart;
Blob* cart_data; Blob* cart_data;
scat(path, "carts/"); scat(path, DATA_DIR);
scat(path, name); scat(path, name);
scpy(path, file, 64); scpy(path, file, 256);
ccat(file, '/'); ccat(file, '/');
scat(file, name); scat(file, name);
scat(file, ".rom"); scat(file, ".rom");

View file

@ -5,6 +5,7 @@ typedef enum {
CREATE = 7083959236, CREATE = 7083959236,
PROTECT = 295480618573, PROTECT = 295480618573,
TRANSFER = 11311529048177, TRANSFER = 11311529048177,
DELETE = 7129299147,
ENTER = 195024746, ENTER = 195024746,
LEAVE = 207662601, LEAVE = 207662601,
LOGOUT = 7702552890, LOGOUT = 7702552890,

5
config.h Normal file
View file

@ -0,0 +1,5 @@
/* Maximum number of users on the server */
#define MAX_USERS 64
/* Path to cart/realm storage (must include trailing slash) */
#define DATA_DIR "/home/nilix/src/xrxs/carts/"

25
realm.c
View file

@ -1,6 +1,7 @@
#include <u.h> #include <u.h>
#include <libc.h> #include <libc.h>
#include <stdio.h> #include <stdio.h>
#include "config.h"
#include "util.h" #include "util.h"
#include "user.h" #include "user.h"
#include "cart.h" #include "cart.h"
@ -13,7 +14,7 @@ Realm* create_realm(UserInfo* table, char* uname, char* name) {
char cart[32]; char cart[32];
int max = 4; int max = 4;
char* n = name; char* n = name;
char path[128] = {0}; char path[256] = {0};
if (u == nil || u->cart == nil) if (u == nil || u->cart == nil)
return 0; return 0;
@ -28,7 +29,7 @@ Realm* create_realm(UserInfo* table, char* uname, char* name) {
max = atoi(n); max = atoi(n);
} }
scat(path, "carts/"); scat(path, DATA_DIR);
scat(path, cart); scat(path, cart);
scat(path, "/realms/"); scat(path, "/realms/");
if (open(path, OREAD) < 0) if (open(path, OREAD) < 0)
@ -55,14 +56,14 @@ Realm* create_realm(UserInfo* table, char* uname, char* name) {
Realm* parse_realm(char* cart, char* name) { Realm* parse_realm(char* cart, char* name) {
Realm* self; Realm* self;
FILE* f; FILE* f;
char path[128] = {0}; char path[256] = {0};
char file[128] = {0}; char file[256] = {0};
char buf[256] = {0}; char buf[256] = {0};
scat(path, "carts/"); scat(path, DATA_DIR);
scat(path, cart); scat(path, cart);
scat(path, "/realms/"); scat(path, "/realms/");
scat(path, name); scat(path, name);
scpy(path, file, 128); scpy(path, file, 256);
scat(file, "/realm"); scat(file, "/realm");
@ -85,7 +86,7 @@ Realm* parse_realm(char* cart, char* name) {
return nil; return nil;
} }
scpy(path, file, 128); scpy(path, file, 256);
scat(file, "/universe"); scat(file, "/universe");
self->universe = parse_universe(cart, name); self->universe = parse_universe(cart, name);
return self; return self;
@ -95,7 +96,7 @@ Realm* find_realm(UserInfo* table, char* name) {
UserInfo* u = table; UserInfo* u = table;
int i; int i;
for (i = 0; i < 64; i++) { for (i = 0; i < MAX_USERS; i++) {
if (slen(u->name) > 0 && u->realm != nil && scmp(u->realm->name, name)) if (slen(u->name) > 0 && u->realm != nil && scmp(u->realm->name, name))
return u->realm; return u->realm;
u++; u++;
@ -105,13 +106,13 @@ Realm* find_realm(UserInfo* table, char* name) {
void save_realm(char* cart, Realm* self) { void save_realm(char* cart, Realm* self) {
FILE* f; FILE* f;
char path[128] = {0}; char path[256] = {0};
char file[128] = {0}; char file[256] = {0};
scat(path, "carts/"); scat(path, DATA_DIR);
scat(path, cart); scat(path, cart);
scat(path, "/realms/"); scat(path, "/realms/");
scat(path, self->name); scat(path, self->name);
scpy(path, file, 128); scpy(path, file, 256);
scat(file, "/realm"); scat(file, "/realm");
f = fopen(file, "w"); f = fopen(file, "w");

View file

@ -1,6 +1,7 @@
#include <u.h> #include <u.h>
#include <libc.h> #include <libc.h>
#include <stdio.h> #include <stdio.h>
#include "config.h"
#include "util.h" #include "util.h"
#include "universe.h" #include "universe.h"
@ -14,7 +15,7 @@ Universe* create_universe() {
} }
Universe* parse_universe(char* cart, char* realm_name) { Universe* parse_universe(char* cart, char* realm_name) {
char path[64] = {0}; char path[256] = {0};
char buf[256] = {0}; char buf[256] = {0};
char name[16] = {0}; char name[16] = {0};
char value[64] = {0}; char value[64] = {0};
@ -22,7 +23,7 @@ Universe* parse_universe(char* cart, char* realm_name) {
Atom* a; Atom* a;
Universe* self; Universe* self;
scat(path, "carts/"); scat(path, DATA_DIR);
scat(path, cart); scat(path, cart);
scat(path, "/realms/"); scat(path, "/realms/");
scat(path, realm_name); scat(path, realm_name);
@ -52,12 +53,12 @@ Universe* parse_universe(char* cart, char* realm_name) {
} }
void save_universe(char* cart, Universe* self, char* realm_name) { void save_universe(char* cart, Universe* self, char* realm_name) {
char path[64] = {0}; char path[256] = {0};
FILE* f; FILE* f;
Atom* a; Atom* a;
int i; int i;
scat(path, "carts/"); scat(path, DATA_DIR);
scat(path, cart); scat(path, cart);
scat(path, "/realms/"); scat(path, "/realms/");
scat(path, realm_name); scat(path, realm_name);

View file

@ -4,7 +4,7 @@ typedef struct Atom Atom;
struct Atom { struct Atom {
char name[16]; char name[16];
char value[64]; char value[MAX_USERS];
Atom* next; Atom* next;
}; };

61
user.c
View file

@ -1,6 +1,8 @@
#include <u.h> #include <u.h>
#include <sys/stat.h>
#include <libc.h> #include <libc.h>
#include <stdio.h> #include <stdio.h>
#include "config.h"
#include "util.h" #include "util.h"
#include "cart.h" #include "cart.h"
#include "realm.h" #include "realm.h"
@ -11,7 +13,7 @@ extern UserInfo users_table[64];
UserInfo* find_user(UserInfo* table, char* uname) { UserInfo* find_user(UserInfo* table, char* uname) {
UserInfo* u = table; UserInfo* u = table;
int i; int i;
for (i = 0; i < 64; i++) { for (i = 0; i < MAX_USERS; i++) {
if (scmp(uname, u->name)) if (scmp(uname, u->name))
return u; return u;
u++; u++;
@ -19,6 +21,13 @@ UserInfo* find_user(UserInfo* table, char* uname) {
return nil; return nil;
} }
int* ctl_code_handle(UserInfo* table, char* uname) {
UserInfo* u = find_user(table, uname);
if (u != nil)
return &(u->ctl_code);
return nil;
}
int login(UserInfo* table, char* uname, char* password) { int login(UserInfo* table, char* uname, char* password) {
UserInfo* u = find_user(table, uname); UserInfo* u = find_user(table, uname);
@ -43,7 +52,7 @@ int logout(UserInfo* table, char* uname) {
u->scope = nil; u->scope = nil;
} }
u->random = 0; u->random = -1;
if (u->realm != nil) if (u->realm != nil)
leave_realm(table, uname); leave_realm(table, uname);
@ -104,8 +113,7 @@ int enter_realm(UserInfo* table, char* uname, char* realm_name) {
return 0; return 0;
} }
for (i = 0; i < 64; i++) { for (i = 0; i < MAX_USERS; i++) {
fprintf(stderr, "iterating through users table: slot %d\n", i);
if (table[i].realm != nil && scmp(table[i].realm->name, realm_name)) if (table[i].realm != nil && scmp(table[i].realm->name, realm_name))
j++; j++;
} }
@ -163,3 +171,48 @@ int unload_cart(UserInfo* table, char* uname) {
u->cart = nil; u->cart = nil;
return 1; return 1;
} }
int delete_realm(UserInfo* table, char* uname, char* realm) {
UserInfo* u = find_user(table, uname);
char path[256] = {0};
char file[256] = {0};
Blob* realm_data;
char garbage[32] = {0};
char master[32] = {0};
int i;
if (u == nil || u->cart == nil) {
fprintf(stderr, "no user/cart\n");
return 0;
}
for (i = 0; i < MAX_USERS; i++) {
if (table[i].realm != nil && scmp(table[i].realm->name, realm)) {
fprintf(stderr, "realm not empty\n");
return 0;
}
}
scat(path, DATA_DIR);
scat(path, u->cart->name);
scat(path, "/realms/");
scat(path, realm);
scpy(path, file, 256);
ccat(file, '/');
scat(file, "realm");
fprintf(stderr, "%s\n", file);
realm_data = read_chars(file);
if (realm_data == nil)
return 0;
sscanf(
realm_data->data,
"%u %32s %llu",
(uint*)garbage,
master,
(uvlong*)garbage);
if (scmp(master, uname) && rm_dir(path))
return 1;
else
return 0;
}

3
user.h
View file

@ -7,9 +7,11 @@ typedef struct UserInfo {
Realm* realm; Realm* realm;
char* scope; char* scope;
int random; int random;
int ctl_code;
} UserInfo; } UserInfo;
UserInfo* find_user(UserInfo* table, char* uname); UserInfo* find_user(UserInfo* table, char* uname);
int* ctl_code_handle(UserInfo* table, char* uname);
int login(UserInfo* table, char* uname, char* password); int login(UserInfo* table, char* uname, char* password);
int logout(UserInfo* table, char* uname); int logout(UserInfo* table, char* uname);
int protect_realm(UserInfo* table, char* uname, char* password); int protect_realm(UserInfo* table, char* uname, char* password);
@ -18,3 +20,4 @@ int load_cart(UserInfo* table, char* uname, char* cart_name);
int enter_realm(UserInfo* table, char* uname, char* realm_name); int enter_realm(UserInfo* table, char* uname, char* realm_name);
int leave_realm(UserInfo* table, char* uname); int leave_realm(UserInfo* table, char* uname);
int unload_cart(UserInfo* table, char* uname); int unload_cart(UserInfo* table, char* uname);
int delete_realm(UserInfo* table, char* uname, char* realm);

54
util.c
View file

@ -1,4 +1,5 @@
#include <u.h> #include <u.h>
#include <sys/stat.h>
#include <libc.h> #include <libc.h>
#include <stdio.h> #include <stdio.h>
#include "cart.h" #include "cart.h"
@ -149,6 +150,59 @@ Blob* read_chars(char* path) {
} }
} }
int issymlink(char* name) {
struct stat s;
return lstat(name, &s) >= 0 && S_ISLNK(s.st_mode);
}
int rm_dir(char* f) {
char* name;
int fd, i, j, n, ndir, nname;
Dir* dirbuf;
int fail = 0;
fd = open(f, OREAD);
if (fd < 0) {
return 0;
}
n = dirreadall(fd, &dirbuf);
close(fd);
if (n < 0) {
return 0;
}
nname = strlen(f) + 1 + STATMAX + 1; /* plenty! */
name = malloc(nname);
if (name == 0) {
return 0;
}
ndir = 0;
for (i = 0; i < n; i++) {
snprint(name, nname, "%s/%s", f, dirbuf[i].name);
if (remove(name) != -1 || issymlink(name))
dirbuf[i].qid.type = QTFILE; /* so we won't recurse */
else {
if (dirbuf[i].qid.type & QTDIR)
ndir++;
else
fail = 1;
}
}
if (ndir)
for (j = 0; j < n; j++)
if (dirbuf[j].qid.type & QTDIR) {
snprint(name, nname, "%s/%s", f, dirbuf[j].name);
rmdir(name);
}
if (remove(f) == -1)
fail = 1;
free(name);
free(dirbuf);
return fail ? 0 : 1;
}
void strreverse(char* begin, char* end) { void strreverse(char* begin, char* end) {
char aux; char aux;

1
util.h
View file

@ -17,3 +17,4 @@ char* ccat(char* dst, char c);
Blob* read_bytes(char* path); Blob* read_bytes(char* path);
Blob* read_chars(char* path); Blob* read_chars(char* path);
void itoa(int, char*, int); void itoa(int, char*, int);
int rm_dir(char* path);

91
xrxs.c
View file

@ -7,6 +7,7 @@
#include <dirent.h> #include <dirent.h>
#include <libString.h> #include <libString.h>
#include <string.h> #include <string.h>
#include "config.h"
#include "err.h" #include "err.h"
#include "command.h" #include "command.h"
#include "util.h" #include "util.h"
@ -16,14 +17,11 @@
#include "realm.h" #include "realm.h"
#include "user.h" #include "user.h"
#define CARTSPATH "./carts"
#define REALMSPATH "./realms"
int chatty9p = 1; int chatty9p = 1;
static Tree* tree; static Tree* tree;
static UserInfo users_table[64]; static UserInfo users_table[MAX_USERS];
void xrxs_attach(Req* r) { void xrxs_attach(Req* r) {
/* As it is, once the user detaches, they will stay in the table /* As it is, once the user detaches, they will stay in the table
@ -36,7 +34,7 @@ void xrxs_attach(Req* r) {
char* usr; char* usr;
char* username = r->ifcall.uname; char* username = r->ifcall.uname;
for (i = 0; i < 64; i++) { for (i = 0; i < MAX_USERS; i++) {
usr = users_table[i].name; usr = users_table[i].name;
if (scmp(usr, username)) { if (scmp(usr, username)) {
respond(r, EUNAME); respond(r, EUNAME);
@ -44,6 +42,7 @@ void xrxs_attach(Req* r) {
} }
if (*usr == 0) { if (*usr == 0) {
scpy(username, usr, 32); scpy(username, usr, 32);
users_table[i].random = -1;
vacancy = 1; vacancy = 1;
break; break;
} }
@ -59,6 +58,7 @@ void write_ctl(Req* r) {
char cmd[16] = {0}; char cmd[16] = {0};
char* c = r->ifcall.data; char* c = r->ifcall.data;
int i; int i;
int* code = ctl_code_handle(users_table, r->fid->uid);
for (i = 0; i < r->ifcall.count && *c != ' ' && *c != '\n'; i++) { for (i = 0; i < r->ifcall.count && *c != ' ' && *c != '\n'; i++) {
ccat(cmd, *c++); ccat(cmd, *c++);
@ -71,28 +71,31 @@ void write_ctl(Req* r) {
uvlong const cmd_hashv = hash(cmd, 0); uvlong const cmd_hashv = hash(cmd, 0);
switch (cmd_hashv) { switch (cmd_hashv) {
case LOGIN: case LOGIN:
login(users_table, r->fid->uid, c); *code = login(users_table, r->fid->uid, c);
break; break;
case LOAD: case LOAD:
load_cart(users_table, r->fid->uid, c); *code = load_cart(users_table, r->fid->uid, c);
break; break;
case CHUNK: case CHUNK:
get_chunk(users_table, r->fid->uid, c); *code = get_chunk(users_table, r->fid->uid, c);
break; break;
case CREATE: case CREATE:
create_realm(users_table, r->fid->uid, c); *code = create_realm(users_table, r->fid->uid, c) != nil ? 1 : 0;
break; break;
case PROTECT: case PROTECT:
protect_realm(users_table, r->fid->uid, c); *code = protect_realm(users_table, r->fid->uid, c);
break; break;
case TRANSFER: case TRANSFER:
transfer_realm(users_table, r->fid->uid, c); *code = transfer_realm(users_table, r->fid->uid, c);
break;
case DELETE:
*code = delete_realm(users_table, r->fid->uid, c);
break; break;
case ENTER: case ENTER:
enter_realm(users_table, r->fid->uid, c); *code = enter_realm(users_table, r->fid->uid, c);
break; break;
case LEAVE: case LEAVE:
leave_realm(users_table, r->fid->uid); *code = leave_realm(users_table, r->fid->uid);
break; break;
case LOGOUT: case LOGOUT:
logout(users_table, r->fid->uid); logout(users_table, r->fid->uid);
@ -104,7 +107,7 @@ void write_ctl(Req* r) {
// reset(r->fid->uid); // reset(r->fid->uid);
break; break;
case UNLOAD: case UNLOAD:
unload_cart(users_table, r->fid->uid); *code = unload_cart(users_table, r->fid->uid);
break; break;
} }
r->ofcall.count = r->ifcall.count; r->ofcall.count = r->ifcall.count;
@ -189,26 +192,27 @@ void xrxs_write(Req* r) {
} }
void read_users(Req* r) { void read_users(Req* r) {
char buf[2113] = {0}; String* data = s_new();
int i; int i;
for (i = 0; i < 64; i++) { for (i = 0; i < MAX_USERS; i++) {
if (scmp(users_table[i].name, r->fid->uid)) { if (scmp(users_table[i].name, r->fid->uid)) {
scat(buf, users_table[i].name); s_append(data, users_table[i].name);
ccat(buf, '\n'); s_putc(data, '\n');
break; break;
} }
} }
for (i = 0; i < 64; i++) { for (i = 0; i < MAX_USERS; i++) {
if ( if (
scmp(users_table[i].name, "\0") || scmp(users_table[i].name, "\0") ||
scmp(users_table[i].name, r->fid->uid)) { scmp(users_table[i].name, r->fid->uid)) {
continue; continue;
} }
scat(buf, users_table[i].name); s_append(data, users_table[i].name);
ccat(buf, '\n'); s_putc(data, '\n');
} }
ccat(buf, 0); s_terminate(data);
readstr(r, buf); readstr(r, data->base);
s_free(data);
respond(r, nil); respond(r, nil);
} }
@ -250,8 +254,24 @@ void s_freemany(String** ss) {
free(ss); free(ss);
} }
void read_ctl(Req* r) {
int* code = ctl_code_handle(users_table, r->fid->uid);
char buf[8] = {0};
if (code != nil) {
if (*code) {
strcat(buf, "1\n");
} else {
strcat(buf, "0\n");
}
} else {
strcat(buf, "-1\n");
}
readstr(r, buf);
respond(r, nil);
}
void read_carts(Req* r) { void read_carts(Req* r) {
String** carts = list_dir(CARTSPATH); String** carts = list_dir(DATA_DIR);
String** c = carts; String** c = carts;
String* data = s_new(); String* data = s_new();
while (*c != nil) { while (*c != nil) {
@ -318,7 +338,7 @@ end:
void read_realms(Req* r) { void read_realms(Req* r) {
UserInfo* user = find_user(users_table, r->fid->uid); UserInfo* user = find_user(users_table, r->fid->uid);
char realm_path[128] = {0}; char realm_path[256] = {0};
String** realms; String** realms;
String** rr; String** rr;
Realm* realm; Realm* realm;
@ -346,7 +366,7 @@ void read_realms(Req* r) {
m = realm->max; m = realm->max;
p = realm->password ? 1 : 0; p = realm->password ? 1 : 0;
for (i = u = 0; i < 64; i++) { for (i = u = 0; i < MAX_USERS; i++) {
if ( if (
users_table[i].realm != nil && users_table[i].realm != nil &&
scmp(users_table[i].realm->name, realm->name)) scmp(users_table[i].realm->name, realm->name))
@ -463,22 +483,24 @@ void read_grandom(Req* r) {
int reset = 1; int reset = 1;
int random; int random;
UserInfo* u = find_user(users_table, r->fid->uid); UserInfo* u = find_user(users_table, r->fid->uid);
UserInfo** usrs = malloc(64 * sizeof(UserInfo*)); UserInfo** usrs = malloc(MAX_USERS * sizeof(UserInfo*));
UserInfo* p = users_table; UserInfo* p = users_table;
UserInfo** uu = usrs; UserInfo** uu = usrs;
if (u->realm == nil) if (u->realm == nil) {
respond(r, nil);
return; return;
}
for (i = 0; i < 64; i++) { for (i = 0; i < MAX_USERS; i++) {
if (scmp(p->realm->name, u->realm->name)) { if (scmp(p->realm->name, u->realm->name)) {
*uu++ = p; *uu++ = p;
if (i < 64) if (i < MAX_USERS - 1)
*uu = nil; *uu = nil;
} }
} }
uu = usrs; uu = usrs;
for (i = 0; i < 64; i++) { for (i = 0; i < MAX_USERS; i++) {
if ((*uu) != nil && (*uu)->random >= 0) { if ((*uu) != nil && (*uu)->random >= 0) {
reset = 0; reset = 0;
break; break;
@ -489,7 +511,7 @@ void read_grandom(Req* r) {
srand(rand()); srand(rand());
random = rand() % 100; random = rand() % 100;
uu = usrs; uu = usrs;
for (i = 0; i < 64; i++) { for (i = 0; i < MAX_USERS; i++) {
if ((*uu) != nil) { if ((*uu) != nil) {
(*uu)->random = random; (*uu)->random = random;
} }
@ -505,6 +527,9 @@ void read_grandom(Req* r) {
void xrxs_read(Req* r) { void xrxs_read(Req* r) {
Aux* a = r->fid->file->aux; Aux* a = r->fid->file->aux;
switch (a->type) { switch (a->type) {
case CTL:
read_ctl(r);
break;
case USERS: case USERS:
read_users(r); read_users(r);
break; break;
@ -586,7 +611,7 @@ void threadmain(int argc, char* argv[]) {
tree = fs.tree; tree = fs.tree;
closefile( closefile(
createfile(tree->root, "ctl", nil, DMAPPEND | 0300, create_aux(CTL))); createfile(tree->root, "ctl", nil, DMAPPEND | 0600, create_aux(CTL)));
closefile(createfile(tree->root, "carts", nil, 0400, create_aux(CARTS))); closefile(createfile(tree->root, "carts", nil, 0400, create_aux(CARTS)));
closefile(createfile(tree->root, "users", nil, 0400, create_aux(USERS))); closefile(createfile(tree->root, "users", nil, 0400, create_aux(USERS)));
closefile(createfile(tree->root, "slot", nil, 0400, create_aux(SLOT))); closefile(createfile(tree->root, "slot", nil, 0400, create_aux(SLOT)));