/*
 * Extract Plan9 tree
 * public domain.
 *
 * usage: gzip -cd plan9.9gz | 9ext
 */

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <stdio.h>
#include <string.h>
#include <time.h>

int
main()
{
	char line[1024];
	char fnbuf[1024], owner[1024], group[1024];
	char *fn;
	unsigned long mode, mt, size;
	time_t mtime;
	struct timeval tv[2];
	mode_t mask;

	mask = umask(0);
	umask(mask);
	mask = 0777 & ~mask;

	while (fgets(line, sizeof line, stdin)) {
		if (sscanf(line, "%s %lo %s %s %lu %lu", 
			   fnbuf, &mode, owner, group, &mt, &size) != 6) {
			if (strcmp(line, "end of archive\n") == 0) {
				return 0;
			} else {
				fprintf(stderr, "format error\n");
				return 1;
			}
		}

		mtime = mt;

		/* make sure the path is relative */
		for (fn = fnbuf; *fn == '/'; fn++)
			;

		switch (mode & ~0777) {
		case 0:
		case 010000000000:	/* append only (attribute ignored) */
			printf("x %s\t%s", fn, asctime(localtime(&mtime)));
			{
				/*
				 * copy stdin to file fn
				 * XXX slow
				 */
				FILE *fp;
				if (!(fp = fopen(fn, "w"))) {
					perror(fn);
					return 1;
				}
				while (size--)
					putc(getchar(), fp);
				if (feof(stdin) || ferror(stdin)) {
					fprintf(stderr, "unexpected end of file\n");
					remove(fn);
					return 1;
				}
				if (ferror(fp) || fclose(fp)) {
					perror(fn);
					remove(fn);
					return 1;
				}
			}
			chmod(fn, (mode_t) mode & mask);
			tv[0].tv_sec = mtime;	/* atime */
			tv[0].tv_usec = 0;
			tv[1].tv_sec = mtime;	/* mtime */
			tv[1].tv_usec = 0;
			if (utimes(fn, tv))
				perror(fn);
			break;

		case 020000000000:
			/* directory	XXX mode? mtime? */
			printf("x %s (directory)\n", fn);
			mkdir(fn, 0777);
			break;

		default:
			fprintf(stderr, "%s: unknown type (0%lo) ignored\n",
				fnbuf, mode);
			while (size--)
				getchar();
			break;
		}
	}
	fprintf(stderr, "unexpected end of file\n");
	return 1;
}
