shithub: s3

ref: 0591d4ae19bb6ad8349f2d3bfda81a99bd04d956
dir: /cp.c/

View raw version
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <mp.h>
#include <libsec.h>
#include "s3.h"
#include "cmd.h"

static void
mimetype(char *path, char *out, int nout)
{
	int p[2];
	char buf[256];
	int n;

	pipe(p);
	switch(fork()){
	case 0:
		close(0);
		dup(p[0], 1);
		close(2);
		close(p[0]);
		close(p[1]);
		execl("/bin/file", "file", "-m", path, nil);
		sysfatal("execl: %r");
	default:
		close(p[0]);
		n = read(p[1], buf, sizeof buf - 1);
		if(n <= 0)
			sysfatal("no mimetype found");
		buf[n - 1] = 0;
		snprint(out, nout, "%s", buf);
	}
}

static void
upload(S3 *s3, char *localpath, char *remotepath)
{
	DigestState *ds;
	uchar data[8192];
	char mime[32];
	uchar digest[SHA2_256dlen];
	long n;
	int fd;
	char buf[256];
	Hcon con;

	mimetype(localpath, mime, sizeof mime);
	fd = open(localpath, OREAD);
	if(fd < 0)
		sysfatal("upload open: %r");
	for(ds = nil;;){
		n = read(fd, data, sizeof data);
		if(n < 0)
			sysfatal("file read: %r");
		if(n == 0)
			break;
		ds = sha2_256(data, n, nil, ds);
	}
	sha2_256(nil, 0, digest, ds);
	seek(fd, 0, 0);

	if(s3put(s3, &con, remotepath, mime, digest) < 0)
		sysfatal("upload postbody open: %r");
	for(;;){
		n = read(fd, buf, sizeof buf);
		if(n < 0)
			sysfatal("file read: %r");
		if(n == 0)
			break;
		if(write(con.post, buf, n) < 0)
			sysfatal("upload write: %r");
	}
	if(hdone(&con) < 0)
		sysfatal("error response code: %r");
	hclose(&con);
}

_Noreturn void
usage(void)
{
	fprint(2, "Usage %s: source s3://bucket/dst\n", argv0);
	fprint(2, "Usage %s: s3://bucket/source dst\n", argv0);
	exits("usage");
}

void
main(int argc , char **argv)
{
	S3 s3;
	int i;
	int fd;
	Biobuf *b;
	char path[512];

	tmfmtinstall();
	fmtinstall('H', encodefmt);
	i = parseargs(&s3, argc, argv);
	argc -= i;
	argv += i;

	if(argc < 2)
		usage();
	if(parseuri(&s3, path, sizeof path, argv[0]) == 0){
		if(parseuri(&s3, path, sizeof path, argv[1]) == 0)
			sysfatal("s3:// → s3:// is not implemented");
		fd = create(argv[1], OWRITE, 0644);
		if(fd < 0)
			sysfatal("create: %r");
		b = Bfdopen(fd, OWRITE);
		if(b == nil)
			sysfatal("Bfdopen: %r");
		download(&s3, path, b, s3get);
		Bterm(b);
		exits(nil);
	}
	if(parseuri(&s3, path, sizeof path, argv[1]) < 0)
		usage();
	upload(&s3, argv[0], path);
	exits(nil);
}