all repos — cgit @ c5984a9896b39748e61daf6e620483749654b102

a hyperfast web frontend for git written in c

ui-snapshot.c (view raw)

  1/* ui-snapshot.c: generate snapshot of a commit
  2 *
  3 * Copyright (C) 2006 Lars Hjemli
  4 *
  5 * Licensed under GNU General Public License v2
  6 *   (see COPYING for full license text)
  7 */
  8
  9#include "cgit.h"
 10#include "html.h"
 11
 12static int write_compressed_tar_archive(struct archiver_args *args,const char *filter)
 13{
 14	int rw[2];
 15	pid_t gzpid;
 16	int stdout2;
 17	int status;
 18	int rv;
 19
 20	stdout2 = chk_non_negative(dup(STDIN_FILENO), "Preserving STDOUT before compressing");
 21	chk_zero(pipe(rw), "Opening pipe from compressor subprocess");
 22	gzpid = chk_non_negative(fork(), "Forking compressor subprocess");
 23	if(gzpid==0) {
 24		/* child */
 25		chk_zero(close(rw[1]), "Closing write end of pipe in child");
 26		chk_zero(close(STDIN_FILENO), "Closing STDIN");
 27		chk_non_negative(dup2(rw[0],STDIN_FILENO), "Redirecting compressor input to stdin");
 28		execlp(filter,filter,NULL);
 29		_exit(-1);
 30	}
 31	/* parent */
 32	chk_zero(close(rw[0]), "Closing read end of pipe");
 33	chk_non_negative(dup2(rw[1],STDOUT_FILENO), "Redirecting output to compressor");
 34
 35	rv = write_tar_archive(args);
 36
 37	chk_zero(close(STDOUT_FILENO), "Closing STDOUT redirected to compressor");
 38	chk_non_negative(dup2(stdout2,STDOUT_FILENO), "Restoring uncompressed STDOUT");
 39	chk_zero(close(stdout2), "Closing uncompressed STDOUT");
 40	chk_zero(close(rw[1]), "Closing write end of pipe in parent");
 41	chk_positive(waitpid(gzpid,&status,0), "Waiting on compressor process");
 42	if(! ( WIFEXITED(status) && WEXITSTATUS(status)==0 ) )
 43		cgit_print_error("Failed to compress archive");
 44
 45	return rv;
 46}
 47
 48static int write_tar_gzip_archive(struct archiver_args *args)
 49{
 50	return write_compressed_tar_archive(args,"gzip");
 51}
 52
 53static int write_tar_bzip2_archive(struct archiver_args *args)
 54{
 55	return write_compressed_tar_archive(args,"bzip2");
 56}
 57
 58const struct cgit_snapshot_format cgit_snapshot_formats[] = {
 59	{ ".zip", "application/x-zip", write_zip_archive, 0x1 },
 60	{ ".tar.gz", "application/x-tar", write_tar_gzip_archive, 0x2 },
 61	{ ".tar.bz2", "application/x-tar", write_tar_bzip2_archive, 0x4 },
 62	{ ".tar", "application/x-tar", write_tar_archive, 0x8 },
 63	{}
 64};
 65
 66static int make_snapshot(const struct cgit_snapshot_format *format,
 67			 const char *hex, const char *prefix,
 68			 const char *filename)
 69{
 70	struct archiver_args args;
 71	struct commit *commit;
 72	unsigned char sha1[20];
 73
 74	if(get_sha1(hex, sha1)) {
 75		cgit_print_error(fmt("Bad object id: %s", hex));
 76		return 1;
 77	}
 78	commit = lookup_commit_reference(sha1);
 79	if(!commit) {
 80		cgit_print_error(fmt("Not a commit reference: %s", hex));
 81		return 1;
 82	}
 83	memset(&args, 0, sizeof(args));
 84	args.base = fmt("%s/", prefix);
 85	args.tree = commit->tree;
 86	args.time = commit->date;
 87	ctx.page.mimetype = xstrdup(format->mimetype);
 88	ctx.page.filename = xstrdup(filename);
 89	cgit_print_http_headers(&ctx);
 90	format->write_func(&args);
 91	return 0;
 92}
 93
 94void cgit_print_snapshot(const char *head, const char *hex, const char *prefix,
 95			 const char *filename, int snapshots)
 96{
 97	const struct cgit_snapshot_format* f;
 98	int sl, fnl;
 99
100	fnl = strlen(filename);
101	if (!hex)
102		hex = head;
103	for (f = cgit_snapshot_formats; f->suffix; f++) {
104		if (!(snapshots & f->bit))
105			continue;
106		sl = strlen(f->suffix);
107		if(fnl < sl || strcmp(&filename[fnl-sl], f->suffix))
108			continue;
109		make_snapshot(f, hex, prefix, filename);
110		return;
111	}
112	cgit_print_error(fmt("Unsupported snapshot format: %s", filename));
113}