📄 dd.c
字号:
(void)memset(out.dbp, 0, out.dbsz - out.dbcnt); out.dbcnt = out.dbsz; } /* If there are pending sparse blocks, make sure * to write out the final block un-sparse */ if ((out.dbcnt == 0) && pending) { memset(out.db, 0, out.dbsz); out.dbcnt = out.dbsz; out.dbp = out.db + out.dbcnt; pending -= out.dbsz; } if (out.dbcnt) dd_out(1); /* * Reporting nfs write error may be defered until next * write(2) or close(2) system call. So, we need to do an * extra check. If an output is stdout, the file structure * may be shared among with other processes and close(2) just * decreases the reference count. */ if (out.fd == STDOUT_FILENO && fsync(out.fd) == -1 && errno != EINVAL) { fprintf(stderr, "fsync stdout: %s\n", strerror(errno)); exit(1); /* NOTREACHED */ } if (close(out.fd) == -1) { fprintf(stderr, "close: %s\n", strerror(errno)); exit(1); /* NOTREACHED */ }}voiddd_out(int force){ static int warned; int64_t cnt, n, nw; u_char *outp; /* * Write one or more blocks out. The common case is writing a full * output block in a single write; increment the full block stats. * Otherwise, we're into partial block writes. If a partial write, * and it's a character device, just warn. If a tape device, quit. * * The partial writes represent two cases. 1: Where the input block * was less than expected so the output block was less than expected. * 2: Where the input block was the right size but we were forced to * write the block in multiple chunks. The original versions of dd(1) * never wrote a block in more than a single write, so the latter case * never happened. * * One special case is if we're forced to do the write -- in that case * we play games with the buffer size, and it's usually a partial write. */ outp = out.db; for (n = force ? out.dbcnt : out.dbsz;; n = out.dbsz) { for (cnt = n;; cnt -= nw) { if (!force && ddflags & C_SPARSE) { int sparse, i; sparse = 1; /* Is buffer sparse? */ for (i = 0; i < cnt; i++) if (outp[i] != 0) { sparse = 0; break; } if (sparse) { pending += cnt; outp += cnt; nw = 0; break; } } if (pending != 0) { if (lseek(out.fd, pending, SEEK_CUR) == -1) { fprintf(stderr, "%s: seek error creating " "sparse file: %s\n", out.name, strerror(errno)); exit(1); } } nw = bwrite(out.fd, outp, cnt); if (nw <= 0) { if (nw == 0) { fprintf(stderr, "%s: end of device\n", out.name); exit(1); /* NOTREACHED */ } if (errno != EINTR) { fprintf(stderr, "%s: write error: %s\n", out.name, strerror(errno)); /* NOTREACHED */ exit(1); } nw = 0; } if (pending) { st.bytes += pending; st.sparse += pending/out.dbsz; st.out_full += pending/out.dbsz; pending = 0; } outp += nw; st.bytes += nw; if (nw == n) { if (n != out.dbsz) ++st.out_part; else ++st.out_full; break; } ++st.out_part; if (nw == cnt) break; if (out.flags & ISCHR && !warned) { warned = 1; fprintf(stderr, "%s: short write on character " "device\n", out.name); } if (out.flags & ISTAPE) { fprintf(stderr, "%s: short write on tape device", out.name); exit(1); /* NOTREACHED */ } } if ((out.dbcnt -= n) < out.dbsz) break; } /* Reassemble the output block. */ if (out.dbcnt) (void)memmove(out.db, out.dbp - out.dbcnt, out.dbcnt); out.dbp = out.db + out.dbcnt; if (progress) (void)write(STDERR_FILENO, ".", 1);}/* * A protected against SIGINFO write */ssize_tbwrite(int fd, const void *buf, size_t len){ sigset_t oset; ssize_t rv; int oerrno; (void)sigprocmask(SIG_BLOCK, &infoset, &oset); rv = write(fd, buf, len); oerrno = errno; (void)sigprocmask(SIG_SETMASK, &oset, NULL); errno = oerrno; return (rv);}/* * Position input/output data streams before starting the copy. Device type * dependent. Seekable devices use lseek, and the rest position by reading. * Seeking past the end of file can cause null blocks to be written to the * output. */voidpos_in(void){ int bcnt, cnt, nr, warned; /* If not a pipe or tape device, try to seek on it. */ if (!(in.flags & (ISPIPE|ISTAPE))) { if (lseek(in.fd, (off_t)in.offset * (off_t)in.dbsz, SEEK_CUR) == -1) { fprintf(stderr, "%s: seek error: %s", in.name, strerror(errno)); exit(1); /* NOTREACHED */ } return; /* NOTREACHED */ } /* * Read the data. If a pipe, read until satisfy the number of bytes * being skipped. No differentiation for reading complete and partial * blocks for other devices. */ for (bcnt = in.dbsz, cnt = in.offset, warned = 0; cnt;) { if ((nr = read(in.fd, in.db, bcnt)) > 0) { if (in.flags & ISPIPE) { if (!(bcnt -= nr)) { bcnt = in.dbsz; --cnt; } } else --cnt; continue; } if (nr == 0) { if (files_cnt > 1) { --files_cnt; continue; } fprintf(stderr, "skip reached end of input\n"); exit(1); /* NOTREACHED */ } /* * Input error -- either EOF with no more files, or I/O error. * If noerror not set die. POSIX requires that the warning * message be followed by an I/O display. */ if (ddflags & C_NOERROR) { if (!warned) { fprintf(stderr, "%s: error occurred\n", in.name); warned = 1; summary(); } continue; } fprintf(stderr, "%s: read error: %s", in.name, strerror(errno)); exit(1); /* NOTREACHED */ }}voidpos_out(void){// struct mtop t_op; int cnt, n; /* * If not a tape, try seeking on the file. Seeking on a pipe is * going to fail, but don't protect the user -- they shouldn't * have specified the seek operand. */ if (!(out.flags & ISTAPE)) { if (lseek(out.fd, (off_t)out.offset * (off_t)out.dbsz, SEEK_SET) == -1) { fprintf(stderr, "%s: seek error: %s\n", out.name, strerror(errno)); exit(1); /* NOTREACHED */ } return; } /* If no read access, try using mtio. */ if (out.flags & NOREAD) {/* t_op.mt_op = MTFSR; t_op.mt_count = out.offset; if (ioctl(out.fd, MTIOCTOP, &t_op) < 0)*/ fprintf(stderr, "%s: cannot read", out.name); exit(1); /* NOTREACHED */ return; } /* Read it. */ for (cnt = 0; cnt < out.offset; ++cnt) { if ((n = read(out.fd, out.db, out.dbsz)) > 0) continue; if (n < 0) { fprintf(stderr, "%s: cannot position by reading: %s\n", out.name, strerror(errno)); exit(1); /* NOTREACHED */ } /* * If reach EOF, fill with NUL characters; first, back up over * the EOF mark. Note, cnt has not yet been incremented, so * the EOF read does not count as a seek'd block. *//* t_op.mt_op = MTBSR; t_op.mt_count = 1; if (ioctl(out.fd, MTIOCTOP, &t_op) == -1) */ { fprintf(stderr, "%s: cannot position\n", out.name); exit(1); /* NOTREACHED */ } while (cnt++ < out.offset) if ((n = bwrite(out.fd, out.db, out.dbsz)) != out.dbsz) { fprintf(stderr, "%s: cannot position " "by writing: %s\n", out.name, strerror(errno)); exit(1); /* NOTREACHED */ } break; }}/* * def -- * Copy input to output. Input is buffered until reaches obs, and then * output until less than obs remains. Only a single buffer is used. * Worst case buffer calculation is (ibs + obs - 1). */voiddef(void){ uint64_t cnt; u_char *inp; const u_char *t; if ((t = ctab) != NULL) for (inp = in.dbp - (cnt = in.dbrcnt); cnt--; ++inp) *inp = t[*inp]; /* Make the output buffer look right. */ out.dbp = in.dbp; out.dbcnt = in.dbcnt; if (in.dbcnt >= out.dbsz) { /* If the output buffer is full, write it. */ dd_out(0); /* * Ddout copies the leftover output to the beginning of * the buffer and resets the output buffer. Reset the * input buffer to match it. */ in.dbp = out.dbp; in.dbcnt = out.dbcnt; }}voiddef_close(void){ /* Just update the count, everything is already in the buffer. */ if (in.dbcnt) out.dbcnt = in.dbcnt;}#ifdef NO_CONV/* Build a smaller version (i.e. for a miniroot) *//* These can not be called, but just in case... */static const char no_block[] = "unblock and -DNO_CONV?\n";void block(void) { fprintf(stderr, "%s", no_block + 2); exit(1); }void block_close(void) { fprintf(stderr, "%s", no_block + 2); exit(1); }void unblock(void) { fprintf(stderr, "%s", no_block); exit(1); }void unblock_close(void) { fprintf(stderr, "%s", no_block); exit(1); }#else /* NO_CONV *//* * Copy variable length newline terminated records with a max size cbsz * bytes to output. Records less than cbs are padded with spaces. * * max in buffer: MAX(ibs, cbsz) * max out buffer: obs + cbsz */voidblock(void){ static int intrunc; int ch = 0; /* pacify gcc */ uint64_t cnt, maxlen; u_char *inp, *outp; const u_char *t; /* * Record truncation can cross block boundaries. If currently in a * truncation state, keep tossing characters until reach a newline. * Start at the beginning of the buffer, as the input buffer is always * left empty. */ if (intrunc) { for (inp = in.db, cnt = in.dbrcnt; cnt && *inp++ != '\n'; --cnt); if (!cnt) { in.dbcnt = 0; in.dbp = in.db; return; } intrunc = 0; /* Adjust the input buffer numbers. */ in.dbcnt = cnt - 1; in.dbp = inp + cnt - 1; } /* * Copy records (max cbsz size chunks) into the output buffer. The * translation is done as we copy into the output buffer. */ for (inp = in.dbp - in.dbcnt, outp = out.dbp; in.dbcnt;) { maxlen = MIN(cbsz, in.dbcnt); if ((t = ctab) != NULL) for (cnt = 0; cnt < maxlen && (ch = *inp++) != '\n'; ++cnt) *outp++ = t[ch]; else for (cnt = 0; cnt < maxlen && (ch = *inp++) != '\n'; ++cnt) *outp++ = ch; /* * Check for short record without a newline. Reassemble the * input block. */ if (ch != '\n' && in.dbcnt < cbsz) { (void)memmove(in.db, in.dbp - in.dbcnt, in.dbcnt); break; } /* Adjust the input buffer numbers. */ in.dbcnt -= cnt; if (ch == '\n') --in.dbcnt; /* Pad short records with spaces. */ if (cnt < cbsz) (void)memset(outp, ctab ? ctab[' '] : ' ', cbsz - cnt); else { /* * If the next character wouldn't have ended the * block, it's a truncation. */ if (!in.dbcnt || *inp != '\n') ++st.trunc; /* Toss characters to a newline. */ for (; in.dbcnt && *inp++ != '\n'; --in.dbcnt); if (!in.dbcnt) intrunc = 1; else --in.dbcnt; } /* Adjust output buffer numbers. */ out.dbp += cbsz; if ((out.dbcnt += cbsz) >= out.dbsz) dd_out(0); outp = out.dbp; } in.dbp = in.db + in.dbcnt;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -