Просьба проверить учебную программу на языке Си на наличие ошибок.
Программа предназначена для копирования фрагмента файла source в файл destination. Фрагмент задается смещением offset, длиной length.
Утилита dd выполняет указанную задачу медленно при условии, что bs < 512 байт.
Порядок сборки программы:
cc -Wall -Wextra -O2 -o subcp subcp.c
Порядок запуска:
./subcp source_file fragment_offset fragment_length destination_file
В случае обнаружения ошибок, недочетов в программе просьба сообщить.
Спасибо.
Исходный код файла «subcp.c»:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h> // stat()
#define MiB (1<<20)
void err (const char* s); // show error message and exit
int fcopy (void* buf, size_t size, FILE* srcfd, FILE* dstfd); // copy SIZE bytes from SRCFD to DSTFD using buffer BUF
off_t fsize (const char* path); // get file size
void perr (const char* s); // show perror(s) and exit
long stol (const char* s); // strtol() wrapper
int main (int argc, char** argv)
{
FILE *srcfd, *dstfd; // source, destination file descriptor
char *srcpath, *dstpath; // source, destination file name
off_t srcsize; // source file size
long off, len; // offset and length of fragment to be copied
int status; // exit status
if (argc != 5) err ("Usage: cpy SRC OFF LEN DST");
srcpath = argv[1];
dstpath = argv[4];
if (strcmp (srcpath, dstpath) == 0) err ("SRC and DST should be different files");
srcsize = fsize (srcpath);
if (srcsize == 0) err ("nothing to copy: SRC file is empty");
off = stol (argv[2]);
if (off < 0 || off > (srcsize-1)) err ("wrong OFF value for use with SRC file");
len = stol (argv[3]);
if (len < 1 || len > (srcsize-off)) err ("wrong LEN value for use with SRC file");
printf ("SRCSIZE=%ld, OFF=%ld, LEN=%ld\n", srcsize, off, len); // PRINT DEBUG INFO
srcfd = fopen (srcpath, "rb");
if (srcfd == NULL) perr ("fopen(SRC)");
status = EXIT_FAILURE;
dstfd = fopen (dstpath, "wb");
if (dstfd == NULL) {
perror ("fopen(DST)");
goto close_src;
}
// set offset for SRCFD file
if (fseek (srcfd, off, SEEK_SET) == -1) {
perror ("fseek(SRC)");
goto close_dst;
}
/* copy "len" bytes from SRCFD to DSTFD using 64M chunks and remainder:
len = num * 64M + rem */
{
void* buf; // memory buffer
size_t
size, // buf size
num, // number of 64M chunks to copy
rem, // length of remainder
i;
size = 64 * MiB;
num = len / size;
if (num == 0) size = rem = len; // if (len < 64M) buf = malloc (len)
else rem = len % size; // else calculate "rem"; buf = malloc (64M)
buf = malloc (size);
if (buf == NULL) {
perror ("malloc");
goto free_buf;
}
// copy 64M chunks
for (i=0; i<num; i++)
if (fcopy (buf, size, srcfd, dstfd) == -1)
goto free_buf;
// copy fragment remainder
if (rem != 0)
if (fcopy (buf, rem, srcfd, dstfd) == -1)
goto free_buf;
// copying complete
status = EXIT_SUCCESS;
free_buf:
free (buf);
}
close_dst:
if (fclose (dstfd) == EOF) perror ("fclose(DST)");
close_src:
if (fclose (srcfd) == EOF) perror ("fclose(SRC)");
exit (status);
}
void err (const char* s) {
fprintf (stderr, "%s\n", s);
exit (EXIT_FAILURE);
}
int fcopy (void* buf, size_t size, FILE* srcfd, FILE* dstfd) {
if (fread (buf, size, 1, srcfd) == 0) {
if (ferror (srcfd)) perror ("fread(SRC)");
else fputs ("unexpected end of SRC file\n", stderr); // should not happen
return -1;
}
if (fwrite (buf, size, 1, dstfd) == 0) {
perror ("fwrite(DST)");
return -1;
}
return 0;
}
off_t fsize (const char* path) {
struct stat s;
if (stat (path, &s) == -1) perr ("stat(SRC)");
return s.st_size;
}
void perr (const char* s) {
perror (s);
exit (EXIT_FAILURE);
}
long stol (const char* s) {
long ret;
errno = 0;
ret = strtol (s, NULL, 0);
if (errno) perr ("strtol");
return ret;
}