diff options
| author | Laurent Bercot <ska-skaware@skarnet.org> | 2024-01-30 20:51:38 +0000 |
|---|---|---|
| committer | Laurent Bercot <ska@appnovation.com> | 2024-01-30 20:51:38 +0000 |
| commit | 21d51f7e0a639a3224ffc45dc3c06854decf1d45 (patch) | |
| tree | 87c4a36f66510e79d7ec8315361bb8bbbb5767f5 /src | |
| download | apaste-21d51f7e0a639a3224ffc45dc3c06854decf1d45.tar.gz | |
Initial commit
Signed-off-by: Laurent Bercot <ska@appnovation.com>
Diffstat (limited to 'src')
| -rw-r--r-- | src/client/PROTOCOL.txt | 19 | ||||
| -rw-r--r-- | src/client/apaste.c | 101 | ||||
| -rw-r--r-- | src/client/apastec.c | 155 | ||||
| -rw-r--r-- | src/client/apastec.h | 17 | ||||
| -rw-r--r-- | src/client/deps-exe/apaste | 1 | ||||
| -rw-r--r-- | src/client/deps-exe/apastec | 4 | ||||
| -rw-r--r-- | src/client/send_file.c | 93 | ||||
| -rw-r--r-- | src/include-local/apaste-common.h | 9 | ||||
| -rw-r--r-- | src/server/apasted.c | 339 | ||||
| -rw-r--r-- | src/server/deps-exe/apasted | 3 |
10 files changed, 741 insertions, 0 deletions
diff --git a/src/client/PROTOCOL.txt b/src/client/PROTOCOL.txt new file mode 100644 index 0000000..6e828ca --- /dev/null +++ b/src/client/PROTOCOL.txt @@ -0,0 +1,19 @@ + +apastec: + +banner \n +nfiles (uint32) \n +{ + namelength (uint16) \n + name (namelength) \n + filelength (uint64) \n + file (filelength) \n +} +banner \n + + +apasted: + +banner \n +slug \n +banner \n diff --git a/src/client/apaste.c b/src/client/apaste.c new file mode 100644 index 0000000..1d2a739 --- /dev/null +++ b/src/client/apaste.c @@ -0,0 +1,101 @@ +/* ISC license. */ + +#include <stdint.h> +#include <string.h> + +#include <skalibs/uint16.h> +#include <skalibs/uint32.h> +#include <skalibs/sgetopt.h> +#include <skalibs/strerr.h> +#include <skalibs/exec.h> + +#include <s6-networking/config.h> + +#include <apaste/config.h> + +#define USAGE "apaste [ -S | -s ] [ -C cadir ] [ -d server[:port] ] [ -r rtimeout ] [ -w wtimeout ] file..." +#define dieusage() strerr_dieusage(100, USAGE) + +int main (int argc, char *const *argv) +{ + char const *cadir = APASTE_DEFAULT_CADIR ; + char const *server = APASTE_DEFAULT_SERVER ; + int dotls = APASTE_DEFAULT_TLS ; + uint32_t rt = 0 ; + uint32_t wt = 0 ; + uint16_t port = 0 ; + PROG = "apaste" ; + + { + subgetopt l = SUBGETOPT_ZERO ; + for (;;) + { + int opt = subgetopt_r(argc, (char const *const *)argv, "SsC:d:r:w:", &l) ; + if (opt == -1) break ; + switch (opt) + { + case 'S' : dotls = 0 ; break ; + case 's' : dotls = 1 ; break ; + case 'C' : cadir = l.arg ; break ; + case 'd' : + { + char *colon = strchr(l.arg, ':') ; + server = l.arg ; + if (colon) + { + *colon = 0 ; + if (!uint160_scan(colon + 1, &port)) dieusage() ; + } + break ; + } + case 'r' : if (!uint320_scan(l.arg, &rt)) dieusage() ; break ; + case 'w' : if (!uint320_scan(l.arg, &wt)) dieusage() ; break ; + default : dieusage() ; + } + } + argc -= l.ind ; argv += l.ind ; + } + if (!argc) dieusage() ; + if (!port) port = dotls ? APASTE_DEFAULT_TLSPORT : APASTE_DEFAULT_PORT ; + { + char const *newargv[12 + argc] ; + unsigned int m = 0 ; + char fmtr[UINT32_FMT] ; + char fmtw[UINT32_FMT] ; + char fmtp[UINT16_FMT] ; + + fmtp[uint16_fmt(fmtp, port)] = 0 ; + + newargv[m++] = dotls ? S6_NETWORKING_EXTBINPREFIX "s6-tlsclient" : S6_NETWORKING_EXTBINPREFIX "s6-tcpclient" ; + newargv[m++] = "-N" ; + newargv[m++] = "--" ; + newargv[m++] = server ; + newargv[m++] = fmtp ; + newargv[m++] = APASTE_BINPREFIX "apastec" ; + if (rt) + { + fmtr[uint32_fmt(fmtr, rt)] = 0 ; + newargv[m++] = "-r" ; + newargv[m++] = fmtr ; + } + if (rt) + { + fmtw[uint32_fmt(fmtw, wt)] = 0 ; + newargv[m++] = "-w" ; + newargv[m++] = fmtw ; + } + newargv[m++] = "--" ; + while (argc--) newargv[m++] = *argv++ ; + newargv[m++] = 0 ; + + if (dotls) + { + size_t len = strlen(cadir) ; + char modif[7 + len] ; + memcpy(modif, "CADIR=", 6) ; + memcpy(modif + 6, cadir, len + 1) ; + xmexec_n(newargv, modif, len + 7, 1) ; + } + else xexec(newargv) ; + } +} diff --git a/src/client/apastec.c b/src/client/apastec.c new file mode 100644 index 0000000..3237ceb --- /dev/null +++ b/src/client/apastec.c @@ -0,0 +1,155 @@ +/* ISC license. */ + +#include <stdint.h> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <signal.h> + +#include <skalibs/posixplz.h> +#include <skalibs/uint16.h> +#include <skalibs/uint32.h> +#include <skalibs/uint64.h> +#include <skalibs/buffer.h> +#include <skalibs/sgetopt.h> +#include <skalibs/strerr.h> +#include <skalibs/tai.h> +#include <skalibs/sig.h> +#include <skalibs/djbunix.h> +#include <skalibs/unix-timed.h> + +#include <apaste/config.h> +#include "apaste-common.h" +#include "apastec.h" + +#define USAGE "apastec [ -r rtimeout ] [ -w wtimeout ] file..." +#define dieusage() strerr_dieusage(100, USAGE) + +static void apaste_send (buffer *b, char const *file, tain const *deadline) +{ + int fd ; + struct stat st ; + size_t len = strlen(file) ; + if (!len) strerr_dief2x(100, "empty file", " names are invalid") ; + if (len > UINT16_MAX) strerr_dief2x(100, "file name too long: ", file) ; + if (len == 1 && file[0] == '-') + { + char tmp[sizeof(APASTE_TMPDIR) + 14] = APASTE_TMPDIR "/apaste:XXXXXX" ; + fd = mkstemp(tmp) ; + if (fd == -1) strerr_diefu2sys(111, "mkstemp ", tmp) ; + unlink_void(tmp) ; + if (fd_cat(0, fd) == -1) strerr_diefu2sys(111, "copy stdin to ", tmp) ; + if (lseek(fd, 0, SEEK_SET) == -1) strerr_diefu1sys(111, "lseek") ; + ndelay_on(fd) ; + } + else + { + if (file[len-1] == '/') strerr_dief2x(100, "directory", " names are invalid") ; + fd = open_read(file) ; + if (fd == -1) strerr_diefu2sys(111, "open ", file) ; + } + + if (fstat(fd, &st) == -1) strerr_diefu2sys(111, "stat ", file) ; + if (!S_ISREG(st.st_mode)) strerr_dief3x(100, "file ", file, " is not a regular file") ; + { + char fmt[UINT64_FMT] ; + size_t m = uint16_fmt(fmt, len) ; + fmt[m++] = '\n' ; + if (buffer_timed_put_g(b, fmt, m, deadline) < m + || buffer_timed_put_g(b, file, len, deadline) < len + || buffer_timed_put_g(b, "\n", 1, deadline) < 1) + strerr_diefu1sys(111, "write to server") ; + m = uint64_fmt(fmt, st.st_size) ; + fmt[m++] = '\n' ; + if (buffer_timed_put_g(b, fmt, m, deadline) < m) + strerr_diefu1sys(111, "write to server") ; + } + send_file_g(b, fd, st.st_size, file, deadline) ; + fd_close(fd) ; + if (buffer_timed_put_g(b, "\n", 1, deadline) < 1) + strerr_diefu1sys(111, "write to server") ; +} + +int main (int argc, char const *const *argv) +{ + tain rtto = TAIN_INFINITE_RELATIVE, wtto = TAIN_INFINITE_RELATIVE ; + tain deadline ; + PROG = "apastec" ; + { + uint32_t rt = 0, wt = 0 ; + subgetopt l = SUBGETOPT_ZERO ; + for (;;) + { + int opt = subgetopt_r(argc, argv, "r:w:", &l) ; + if (opt == -1) break ; + switch (opt) + { + case 'r' : if (!uint320_scan(l.arg, &rt)) dieusage() ; break ; + case 'w' : if (!uint320_scan(l.arg, &wt)) dieusage() ; break ; + default : dieusage() ; + } + } + argc -= l.ind ; argv += l.ind ; + if (rt) tain_from_millisecs(&rtto, rt) ; + if (wt) tain_from_millisecs(&rtto, wt) ; + } + if (!argc) dieusage() ; + if (argc > UINT32_MAX) strerr_dief1x(100, "too many arguments") ; + + if (!sig_altignore(SIGPIPE)) + strerr_diefu1sys(111, "ignore SIGPIPE") ; + tain_now_set_stopwatch_g() ; + tain_add_g(&deadline, &wtto) ; + + { + char buf[BUFFER_OUTSIZE] ; + buffer b = BUFFER_INIT(&buffer_write, 7, buf, BUFFER_OUTSIZE) ; + buffer_putnoflush(&b, APASTEC_BANNER "\n", sizeof(APASTEC_BANNER)) ; + { + char fmt[UINT32_FMT] ; + size_t m = uint32_fmt(fmt, argc) ; + fmt[m++] = '\n' ; + buffer_putnoflush(&b, fmt, m) ; + } + { + int gotstdin = 0 ; + for (unsigned int i = 0 ; i < argc ; i++) if (argv[i][0] == '-' && !argv[i][1]) + { + if (gotstdin) strerr_dief1x(100, "stdin specified more than once") ; + gotstdin = 1 ; + } + } + for (unsigned int i = 0 ; i < argc ; i++) apaste_send(&b, argv[i], &deadline) ; + if (buffer_timed_put_g(&b, APASTEC_BANNER "\n", sizeof(APASTEC_BANNER), &deadline) < sizeof(APASTEC_BANNER) + || !buffer_timed_flush_g(&b, &deadline)) + strerr_diefu1sys(111, "write to apaste server") ; + } + + fd_shutdown(7, 1) ; + fd_close(7) ; + tain_add_g(&deadline, &rtto) ; + + { + char buf[BUFFER_INSIZE] ; + char banner[256] ; + char slug[256] ; + buffer b = BUFFER_INIT(&buffer_read, 6, buf, BUFFER_INSIZE) ; + size_t w = 0, sluglen = 0 ; + if (sanitize_read(timed_getlnmax_g(&b, banner, 256, &w, '\n', &deadline)) <= 0) + strerr_diefu1sys(111, "read from apaste server") ; + if (w != sizeof(APASTED_BANNER) || memcmp(banner, APASTED_BANNER, w-1)) + strerr_dief1x(1, "server returned invalid data") ; + if (sanitize_read(timed_getlnmax_g(&b, slug, 256, &sluglen, '\n', &deadline)) <= 0) + strerr_diefu1sys(111, "read from apaste server") ; + w = 0 ; + if (sanitize_read(timed_getlnmax_g(&b, banner, 256, &w, '\n', &deadline)) <= 0) + strerr_diefu1sys(111, "read from apaste server") ; + if (w != sizeof(APASTED_BANNER) || memcmp(banner, APASTED_BANNER, w-1)) + strerr_dief1x(1, "server returned invalid data") ; + if (buffer_putflush(buffer_1small, slug, sluglen) == -1) + strerr_diefu1sys(111, "write to stdout") ; + } + + return 0 ; +} diff --git a/src/client/apastec.h b/src/client/apastec.h new file mode 100644 index 0000000..84ab242 --- /dev/null +++ b/src/client/apastec.h @@ -0,0 +1,17 @@ +/* ISC license. */ + +#ifndef APASTEC_H +#define APASTEC_H + +#include <sys/types.h> + +#include <skalibs/buffer.h> +#include <skalibs/tai.h> + + +/* send_file.c */ + +extern void send_file (buffer *, int, off_t, char const *, tain const *, tain *) ; +#define send_file_g(b, fd, size, file, deadline) send_file(b, fd, size, file, (deadline), &STAMP) + +#endif diff --git a/src/client/deps-exe/apaste b/src/client/deps-exe/apaste new file mode 100644 index 0000000..e7187fe --- /dev/null +++ b/src/client/deps-exe/apaste @@ -0,0 +1 @@ +-lskarnet diff --git a/src/client/deps-exe/apastec b/src/client/deps-exe/apastec new file mode 100644 index 0000000..1e0ab64 --- /dev/null +++ b/src/client/deps-exe/apastec @@ -0,0 +1,4 @@ +send_file.o +-lskarnet +${SOCKET_LIB} +${SYSCLOCK_LIB} diff --git a/src/client/send_file.c b/src/client/send_file.c new file mode 100644 index 0000000..4da8412 --- /dev/null +++ b/src/client/send_file.c @@ -0,0 +1,93 @@ +/* ISC license. */ + +#include <skalibs/sysdeps.h> + +#ifdef SKALIBS_HASSENDFILE + +#include <sys/types.h> +#include <sys/sendfile.h> +#include <limits.h> + +#include <skalibs/uint64.h> +#include <skalibs/strerr.h> +#include <skalibs/tai.h> +#include <skalibs/unix-timed.h> + +struct sendfile_s +{ + int fd ; + buffer *out ; + off_t pos ; + uint64_t n ; +} ; + +static int s_getfd (void *p) +{ + struct sendfile_s *sf = p ; + return buffer_fd(sf->out) ; +} + +static int s_isnonempty (void *p) +{ + struct sendfile_s *sf = p ; + return !!sf->n ; +} + +static int s_flush (void *p) +{ + struct sendfile_s *sf = p ; + while (sf->n) + { + ssize_t r = sendfile(buffer_fd(sf->out), sf->fd, &sf->pos, sf->n > SSIZE_MAX ? SSIZE_MAX : sf->n) ; + if (r == -1) return 0 ; + sf->n -= r ; + } + return 1 ; +} + +void send_file (buffer *b, int fd, off_t size, char const *fn, tain const *deadline, tain *stamp) +{ + struct sendfile_s sf = { .fd = fd, .out = b, .pos = 0, .n = size } ; + if (!buffer_timed_flush(b, deadline, stamp)) + strerr_diefu1sys(111, "write to network") ; + if (!timed_flush(&sf, &s_getfd, &s_isnonempty, &s_flush, deadline, stamp)) + strerr_diefu3sys(111, "sendfile ", fn, " to network") ; +} + +#else + +#include <sys/uio.h> +#include <unistd.h> +#include <stdint.h> + +#include <skalibs/uint64.h> +#include <skalibs/allreadwrite.h> +#include <skalibs/buffer.h> +#include <skalibs/strerr.h> +#include <skalibs/tai.h> +#include <skalibs/unix-timed.h> + +void send_file (buffer *b, int fd, uint64_t n, char const *fn, tain const *deadline, tain *stamp) +{ + struct iovec v[2] ; + ssize_t r ; + if (!n) goto flushit ; + fillit: + buffer_wpeek(b, v) ; + r = allreadv(fd, v, 2) ; + if (r == -1) strerr_diefu2sys(111, "read from ", fn) ; + if (!r) strerr_diefu3x(111, "send ", fn, ": file was truncated") ; + if (r > n) + { + r = n ; + strerr_warnw2x("sending elongated file: ", fn) ; + } + buffer_wseek(b, r) ; + n -= r ; + flushit: + if (!buffer_timed_flush(b, deadline, stamp)) + strerr_diefu1sys(111, "write to network") ; + if (n) goto fillit ; +} + +#endif diff --git a/src/include-local/apaste-common.h b/src/include-local/apaste-common.h new file mode 100644 index 0000000..8a680d9 --- /dev/null +++ b/src/include-local/apaste-common.h @@ -0,0 +1,9 @@ +/* ISC license. */ + +#ifndef APASTE_COMMON_H +#define APASTE_COMMON_H + +#define APASTEC_BANNER "apastec protocol v1" +#define APASTED_BANNER "apasted protocol v1" + +#endif diff --git a/src/server/apasted.c b/src/server/apasted.c new file mode 100644 index 0000000..b338154 --- /dev/null +++ b/src/server/apasted.c @@ -0,0 +1,339 @@ +/* ISC license. */ + +#include <stdint.h> +#include <string.h> +#include <sys/uio.h> +#include <unistd.h> +#include <stdlib.h> +#include <errno.h> +#include <signal.h> + +#include <skalibs/posixplz.h> +#include <skalibs/uint16.h> +#include <skalibs/uint32.h> +#include <skalibs/uint64.h> +#include <skalibs/bytestr.h> +#include <skalibs/siovec.h> +#include <skalibs/allreadwrite.h> +#include <skalibs/buffer.h> +#include <skalibs/sgetopt.h> +#include <skalibs/strerr.h> +#include <skalibs/tai.h> +#include <skalibs/stralloc.h> +#include <skalibs/sig.h> +#include <skalibs/djbunix.h> +#include <skalibs/unix-timed.h> + +#include <apaste/config.h> +#include "apaste-common.h" + +#define USAGE "apasted [ -r rtimeout ] [ -w wtimeout ] [ -d rootdir ] [ -p prefix ] [ -m maxfiles ]" +#define dieusage() strerr_dieusage(100, USAGE) + +#define FORBIDDEN " \t\r\n\"<>&;" + +#define INDEXSTART "\ +<html>\n\ + <head>\n\ + <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n\ + <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n\ + <meta http-equiv=\"Content-Language\" content=\"en\" />\n\ + <title>apaste results</title>\n\ + <meta name=\"Description\" content=\"apaste results\" />\n\ + </head>\n\ +<body>\n\ +<h3> apaste results </h3>\n\ +<ul>\n" + +static void cleanup (char const *dir) +{ + int e = errno ; + rm_rf(dir) ; + errno = e ; +} + +static void prepare_index (buffer *ib, char const *dir, char *buf, size_t buflen) +{ + int fd ; + size_t dirlen = strlen(dir) ; + char fn[dirlen + 12] ; + memcpy(fn, dir, dirlen) ; + memcpy(fn + dirlen, "/index.html", 12) ; + fd = open_create(fn) ; + if (fd == -1) + { + cleanup(dir) ; + strerr_diefu3sys(111, "open ", dir, "/index.html for writing") ; + } + buffer_init(ib, &buffer_write, fd, buf, buflen) ; + if (buffer_puts(ib, INDEXSTART) == -1) + { + cleanup(dir) ; + strerr_diefu2sys(111, "prepare index for ", dir) ; + } +} + +static inline void add_index_entry (char const *dir, buffer *ib, char const *name, uint64_t filelen) +{ + char fmt[UINT64_FMT] ; + size_t m = uint64_fmt(fmt, filelen) ; + if (buffer_puts(ib, " <li> <a href=\"") == -1 + || buffer_puts(ib, name) == -1 + || buffer_puts(ib, ".txt\">") == -1 + || buffer_puts(ib, name) == -1 + || buffer_puts(ib, "</a> (") == -1 + || buffer_put(ib, fmt, m) == -1 + || buffer_puts(ib, " bytes) </li>\n") == -1) + { + cleanup(dir) ; + strerr_diefu5sys(111, "add ", name, " to ", dir, "/index.html") ; + } +} + +static inline void finish_index (buffer *ib, char const *dir) +{ + if (buffer_putsflush(ib, "</ul>\n</body>\n</html>\n") == -1 + || fsync(buffer_fd(ib)) == -1) + { + cleanup(dir) ; + strerr_diefu2sys(111, "finish index for ", dir) ; + } + fd_close(buffer_fd(ib)) ; +} + +static inline void recv_one_file (char const *dir, char const *fn, buffer *b, int fd, uint64_t n, tain const *deadline) +{ + struct iovec v[2] ; + size_t len ; + while (n) + { + unsigned int j = 2 ; + if (buffer_len(b) < n) + { + if (sanitize_read(buffer_timed_fill_g(b, deadline)) <= 0) + { + cleanup(dir) ; + _exit(1) ; + } + } + buffer_rpeek(b, v) ; + len = siovec_len(v, 2) ; + if (len > n) + { + j = siovec_trunc(v, 2, n) ; + len = n ; + } + if (allwritev(fd, v, j) < len) + { + cleanup(dir) ; + strerr_diefu2sys(111, "write to ", fn) ; + } + buffer_rseek(b, len) ; + n -= len ; + } +} + +static inline size_t add_unique (stralloc *sa, size_t *indices, uint32_t n, char const *bname) +{ + size_t blen = strlen(bname) ; + size_t pos = sa->len ; + static uint32_t suffix = 0 ; + if (!stralloc_readyplus(sa, blen + UINT32_FMT + 2)) return 0 ; + memcpy(sa->s + pos, bname, blen + 1) ; + for (;;) + { + uint32_t i = 0 ; + for (; i < n ; i++) if (!strcmp(sa->s + indices[i], sa->s + pos)) break ; + if (i == n) break ; + sa->s[pos + blen] = '.' ; + sa->s[pos + blen + 1 + uint32_fmt(sa->s + pos + blen + 1, suffix++)] = 0 ; + } + + blen = strlen(sa->s + pos) ; + indices[n] = sa->len ; + sa->len += blen + 1 ; + return blen ; +} + +static void read_one_file (char const *dir, buffer *b, buffer *ib, stralloc *sa, size_t *indices, uint32_t n, tain const *deadline) +{ + uint64_t filelen ; + size_t bnamelen ; + uint16_t namelen ; + + { + size_t w = 0 ; + size_t m ; + char fmt[UINT16_FMT] ; + if (sanitize_read(timed_getlnmax_g(b, fmt, UINT16_FMT, &w, '\n', deadline)) <= 0) goto err ; + m = uint16_scan(fmt, &namelen) ; + if (!m || m+1 != w || fmt[m] != '\n') goto err ; + } + + { + size_t w = 0 ; + char *bname ; + char name[namelen + 1] ; + if (sanitize_read(timed_getlnmax_g(b, name, namelen + 1, &w, '\n', deadline)) <= 0) goto err ; + if (!w || w != namelen + 1 || name[namelen] != '\n') goto err ; + name[namelen] = 0 ; + bname = strrchr(name, '/') ; + if (bname) bname++ ; else bname = name ; + if (!*bname) goto err ; + + if (ib) /* sanitize the filename for inclusion in index.html */ + { + size_t blen = strlen(bname) ; + if (byte_in(bname, blen, FORBIDDEN, sizeof(FORBIDDEN)) != blen) goto err ; + bnamelen = add_unique(sa, indices, n, bname) ; + if (!bnamelen) + { + cleanup(dir) ; + strerr_diefu3sys(111, "make ", bname, " unique") ; + } + } + else bnamelen = 5 ; + } + + { + size_t w = 0 ; + size_t m ; + char fmt[UINT64_FMT] ; + if (sanitize_read(timed_getlnmax_g(b, fmt, UINT64_FMT, &w, '\n', deadline)) <= 0) goto err ; + m = uint64_scan(fmt, &filelen) ; + if (!m || m+1 != w || fmt[m] != '\n') goto err ; + } + + { + int fd ; + size_t dirlen = strlen(dir) ; + char fn[dirlen + bnamelen + 6] ; + memcpy(fn, dir, dirlen) ; + fn[dirlen] = '/' ; + memcpy(fn + dirlen + 1, ib ? sa->s + indices[n] : "index", bnamelen) ; + memcpy(fn + dirlen + 1 + bnamelen, ".txt", 5) ; + fd = open_create(fn) ; + if (fd == -1) + { + cleanup(dir) ; + strerr_diefu3sys(111, "open ", fn, " for writing") ; + } + recv_one_file(dir, fn, b, fd, filelen, deadline) ; + if (fsync(fd) == -1) + { + cleanup(dir) ; + strerr_diefu2sys(111, "fsync ", fn) ; + } + fd_close(fd) ; + } + + { + char c ; + if (sanitize_read(buffer_timed_get_g(b, &c, 1, deadline)) != 1) goto err ; + if (c != '\n') goto err ; + } + + if (ib) add_index_entry(dir, ib, sa->s + indices[n], filelen) ; + return ; + + err: + cleanup(dir) ; + _exit(1) ; +} + +int main (int argc, char const *const *argv) +{ + char const *prefix = "" ; + tain rtto = TAIN_INFINITE_RELATIVE, wtto = TAIN_INFINITE_RELATIVE ; + tain deadline ; + uint32_t maxfiles = 0 ; + uint32_t n ; + char buf[4097] ; + char dir[7] = "XXXXXX" ; + buffer b = BUFFER_INIT(&buffer_read, 0, buf, 4097) ; + PROG = "apasted" ; + { + char const *rootdir = 0 ; + uint32_t rt = 0, wt = 0 ; + subgetopt l = SUBGETOPT_ZERO ; + for (;;) + { + int opt = subgetopt_r(argc, argv, "r:w:d:p:m:", &l) ; + if (opt == -1) break ; + switch (opt) + { + case 'r' : if (!uint320_scan(l.arg, &rt)) dieusage() ; break ; + case 'w' : if (!uint320_scan(l.arg, &wt)) dieusage() ; break ; + case 'd' : rootdir = l.arg ; break ; + case 'p' : prefix = l.arg ; break ; + case 'm' : if (!uint320_scan(l.arg, &maxfiles)) dieusage() ; break ; + default : dieusage() ; + } + } + argc -= l.ind ; argv += l.ind ; + if (rt) tain_from_millisecs(&rtto, rt) ; + if (wt) tain_from_millisecs(&rtto, wt) ; + if (rootdir && chdir(rootdir) == -1) + strerr_diefu2sys(111, "chdir to ", rootdir) ; + if (strlen(prefix) > 4000) strerr_dief1x(100, "prefix too long") ; + } + + if (!sig_altignore(SIGPIPE)) + strerr_diefu1sys(111, "ignore SIGPIPE") ; + tain_now_set_stopwatch_g() ; + tain_add_g(&deadline, &rtto) ; + + { + char banner[256] ; + size_t w = 0 ; + if (sanitize_read(timed_getlnmax_g(&b, banner, 256, &w, '\n', &deadline)) <= 0) _exit(1) ; + if (w != sizeof(APASTEC_BANNER) || memcmp(banner, APASTEC_BANNER, w-1)) _exit(1) ; + } + + { + char fmt[UINT32_FMT] ; + size_t w = 0 ; + size_t m ; + if (sanitize_read(timed_getlnmax_g(&b, fmt, UINT32_FMT, &w, '\n', &deadline)) <= 0) + strerr_diefu1sys(111, "read from apaste server") ; + m = uint32_scan(fmt, &n) ; + if (!m || m+1 != w) _exit(1) ; + if (!n || (maxfiles && n > maxfiles)) _exit(1) ; + } + + if (!mkdtemp(dir)) strerr_diefu1sys(111, "mkdtemp") ; + if (n == 1) read_one_file(dir, &b, 0, 0, 0, 0, &deadline) ; + else + { + stralloc sa = STRALLOC_ZERO ; + size_t indices[n] ; + buffer ib ; + char ibuf[4096] ; + prepare_index(&ib, dir, ibuf, 4096) ; + for (uint32_t i = 0 ; i < n ; i++) read_one_file(dir, &b, &ib, &sa, indices, i, &deadline) ; + finish_index(&ib, dir) ; + } + + { + char banner[256] ; + size_t w = 0 ; + if (sanitize_read(timed_getlnmax_g(&b, banner, 256, &w, '\n', &deadline)) <= 0 + || w != sizeof(APASTEC_BANNER) + || memcmp(banner, APASTEC_BANNER, w-1)) goto err ; + } + + buffer_init(&b, &buffer_write, 1, buf, 4097) ; + buffer_putsnoflush(&b, APASTED_BANNER "\n") ; + if (prefix[0]) buffer_putsnoflush(&b, prefix) ; + buffer_putnoflush(&b, dir, 6) ; + if (!strncmp(prefix, "http", 4)) buffer_putnoflush(&b, "/", 1) ; + buffer_putsnoflush(&b, "\n" APASTED_BANNER "\n") ; + tain_add_g(&deadline, &wtto) ; + if (!buffer_timed_flush_g(&b, &deadline)) goto err ; + + return 0 ; + + err: + cleanup(dir) ; + return 1 ; +} diff --git a/src/server/deps-exe/apasted b/src/server/deps-exe/apasted new file mode 100644 index 0000000..720fe7d --- /dev/null +++ b/src/server/deps-exe/apasted @@ -0,0 +1,3 @@ +-lskarnet +${SOCKET_LIB} +${SYSCLOCK_LIB} |
