else
log(L_DEBUG, ">> ???");
}
- put_attr_set_type(BUCKET_TYPE_PLAIN);
- bput_object(&c->tx_fb, c->reply);
+ obj_write(&c->tx_fb, c->reply, BUCKET_TYPE_PLAIN);
bputc(&c->tx_fb, '\n');
bflush(&c->tx_fb);
}
/*** SUBMIT ***/
+static struct fastbuf *
+read_attachment(struct conn *c)
+{
+ uns size = obj_find_anum(c->request, 'S', 0);
+ if (size > max_attachment_size)
+ {
+ err(c, "Submission too large");
+ return NULL;
+ }
+ obj_set_attr(c->reply, '+', "Go on");
+ write_reply(c);
+ obj_set_attr(c->reply, '+', NULL);
+
+ // This is less efficient than bbcopy(), but we want our own error handling.
+ struct fastbuf *fb = bopen_tmp(4096);
+ byte buf[4096];
+ uns remains = size;
+ while (remains)
+ {
+ uns cnt = bread(&c->rx_fb, buf, MIN(remains, (uns)sizeof(buf)));
+ if (!cnt)
+ {
+ bclose(fb);
+ client_error("Truncated attachment");
+ }
+ bwrite(fb, buf, cnt);
+ remains -= cnt;
+ }
+ brewind(fb);
+ return fb;
+}
+
static void
cmd_submit(struct conn *c)
{
err(c, "No such task");
return;
}
+ struct fastbuf *fb = read_attachment(c);
+ if (!fb)
+ return;
+
+ // FIXME: Check contest time
+ // FIXME: Keep history of submitted tasks
+ // FIXME: File names
+
+ task_lock_status(c);
+ struct odes *o = task_status_find_task(c, task);
+ task_submit(c, task, fb, task->name);
+ log(L_INFO, "User %s submitted task %s", c->user, task->name);
+ task_unlock_status(c, 1);
}
/*** COMMAND MUX ***/
struct mempool *pool;
struct odes *request;
struct odes *reply;
+ struct odes *task_status;
+ int task_lock_fd;
byte *user;
};
struct task *task_find(byte *name);
int user_exists_p(byte *user);
+void task_lock_status(struct conn *c);
+void task_unlock_status(struct conn *c, uns write_back);
+void task_submit(struct conn *c, struct task *t, struct fastbuf *fb, byte *filename);
+struct odes *task_status_find_task(struct conn *c, struct task *t);
#endif
#include "lib/lib.h"
#include "lib/conf.h"
+#include "lib/fastbuf.h"
#include "lib/stkstring.h"
+#include "sherlock/object.h"
#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
#include "submitd.h"
struct stat st;
return !stat(fn, &st) && S_ISREG(st.st_mode);
}
+
+void
+task_lock_status(struct conn *c)
+{
+ ASSERT(!c->task_lock_fd);
+ if ((c->task_lock_fd = open(stk_printf("solutions/%s/status.lock", c->user), O_RDWR | O_CREAT | O_TRUNC, 0666)) < 0)
+ die("Cannot create task lock: %m");
+ struct flock fl = {
+ .l_type = F_WRLCK,
+ .l_whence = SEEK_SET,
+ .l_start = 0,
+ .l_len = 1
+ };
+ if (fcntl(c->task_lock_fd, F_SETLKW, &fl) < 0)
+ die("Cannot lock status file: %m");
+
+ struct fastbuf *fb = bopen_try(stk_printf("solutions/%s/status", c->user), O_RDONLY, 4096);
+ c->task_status = obj_new(c->pool);
+ if (fb)
+ {
+ obj_read(fb, c->task_status);
+ bclose(fb);
+ }
+}
+
+void
+task_unlock_status(struct conn *c, uns write_back)
+{
+ ASSERT(c->task_lock_fd);
+ ASSERT(c->task_status);
+
+ if (write_back)
+ {
+ struct fastbuf *fb = bopen_tmp(4096);
+ obj_write(fb, c->task_status, BUCKET_TYPE_PLAIN);
+ brewind(fb);
+ bconfig(fb, BCONFIG_IS_TEMP_FILE, 0);
+ byte *name = stk_printf("solutions/%s/status", c->user);
+ if (rename(fb->name, name) < 0)
+ die("Unable to rename %s to %s: %m", fb->name, name);
+ bclose(fb);
+ }
+
+ struct flock fl = {
+ .l_type = F_UNLCK,
+ .l_whence = SEEK_SET,
+ .l_start = 0,
+ .l_len = 1
+ };
+ if (fcntl(c->task_lock_fd, F_SETLKW, &fl) < 0)
+ die("Cannot unlock status file: %m");
+ c->task_lock_fd = 0;
+ c->task_status = NULL;
+}
+
+struct odes *
+task_status_find_task(struct conn *c, struct task *t)
+{
+ for (struct oattr *a = obj_find_attr(c->task_status, 'T' + OBJ_ATTR_SON); a; a=a->same)
+ {
+ struct odes *o = a->son;
+ byte *name = obj_find_aval(o, 'T');
+ if (!strcmp(name, t->name))
+ return o;
+ }
+ struct odes *o = obj_add_son(c->task_status, 'T' + OBJ_ATTR_SON);
+ obj_set_attr(o, 'T', t->name);
+ return o;
+}
+
+void
+task_submit(struct conn *c, struct task *t, struct fastbuf *fb, byte *filename)
+{
+ byte *dir = stk_printf("solutions/%s/%s", c->user, t->name);
+ byte *name = stk_printf("%s/%s", dir, filename);
+}