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