Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /* simple copy of 'srcfile' to 'destfile' using sendfile
- *
- * options:
- * -h display help
- * -o offset begin copy from srcfile at offset-bytes
- * -n nbytes copy only nbytes-bytes from src to dest
- * -v display verbose ouotput
- *
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <sys/sendfile.h>
- #include <sys/stat.h>
- #include <sys/types.h>
- #include <unistd.h>
- #define PACKAGE "sfcopy"
- #define VERSION "0.01"
- #define MAXARGS 10
- /* note: on non-GNU systems, implement macros as functions, the
- * braced grouping is not ISO-C
- */
- /* simple macro to open file and validate the return */
- #define xopenro(fn, flags) \
- ({ int fd = open (fn, flags); \
- if (fd == -1) { \
- fprintf (stderr, "xopen() error: file open failed '%s'.\n", fn); \
- exit (EXIT_FAILURE); \
- } \
- fd; \
- })
- /* simple macro to open file with creation mode flags and
- * validate the return of open
- */
- #define xopencrt(fn, flags, mode) \
- ({ int fd = open (fn, flags, mode); \
- if (fd == -1) { \
- fprintf (stderr, "xopen() error: file open failed '%s'.\n", fn); \
- exit (EXIT_FAILURE); \
- } \
- fd; \
- })
- int processopts (int argc, char **argv, long (*lv)[10]);
- long file_sfcopy (char *ofn, char *ifn, off_t *offset, long *nbytes);
- void help (int xcode);
- int main (int argc, char **argv) {
- long lv[MAXARGS] = {0};
- int optind = processopts (argc, argv, &lv);
- off_t offset = lv[0];
- long nbytes = lv[1], verbose = lv[2];
- char *ifn = argc > optind ? argv[optind] : NULL,
- *ofn = argc > optind + 1 ? argv[optind + 1] : NULL;
- #ifdef DEBUG
- printf (" nbytes : %ld\n verbose : %ld\n infile : %s\n outfile : %s\n\n",
- nbytes, verbose, ifn ? ifn : "stdin", ofn ? ofn : "stdout");
- #endif
- if (verbose) { /* provide verbose output */
- printf ("copying %s -> %s\n", ifn ? ifn : "stdin",
- ofn ? ofn : "stdout");
- }
- if (file_sfcopy (ofn, ifn, &offset, &nbytes) == -1) {
- fprintf (stderr, "error: file_sfcopy returned -1\n");
- }
- if (verbose) printf ("%ld bytes copied.\n", nbytes);
- return 0;
- }
- /** copy input file name 'ifn' to output file name 'ofn'
- * using sendfile to perform copy in kernel space. copy
- * speed is equivalent to memcopy of mmap'ed files.
- * returns the number of bytes copied on success, -1
- * otherwise. (include: off_t offset to start copy at
- * location other than beginning of 'ifn'.
- */
- long file_sfcopy (char *ofn, char *ifn, off_t *offset, long *nbytes)
- {
- int ifd, ofd, writeok = 1;
- struct stat sb = {0};
- /* open input file read-only, assign file descriptor */
- ifd = ifn ? xopenro (ifn, O_RDONLY) : STDIN_FILENO;
- if (fstat (ifd, &sb) == -1) { /* fill stat buffer */
- fprintf (stderr, "error: undetermined input file size.\n");
- return -1;
- }
- /* open output file for writing with same ownership/permission */
- ofd = ofn ? xopencrt (ofn, O_RDWR|O_CREAT|O_TRUNC, sb.st_mode) :
- STDOUT_FILENO;
- if (!ifd || !ofd) { /* validate file descriptors */
- fprintf (stderr, "error: invalid file descriptor.\n");
- return -1;
- }
- /* validate offset less than st_size */
- if (*offset >= sb.st_size) {
- fprintf (stderr, "error: requested offset exceeds file size.\n");
- return -1;
- }
- /* copy lesser of *nbytes or st_size. (default: st_size) */
- *nbytes = *nbytes + *offset > sb.st_size || !(*nbytes) ?
- sb.st_size - *offset : *nbytes;
- /* use sendfile to copy input to output */
- if (sendfile (ofd, ifd, offset, *nbytes) != *nbytes) {
- fprintf (stderr, "error: sendfile write failure.\n");
- writeok = 0;
- }
- /* if to stdout, tidy up output to insure final newline written */
- if (ofd == STDOUT_FILENO) { /* check last char */
- if (lseek (ifd, *offset > 0 ? *offset - 1 : 0, SEEK_SET) != -1) {
- int c; /* if not '\n' write newline to stdout */
- if (read (ifd, &c, 1) != -1 && c != '\n')
- putchar ('\n');
- }
- else
- fprintf (stderr, "error: lseek of ifd failed.\n");
- }
- else /* validate close of file descriptors */
- if (close (ofd) == EIO)
- fprintf (stderr, "error: I/O error on output descriptor close.\n");
- if (ifd != STDIN_FILENO)
- if (close (ifd) == EIO) /* validate close of file descriptors */
- fprintf (stderr, "error: I/O error on input descriptor close.\n");
- /* without sdtout cleanup, simply close files validating close, e.g. */
- /*
- if (ifd != STDIN_FILENO)
- if (close (ifd) == EIO)
- fprintf (stderr, "error: I/O error on input descriptor close.\n");
- if (ofd == STDOUT_FILENO)
- if (close (ofd) == EIO)
- fprintf (stderr, "error: I/O error on output descriptor close.\n");
- */
- return writeok ? *nbytes : -1;
- }
- /* process -h, -o offset, -n nbytes and -v options */
- int processopts (int argc, char **argv, long (*lv)[10])
- {
- int opt;
- while ((opt = getopt (argc, argv, "ho:n:v")) != -1) {
- switch (opt) {
- case 'h':
- help (0);
- case 'o': /* set offset */
- (*lv)[0] = strtol (optarg, NULL, 10);
- break;
- case 'n': /* set number of bytes */
- (*lv)[1] = strtol (optarg, NULL, 10);
- break;
- case 'v': /* set verbose */
- (*lv)[2] = 1;
- break;
- }
- }
- if (argc < 2) { /* if insufficient input */
- fprintf (stderr, "error: insufficient arguments.\n");
- help (1);
- }
- return optind; /* return next argument index */
- }
- /* simple help function, exits with xcode */
- void help (int xcode)
- {
- printf ("\n %s, version %s\n\n"
- " usage: %s [-honv] srcfile destfile\n\n"
- " copies srcfile to destfile using sendfile (limit: 2,147,479,552"
- " bytes).\n"
- " if only srcfile is given, copy to stdout.\n\n"
- " Options:\n"
- " -h this help.\n"
- " -o offset begin copy from srcfile at offset-bytes.\n"
- " -n nbytes copy only nbytes-bytes from src to dest.\n"
- " -v verbose ouotput.\n\n",
- PACKAGE, VERSION, PACKAGE);
- exit (xcode);
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement