Commit 7acb53eb authored by Aleksey's avatar Aleksey

Add partcp.c

parent 5e04e503
#include <errno.h> // errno
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h> // stat()
#define MiB (1<<20)
// copy data using chunks, MiB
#define CHUNK_SIZE 4
void err (const char* s);
// copy SIZE bytes from SRCFD to DSTFD using buffer BUF
int fcopy (void* buf, size_t size, FILE* srcfd, FILE* dstfd);
off_t fsize (const char* path); // get file size
void perr (const char* s);
long stol (const char* s); // strtol() wrapper
int main (int argc, char** argv)
FILE *srcfd, *dstfd;
char *srcpath, *dstpath;
off_t srcsize; // source file size
long off, len; // slice offset and length
int status;
if (argc != 5)
err ("Usage: partcp source_file slice_offset slice_length destination_file");
srcpath = argv[1];
dstpath = argv[4];
if (strcmp (srcpath, dstpath) == 0)
err ("SOURCE and DESTINATION must be different files");
srcsize = fsize (srcpath);
if (srcsize == 0) err ("Nothing to copy: source file is empty");
off = stol (argv[2]);
if (off < 0 || off > (srcsize-1)) err ("Wrong OFFSET for source file");
len = stol (argv[3]);
if (len < 1 || len > (srcsize-off)) err ("Wrong LENGTH for source file");
srcfd = fopen (srcpath, "r");
if (srcfd == NULL) perr ("Error opening source file");
status = EXIT_FAILURE;
dstfd = fopen (dstpath, "w");
if (dstfd == NULL) {
perror ("Error opening destination file");
goto close_src;
if (fseek (srcfd, off, SEEK_SET) == -1) {
perror ("Error seeking source file");
goto close_dst;
/* copy LEN bytes using chunks and remainder:
len = num * (CHUNK_SIZE * MiB) + rem */
void* buf; // memory buffer
size, // buf size
num, // number of chunks to copy
rem, // length of remainder
size = CHUNK_SIZE * MiB;
num = len / size;
if (num == 0) size = rem = len; // if (len<CHUNK_SIZE) buf=malloc(len)
else rem = len % size; // else buf=malloc(CHUNK_SIZE)
buf = malloc (size);
if (buf == NULL) {
perror ("Memory allocation error");
goto close_dst;
// copy NUM chunks
for (i=0; i<num; i++)
if (fcopy (buf, size, srcfd, dstfd) == -1)
goto free_buf;
// copy remainder
if (rem != 0)
if (fcopy (buf, rem, srcfd, dstfd) == -1)
goto free_buf;
// copying is complete
status = EXIT_SUCCESS;
puts ("Success");
free (buf);
if (fclose (dstfd) == EOF) perror ("Error closing destination file");
if (fclose (srcfd) == EOF) perror ("Error closing source file");
exit (status);
void err (const char* s)
fprintf (stderr, "%s\n", s);
int fcopy (void* buf, size_t size, FILE* srcfd, FILE* dstfd)
if (fread (buf, size, 1, srcfd) == 0) {
if (ferror (srcfd)) perror ("Error reading source file");
else fputs ("Unexpected end of source file\n", stderr); // should not happen
return -1;
if (fwrite (buf, size, 1, dstfd) == 0) {
perror ("Error writing destination file");
return -1;
return 0;
off_t fsize (const char* path)
struct stat s;
if (stat (path, &s) == -1) perr ("Unable to get source file size");
return s.st_size;
void perr (const char* s)
perror (s);
long stol (const char* s)
long ret;
errno = 0;
ret = strtol (s, NULL, 0); // can also read hex (0x...), octal (0...) values
if (errno) perr ("Unable to read command line parameter");
return ret;
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment