1 /*- 2 * Copyright (c) 1991 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Keith Muller of the University of California, San Diego and Lance 7 * Visser of Convex Computer Corporation. 8 * 9 * %sccs.include.redist.c% 10 */ 11 12 #ifndef lint 13 static char sccsid[] = "@(#)position.c 5.2 (Berkeley) 07/27/91"; 14 #endif /* not lint */ 15 16 #include <sys/types.h> 17 #include <sys/stat.h> 18 #include <sys/ioctl.h> 19 #include <sys/mtio.h> 20 #include <errno.h> 21 #include <unistd.h> 22 #include <string.h> 23 #include "dd.h" 24 #include "extern.h" 25 26 /* 27 * Position input/output data streams before starting the copy. Device type 28 * dependent. Seekable devices use lseek, and the rest position by reading. 29 * Seeking past the end of file can cause null blocks to be written to the 30 * output. 31 */ 32 void 33 pos_in() 34 { 35 register int bcnt, cnt, nr, warned; 36 37 /* If not a character, pipe or tape device, try to seek on it. */ 38 if (!(in.flags & (ISCHR|ISPIPE|ISTAPE))) { 39 if (lseek(in.fd, (off_t)(in.offset * in.dbsz), SEEK_CUR) == -1) 40 err("%s: %s", in.name, strerror(errno)); 41 return; 42 } 43 44 /* 45 * Read the data. If a pipe, read until satisfy the number of bytes 46 * being skipped. No differentiation for reading complete and partial 47 * blocks for other devices. 48 */ 49 for (bcnt = in.dbsz, cnt = in.offset, warned = 0; cnt;) { 50 if ((nr = read(in.fd, in.db, bcnt)) > 0) 51 if (in.flags & ISPIPE) { 52 if (!(bcnt -= nr)) { 53 bcnt = in.dbsz; 54 --cnt; 55 } 56 continue; 57 } else 58 --cnt; 59 60 if (nr == 0) { 61 if (files_cnt > 1) { 62 --files_cnt; 63 continue; 64 } 65 err("skip reached end of input"); 66 } 67 68 /* 69 * Input error -- either EOF with no more files, or I/O error. 70 * If noerror not set die. POSIX requires that the warning 71 * message be followed by an I/O display. 72 */ 73 if (ddflags & C_NOERROR) { 74 if (!warned) { 75 warn("%s: %s", in.name, strerror(errno)); 76 warned = 1; 77 summary(0); 78 } 79 continue; 80 } 81 err("%s: %s", in.name, strerror(errno)); 82 } 83 } 84 85 void 86 pos_out() 87 { 88 register int cnt, n; 89 struct mtop t_op; 90 91 /* 92 * If not a tape, try seeking on the file. Seeking on a pipe is 93 * going to fail, but don't protect the user -- they shouldn't 94 * have specified the seek operand. 95 */ 96 if (!(out.flags & ISTAPE)) { 97 if (lseek(out.fd, 98 (off_t)out.offset * out.dbsz, SEEK_SET) == -1) 99 err("%s: %s", out.name, strerror(errno)); 100 return; 101 } 102 103 /* If no read access, try using mtio. */ 104 if (out.flags & NOREAD) { 105 t_op.mt_op = MTFSR; 106 t_op.mt_count = out.offset; 107 108 if (ioctl(out.fd, MTIOCTOP, &t_op) < 0) 109 err("%s: %s", out.name, strerror(errno)); 110 return; 111 } 112 113 /* Read it. */ 114 for (cnt = 0; cnt < out.offset; ++cnt) { 115 if ((n = read(out.fd, out.db, out.dbsz)) > 0) 116 continue; 117 118 if (n < 0) 119 err("%s: %s", out.name, strerror(errno)); 120 121 /* 122 * If reach EOF, fill with NUL characters; first, back up over 123 * the EOF mark. Note, cnt has not yet been incremented, so 124 * the EOF read does not count as a seek'd block. 125 */ 126 t_op.mt_op = MTBSR; 127 t_op.mt_count = 1; 128 if (ioctl(out.fd, MTIOCTOP, &t_op) == -1) 129 err("%s: %s", out.name, strerror(errno)); 130 131 while (cnt++ < out.offset) 132 if ((n = write(out.fd, out.db, out.dbsz)) != out.dbsz) 133 err("%s: %s", out.name, strerror(errno)); 134 break; 135 } 136 } 137