146003Sbostic /*- 246003Sbostic * Copyright (c) 1990 The Regents of the University of California. 346003Sbostic * All rights reserved. 446003Sbostic * 546003Sbostic * This code is derived from software contributed to Berkeley by 646003Sbostic * Hugh Smith at The University of Guelph. 746003Sbostic * 846003Sbostic * %sccs.include.redist.c% 946003Sbostic */ 1046003Sbostic 1146003Sbostic #ifndef lint 12*46009Sbostic static char sccsid[] = "@(#)replace.c 5.2 (Berkeley) 01/18/91"; 1346003Sbostic #endif /* not lint */ 1446003Sbostic 1546003Sbostic #include <sys/param.h> 1646003Sbostic #include <sys/stat.h> 1746003Sbostic #include <sys/errno.h> 1846003Sbostic #include <fcntl.h> 1946003Sbostic #include <unistd.h> 2046003Sbostic #include <dirent.h> 2146003Sbostic #include <ar.h> 2246003Sbostic #include <stdio.h> 2346003Sbostic #include "archive.h" 2446003Sbostic 2546003Sbostic extern CHDR chdr; /* converted header */ 2646003Sbostic extern char *archive; /* archive name */ 2746003Sbostic extern char *tname; /* temporary file "name" */ 2846003Sbostic 2946003Sbostic /* 3046003Sbostic * replace -- 3146003Sbostic * Replace or add named members to archive. Entries already in the 3246003Sbostic * archive are swapped in place. Others are added before or after 3346003Sbostic * the key entry, based on the a, b and i options. If the u option 3446003Sbostic * is specified, modification dates select for replacement. 3546003Sbostic */ 3646003Sbostic replace(argv) 3746003Sbostic char **argv; 3846003Sbostic { 3946003Sbostic extern char *posname; /* positioning file name */ 4046003Sbostic register char *file; 4146003Sbostic register int afd, curfd, mods, sfd; 4246003Sbostic struct stat sb; 4346003Sbostic CF cf; 4446003Sbostic off_t size, tsize; 4546003Sbostic int err, exists, tfd1, tfd2; 4646003Sbostic char *rname(); 4746003Sbostic 4846003Sbostic /* 4946003Sbostic * If doesn't exist, simply append to the archive. There's 5046003Sbostic * a race here, but it's pretty short, and not worth fixing. 5146003Sbostic */ 5246003Sbostic exists = !stat(archive, &sb); 5346003Sbostic afd = open_archive(O_CREAT|O_RDWR); 5446003Sbostic 5546003Sbostic if (!exists) { 5646003Sbostic tfd1 = -1; 5746003Sbostic tfd2 = tmp(); 5846003Sbostic goto append; 5946003Sbostic } 6046003Sbostic 6146003Sbostic tfd1 = tmp(); /* Files before key file. */ 6246003Sbostic tfd2 = tmp(); /* Files after key file. */ 6346003Sbostic 6446003Sbostic /* 6546003Sbostic * Break archive into two parts -- entries before and after the key 6646003Sbostic * entry. If positioning before the key, place the key at the 6746003Sbostic * beginning of the after key entries and if positioning after the 6846003Sbostic * key, place the key at the end of the before key entries. Put it 6946003Sbostic * all back together at the end. 7046003Sbostic */ 71*46009Sbostic mods = (options & (AR_A|AR_B)); 7246003Sbostic for (err = 0, curfd = tfd1; get_header(afd);) { 7346003Sbostic if ((file = *argv) && files(argv)) { 7446003Sbostic if ((sfd = open(file, O_RDONLY)) < 0) { 7546003Sbostic err = 1; 7646003Sbostic (void)fprintf(stderr, "ar: %s: %s.\n", 7746003Sbostic file, strerror(errno)); 7846003Sbostic goto useold; 7946003Sbostic } 8046003Sbostic (void)fstat(sfd, &sb); 8146003Sbostic if (options & AR_U && sb.st_mtime <= chdr.date) 8246003Sbostic goto useold; 8346003Sbostic 8446003Sbostic if (options & AR_V) 8546003Sbostic (void)printf("r - %s\n", chdr.name); 8646003Sbostic 8746003Sbostic SETCF(sfd, file, curfd, tname, WPAD); 8846003Sbostic put_header(&cf, &sb); 8946003Sbostic copyfile(&cf, sb.st_size); 9046003Sbostic (void)close(sfd); 9146003Sbostic SKIP(afd, chdr.size, archive); 9246003Sbostic continue; 9346003Sbostic } 9446003Sbostic 9546003Sbostic if (mods && compare(posname)) { 9646003Sbostic mods = 0; 9746003Sbostic if (options & AR_B) 9846003Sbostic curfd = tfd2; 9946003Sbostic SETCF(afd, archive, curfd, tname, RPAD|WPAD); 10046003Sbostic put_header(&cf, (struct stat *)NULL); 10146003Sbostic copyfile(&cf, chdr.size); 10246003Sbostic if (options & AR_A) 10346003Sbostic curfd = tfd2; 10446003Sbostic } else { 10546003Sbostic useold: SETCF(afd, archive, curfd, tname, RPAD|WPAD); 10646003Sbostic put_header(&cf, (struct stat *)NULL); 10746003Sbostic copyfile(&cf, chdr.size); 10846003Sbostic } 10946003Sbostic } 11046003Sbostic 11146003Sbostic if (mods) { 11246003Sbostic (void)fprintf(stderr, "ar: %s: archive member not found.\n", 11346003Sbostic posname); 11446003Sbostic close_archive(afd); 11546003Sbostic return(1); 11646003Sbostic } 11746003Sbostic 11846003Sbostic /* Append any left-over arguments to the end of the after file. */ 11946003Sbostic append: while (file = *argv++) { 12046003Sbostic if (options & AR_V) 12146003Sbostic (void)printf("a - %s\n", rname(file)); 12246003Sbostic if ((sfd = open(file, O_RDONLY)) < 0) { 12346003Sbostic err = 1; 12446003Sbostic (void)fprintf(stderr, "ar: %s: %s.\n", 12546003Sbostic file, strerror(errno)); 12646003Sbostic continue; 12746003Sbostic } 12846003Sbostic (void)fstat(sfd, &sb); 129*46009Sbostic SETCF(sfd, file, 130*46009Sbostic options & (AR_A|AR_B) ? tfd1 : tfd2, tname, WPAD); 13146003Sbostic put_header(&cf, &sb); 13246003Sbostic copyfile(&cf, sb.st_size); 13346003Sbostic (void)close(sfd); 13446003Sbostic } 13546003Sbostic 13646003Sbostic (void)lseek(afd, (off_t)SARMAG, SEEK_SET); 13746003Sbostic 13846003Sbostic SETCF(tfd1, tname, afd, archive, RPAD|WPAD); 13946003Sbostic if (tfd1 != -1) { 14046003Sbostic tsize = size = lseek(tfd1, (off_t)0, SEEK_CUR); 14146003Sbostic (void)lseek(tfd1, (off_t)0, SEEK_SET); 14246003Sbostic copyfile(&cf, size); 14346003Sbostic } else 14446003Sbostic tsize = 0; 14546003Sbostic 14646003Sbostic tsize += size = lseek(tfd2, (off_t)0, SEEK_CUR); 14746003Sbostic (void)lseek(tfd2, (off_t)0, SEEK_SET); 14846003Sbostic cf.rfd = tfd2; 14946003Sbostic copyfile(&cf, size); 15046003Sbostic 15146003Sbostic (void)ftruncate(afd, tsize + SARMAG); 15246003Sbostic close_archive(afd); 15346003Sbostic return(err); 15446003Sbostic } 155