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