all repos — cgit @ 5764fe95469f65fdee285467f0f87d188fc1a780

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