PRMJ@cornella (Network Wiz) (03/31/88)
I haven't had a chance to use it yet since I haven't gotten my hard disk up yet but it definitely sounds like something I'm going to want to. I'd say post the final vers & src. Thankx.
dal@syntel.UUCP (Dale Schumacher) (08/28/89)
The 'tar' program that was distributed with Minix-ST had a number of bugs in it which I ran into while trying to move ~11Mb of data from my old hard disk (which I sold) to my new hard disk. I'm posting my fixed version in hopes that I may save someone else the pain I went through. Here are some of the bugs I found. The file type flags were being tested in such a way as to make certain special files look like directories, etc. Filenames containing 14 characters were not handled properly, which is a common bug since such filename are not NUL terminated in the archive header. The filename '-' is now understood to mean read from stdin or write to stdout, as appropriate. All error messages are now written to stderr rather than stdout. Other improvements were made particularly to the output routines. In addition to fixing the bugs I could find, I've added a couple of extremely useful options. The first is the '-v' flag for verbose output, which was essentially default before. The second is '-o' for adopting the owner/group of the extractor rather than that on tape, which again was default before. The old default behaviour was, however, quite annoying when trying to backup and restore an entire file-system where I definately wanted the owner/group restored to what I was in the tar-file. The final option is '-F', a non-standard option which forces 'tar' to ignore certain error conditions which otherwise caused it to quit processing a tar-file. This is intended to give a chance of properly restoring files which come after a corrupted segment of the tar-file. Enjoy. ------------------------------------------------------------------------ /* tar - tape archiver Author: Michiel Huisjes */ /* Usage: tar [cxt][vo][F] tapefile [files] * * Bugs: * This tape archiver should only be used as a program to read or make * simple tape archives. Its basic goal is to read (or build) UNIX V7 tape * archives and extract the named files. It is not wise to use it on * raw magnetic tapes. It doesn't know anything about linked files, * except when the involved fields are filled in. */ #include <sys/types.h> #include <sys/stat.h> #include <sys/dir.h> typedef char BOOL; #define TRUE 1 #define FALSE 0 #define HEADER_SIZE 512 #define NAME_SIZE 100 #define BLOCK_BOUNDARY 20 typedef union { char hdr_block[HEADER_SIZE]; struct m { char m_name[NAME_SIZE]; char m_mode[8]; char m_uid[8]; char m_gid[8]; char m_size[12]; char m_time[12]; char m_checksum[8]; char m_linked; char m_link[NAME_SIZE]; } member; } HEADER; HEADER header; #define INT_TYPE (sizeof(header.member.m_uid)) #define LONG_TYPE (sizeof(header.member.m_size)) #define MKDIR "/bin/mkdir" #define NIL_HEADER ((HEADER *) 0) #define NIL_PTR ((char *) 0) #define BLOCK_SIZE 512 #define flush() print(NIL_PTR) BOOL show_fl, creat_fl, ext_fl; int tar_fd; /* char usage[] = "Usage: tar [cxt] tarfile [files]."; */ char usage[] = "Usage: tar [cxt][vo][F] tarfile [files]."; char io_buffer[BLOCK_SIZE]; char path[NAME_SIZE]; char pathname[NAME_SIZE]; int force_flag = 0; #ifdef ORIGINAL_DEFAULTS int chown_flag = 1; int verbose_flag = 1; #else int chown_flag = 0; int verbose_flag = 0; #endif int total_blocks; long convert(); #define block_size() (int) ((convert(header.member.m_size, LONG_TYPE) \ + (long) BLOCK_SIZE - 1) / (long) BLOCK_SIZE) error(s1, s2) char *s1, *s2; { string_print(NIL_PTR, "%s %s\n", s1, s2 ? s2 : ""); flush(); exit(1); } main(argc, argv) int argc; register char *argv[]; { register char *ptr; int i; if (argc < 3) error(usage, NIL_PTR); for (ptr = argv[1]; *ptr; ptr++) { switch (*ptr) { case 'c' : creat_fl = TRUE; break; case 'x' : ext_fl = TRUE; break; case 't' : show_fl = TRUE; break; case 'v' : /* verbose output -Dal */ verbose_flag = !verbose_flag; break; case 'o' : /* chown/chgrp files -Dal */ chown_flag = TRUE; break; case 'F' : /* IGNORE ERRORS -Dal */ force_flag = TRUE; break; default : error(usage, NIL_PTR); } } if (creat_fl + ext_fl + show_fl != 1) error(usage, NIL_PTR); if (argv[2][0] == '-') tar_fd = creat_fl ? 1 : 0; /* '-' means used stdin/stdout -Dal */ else tar_fd = creat_fl ? creat(argv[2], 0644) : open(argv[2], 0); if (tar_fd < 0) error("Cannot open ", argv[2]); if (creat_fl) { for (i = 3; i < argc; i++) { add_file(argv[i]); path[0] = '\0'; } adjust_boundary(); } else tarfile(); flush(); exit(0); } BOOL get_header() { register int check; mread(tar_fd, &header, sizeof(header)); if (header.member.m_name[0] == '\0') return FALSE; if (force_flag) /* skip checksum verification -Dal */ return TRUE; check = (int) convert(header.member.m_checksum, INT_TYPE); if (check != checksum()) error("Tar: header checksum error.", NIL_PTR); return TRUE; } tarfile() { register char *ptr; register char *mem_name; while (get_header()) { mem_name = header.member.m_name; if (ext_fl) { if (is_dir(mem_name)) { for (ptr = mem_name; *ptr; ptr++) ; *(ptr - 1) = '\0'; mkdir(mem_name); } else extract(mem_name); } else { string_print(NIL_PTR, "%s%s", mem_name, (verbose_flag ? " " : "\n")); if (header.member.m_linked == '1') { if (verbose_flag) string_print(NIL_PTR, "linked to %s\n", header.member.m_link); } else { if (verbose_flag) string_print(NIL_PTR, "%d tape blocks\n", block_size()); skip_entry(); } } flush(); } } skip_entry() { register int blocks = block_size(); while (blocks--) (void) read(tar_fd, io_buffer, BLOCK_SIZE); } extract(file) register char *file; { register int fd; if (header.member.m_linked == '1') { if (link(header.member.m_link, file) < 0) string_print(NIL_PTR, "Cannot link %s to %s\n", header.member.m_link, file); else if (verbose_flag) string_print(NIL_PTR, "Linked %s to %s\n", header.member.m_link, file); return; } if ((fd = creat(file, 0644)) < 0) { string_print(NIL_PTR, "Cannot create %s\n", file); return; } copy(file, tar_fd, fd, convert(header.member.m_size, LONG_TYPE)); (void) close(fd); chmod(file, (int)convert(header.member.m_mode, INT_TYPE)); if(!chown_flag) { /* set correct owner and group -Dal */ chown(file, (int)convert(header.member.m_uid, INT_TYPE), (int)convert(header.member.m_gid, INT_TYPE)); } /* should the timestamp be updated here?? -Dal */ flush(); } copy(file, from, to, bytes) char *file; int from, to; register long bytes; { register int rest; int blocks = (int) ((bytes + (long) BLOCK_SIZE - 1) / (long) BLOCK_SIZE); if (verbose_flag) string_print(NIL_PTR, "%s, %d tape blocks\n", file, blocks); while (blocks--) { (void) read(from, io_buffer, BLOCK_SIZE); rest = (bytes > (long) BLOCK_SIZE) ? BLOCK_SIZE : (int) bytes; mwrite(to, io_buffer, (to == tar_fd) ? BLOCK_SIZE : rest); bytes -= (long) rest; } } long convert(str, type) char str[]; int type; { register long ac = 0L; register int i; for (i = 0; i < type; i++) { if (str[i] >= '0' && str[i] <= '7') { ac <<= 3; ac += (long) (str[i] - '0'); } } return ac; } mkdir(dir_name) char *dir_name; { register int pid, w; if ((dir_name[0] == '.') && ((dir_name[1] == '\0') || (dir_name[1] == '.'))) return; if ((pid = fork()) < 0) error("Cannot fork().", NIL_PTR); if (pid == 0) { execl(MKDIR, "mkdir", dir_name, (char *) 0); error("Cannot find mkdir.", NIL_PTR); } do { w = wait((int *) 0); } while (w != -1 && w != pid); } checksum() { register char *ptr = header.member.m_checksum; register int ac = 0; while (ptr < &header.member.m_checksum[INT_TYPE]) *ptr++ = ' '; ptr = header.hdr_block; while (ptr < &header.hdr_block[BLOCK_SIZE]) ac += *ptr++; return ac; } is_dir(file) register char *file; { while (*file++ != '\0') ; return (*(file - 2) == '/'); } char *path_name(file) register char *file; { string_print(pathname, "%s%s", path, file); return pathname; } add_path(name) register char *name; { register char *path_ptr = path; while (*path_ptr) path_ptr++; if (name == NIL_PTR) { while (*path_ptr-- != '/') ; while (*path_ptr != '/' && path_ptr != path) path_ptr--; if (*path_ptr == '/') path_ptr++; *path_ptr = '\0'; } else { while (*name) { if (path_ptr == &path[NAME_SIZE]) error("Pathname too long", NIL_PTR); *path_ptr++ = *name++; } *path_ptr++ = '/'; *path_ptr = '\0'; } } add_file(file) register char *file; { struct stat st; struct direct dir; register int fd; char namebuf[16]; /* -Dal */ if (stat(file, &st) < 0) { string_print(NIL_PTR, "Cannot find %s\n", file); return; } if ((fd = open(file, 0)) < 0) { string_print(NIL_PTR, "Cannot open %s\n", file); return; } make_header(path_name(file), &st); if ((st.st_mode & S_IFMT) == S_IFREG) { /* fixed test -Dal */ mwrite(tar_fd, &header, sizeof(header)); copy(path_name(file), fd, tar_fd, st.st_size); } else if ((st.st_mode & S_IFMT) == S_IFDIR) { /* fixed test -Dal */ mwrite(tar_fd, &header, sizeof(header)); if (chdir(file) < 0) string_print(NIL_PTR, "Cannot chdir to %s\n", file); else { add_path(file); mread(fd, &dir, sizeof(dir)); /* "." */ mread(fd, &dir, sizeof(dir)); /* ".." */ while (read(fd, &dir, sizeof(dir)) == sizeof(dir)) if (dir.d_ino) { strncpy(namebuf, dir.d_name, 14); namebuf[14] = '\0'; add_file(namebuf); } chdir(".."); add_path(NIL_PTR); } } else print(" Tar: unknown file type. Not added.\n"); (void) close(fd); } make_header(file, st) char *file; register struct stat *st; { register char *ptr = header.member.m_name; clear_header(); while (*ptr++ = *file++) ; if ((st->st_mode & S_IFMT) == S_IFDIR) { /* fixed test -Dal */ *(ptr - 1) = '/'; st->st_size = 0L; } string_print(header.member.m_mode, "%I ", st->st_mode & 07777); string_print(header.member.m_uid, "%I ", st->st_uid); string_print(header.member.m_gid, "%I ", st->st_gid); string_print(header.member.m_size, "%L ", st->st_size); string_print(header.member.m_time, "%L ", st->st_mtime); header.member.m_linked = ' '; string_print(header.member.m_checksum, "%I ", checksum()); header.member.m_linked = ' '; } clear_header() { register char *ptr = header.hdr_block; while (ptr < &header.hdr_block[BLOCK_SIZE]) *ptr++ = '\0'; } adjust_boundary() { clear_header(); mwrite(tar_fd, &header, sizeof(header)); while (total_blocks++ < BLOCK_BOUNDARY) mwrite(tar_fd, &header, sizeof(header)); (void) close(tar_fd); } mread(fd, address, bytes) int fd, bytes; char *address; { if (read(fd, address, bytes) != bytes) error("Tar: read error.", NIL_PTR); } mwrite(fd, address, bytes) int fd, bytes; char *address; { if (write(fd, address, bytes) != bytes) error("Tar: write error.", NIL_PTR); total_blocks++; } char output[BLOCK_SIZE]; print(str) /* changed to use stderr rather than stdout -Dal */ register char *str; { static int index = 0; if (str == NIL_PTR) { write(2, output, index); index = 0; return; } while (*str) { output[index++] = *str++; if (index == BLOCK_SIZE) { write(2, output, BLOCK_SIZE); index = 0; } } } char *num_out(number) register long number; { static char num_buf[12]; register int i; for (i = 11; i--; ) { num_buf[i] = (number & 07) + '0'; number >>= 3; } return num_buf; } /* VARARGS */ string_print(buffer, fmt, args) char *buffer; register char *fmt; int args; { register char *buf_ptr; char *scan_ptr; char buf[NAME_SIZE]; char *argptr = (char *)&args; BOOL pr_fl, i; if (pr_fl = (buffer == NIL_PTR)) buffer = buf; buf_ptr = buffer; while (*fmt) { if (*fmt == '%') { fmt++; switch (*fmt++) { case 's': scan_ptr = *((char **)argptr); argptr += sizeof(char *); break; case 'I': scan_ptr = num_out((long) *((int *)argptr)); argptr += sizeof(int); for (i = 0; i < 5; i++) scan_ptr++; break; case 'L': scan_ptr = num_out(*((long *) argptr)); argptr += sizeof(long); break; case 'd' : scan_ptr = num_out((long) *((int *)argptr)); argptr += sizeof(int); while (*scan_ptr == '0') scan_ptr++; scan_ptr--; break; default: scan_ptr = ""; } while (*buf_ptr++ = *scan_ptr++) ; buf_ptr--; } else *buf_ptr++ = *fmt++; } *buf_ptr = '\0'; if (pr_fl) print(buffer); } ------------------------------------------------------------------------ \\ / Dale Schumacher 399 Beacon Ave. \\ / (alias: Dalnefre') St. Paul, MN 55104-3527 >< ...umn-cs!midgard.mn.org!syntel!dal United States of America / \\ "What is wanted is not the will to believe, but the will to find out, / \\ which is the exact opposite." -Bertrand Russell
kjh@pollux.usc.edu (Kenneth J. Hendrickson) (02/17/91)
A while ago, there was much comment about tar not working. I just ran into the problem. I did tar c - . | compress | vol 1440 /dev/ps1 and vol -u 1440 /dev/ps1 | uncompress | tar x - . and I found that tar couldn't create directories! :-( THIS MAKES TAR USELESS!!!!! You can't use tar for backup purposes, or for moving files between machines, if any subdirectories are involved. Has anybody fixed this? Or ported some other version of tar? I am trying to set up a new Minix machine, and I need a working tar. Thanks very much for responding either by email, or posting. -- favourite oxymorons: student athlete, military justice, mercy killing Ken Hendrickson N8DGN/6 kjh@usc.edu ...!uunet!usc!pollux!kjh
kjh@pollux.usc.edu (Kenneth J. Hendrickson) (02/17/91)
In reference to getting a working tar for Minix, please don't suggest pdtar unless it is newer than Nov 87. I got that version from uunet.uu.net, and tried to compile it. The standard Minix C compiler (ACK) barfed on it. It appears that /lib/opt was running out of memory, and it had already been chmem'd to the maximum. If there is a working/compilable pdtar for Minix, please tell me where to get it. Thanks very much. -- favourite oxymorons: student athlete, military justice, mercy killing Ken Hendrickson N8DGN/6 kjh@usc.edu ...!uunet!usc!pollux!kjh
EIGALY%yubgef51@pucc.princeton.edu (Cedomir Igaly, +38-41-420-639) (02/18/91)
>A while ago, there was much comment about tar not working. I just ran >into the problem. > >I did tar c - . | compress | vol 1440 /dev/ps1 >and vol -u 1440 /dev/ps1 | uncompress | tar x - . > >and I found that tar couldn't create directories! :-( > >THIS MAKES TAR USELESS!!!!! > >You can't use tar for backup purposes, or for moving files between >machines, if any subdirectories are involved. > >Has anybody fixed this? Or ported some other version of tar? Yes. Tar trying to start mkdir as /bin/mkdir, and you probably have mkdir in /usr/bin. Solution is simple - just put mkdir in /bin, or change definition in tar.c. This last works fine for me. Cedomir Igaly
kjh@pollux.usc.edu (Kenneth J. Hendrickson) (02/18/91)
********** tar solution ********** Make sure you have mkdir in /bin/mkdir. tar requires this, if it has to create any directories. RTFsource code. :-) /* I did. */ -- favourite oxymorons: student athlete, military justice, mercy killing Ken Hendrickson N8DGN/6 kjh@usc.edu ...!uunet!usc!pollux!kjh
root@demug.de.mugnet.org (02/19/91)
In article <30463@usc>, kjh@pollux.usc.edu (Kenneth J. Hendrickson) wrote: > A while ago, there was much comment about tar not working. I just ran > into the problem. > > I did tar c - . | compress | vol 1440 /dev/ps1 > and vol -u 1440 /dev/ps1 | uncompress | tar x - . I always use: (cd /; tar cfv - *) | to TAPEIT with TAPEIT being a command line like: from TAPEIT | (cd /shadow; tar xfv -) on my other ("uwalt") system. This effectively creates a pipe over the Ethernet, and the entire file system of "minixug" will be copied to "uwalt" in directory /shadow. This is done each week. After this backup, "uwalt" starts to yell at its tape drive, which completes the process... Each night, my system does: (cd /; tar cf - etc usr/lib/news usr/lib/uucp usr/spool/mail) | vol 1200 /dev/at0 which backups some important directories to disk each time. It works OK. > and I found that tar couldn't create directories! :-( I must admit: I use John Gilmore's PDTAR program, since that understands about much more types of special files than the MINIX tar. However, the standard MINIX tar does its work OK; it makes directories... > THIS MAKES TAR USELESS!!!!! Yes. What TAR are you using? > You can't use tar for backup purposes, or for moving files between > machines, if any subdirectories are involved. > > Has anybody fixed this? Or ported some other version of tar? See above: use PDTAR, available from me :-). I can post it if you are not the only one interested in it..... > I am trying to set up a new Minix machine, and I need a working tar. > Thanks very much for responding either by email, or posting. Hurray, another MINIX box. Look at this header; this is also a newly set up MINIX machine... :-) Cheers, Fred.
HBO043%DJUKFA11.BITNET@cunyvm.cuny.edu (Christoph van Wuellen) (02/20/91)
I compiled GNU-tar 1.09 just recently, but I have MINIX-68K so I cannot say if it works on a PC. A lot of MINIX stuff has to be REMOVED (the 'MINIX' port handles deficiencies of an early MINIX version, like the open3 stuff etc). C.v.W. P.S. The MINIX tar is unusuable since you cannot specify a blocking factor. Try to write the tar archive to a disk with 1K-sectors and you know what I mean. I got rid of setting up a pipe with a (modified) dd all the time. C.v.W.
kjh@pollux.usc.edu (Kenneth J. Hendrickson) (02/22/91)
In article <910219395@demug.de.mugnet.org> root@demug.de.mugnet.org writes: >I must admit: I use John Gilmore's PDTAR program >See above: use PDTAR, available from me :-). I can post it if you >are not the only one interested in it..... I am very interested. I got the most recent version of pdtar from uunet.uunet, and I found that it wouldn't compile. I didn't even look at it any further. Please post your fixes to pktar. Thank you. -- favourite oxymorons: student athlete, military justice, mercy killing Ken Hendrickson N8DGN/6 kjh@usc.edu ...!uunet!usc!pollux!kjh
klamer@mi.eltn.utwente.nl (Klamer Schutte) (04/08/91)
In <3910@bruce.cs.monash.OZ.AU> cechew@bruce.cs.monash.OZ.AU (Earl Chew) writes: >I wonder how many people have given up on tar and are using gnu-tar or pax? What does the minix society want? You can use minix-tar, but it is only tested on small file systems (I made a lot of changes when i didn't have a hard disk. Also, on an atari (on any 68k machine, or a 386) the memory problems are not a problem -- it aren't really memory leaks, just inefficient ways (when a memory leak is a recursive recurrent alloc-but-no-free problem). For POSIX, we need pax. Do we want a tar as well? If we want, i will incorporate all fixes (approx. 4-5 now) into tar. Please mail me. Or post if general interest. Klamer -- Klamer Schutte Faculty of electrical engineering -- University of Twente, The Netherlands klamer@mi.eltn.utwente.nl {backbone}!mcsun!mi.eltn.utwente.nl!klamer
mitchell@MDI.COM (Bill Mitchell) (04/09/91)
In article <klamer.671112990@mi.eltn.utwente.nl> klamer@mi.eltn.utwente.nl (Klamer Schutte) writes: > >For POSIX, we need pax. Do we want a tar as well? As long as the outside world still uses tar, and there is a possibility that we'll want to be able to un-tar tarfiles generated in the outside world or send tarfiles to someone in the outside world who lacks pax we'll still need tar. Right? -- mitchell@mdi.com (Bill Mitchell)
klamer@mi.eltn.utwente.nl (Klamer Schutte) (04/10/91)
In <1991Apr8.213707.7070@MDI.COM> mitchell@MDI.COM (Bill Mitchell) writes: >In article <klamer.671112990@mi.eltn.utwente.nl> klamer@mi.eltn.utwente.nl (Klamer Schutte) writes: >> >>For POSIX, we need pax. Do we want a tar as well? >As long as the outside world still uses tar, and there is a possibility >that we'll want to be able to un-tar tarfiles generated in the outside >world or send tarfiles to someone in the outside world who lacks pax >we'll still need tar. Right? The current minix tar can read both pax (POSIX tar) and old UNIX tar archives. I will be suprised if pax can't -- but will try it. Klamer -- Klamer Schutte Faculty of electrical engineering -- University of Twente, The Netherlands klamer@mi.eltn.utwente.nl {backbone}!mcsun!mi.eltn.utwente.nl!klamer
X913%DMAFHT1.BITNET@cunyvm.cuny.edu (Martin Sckopke) (04/10/91)
I'm not sure about still needing tar, cause the pax version I know of supports pax, tar and afio. But I also remember it was quite big, so I am not sure if it'll compile and run on PC-Minix. It does run on ST-Minix though. ! This space intentionally Martin Sckopke (X913@DMAFHT1) ! ! left blank.