LINUX.ORG.RU

Копирование фрагмента файла - учебная программа

 , ,


0

0

Просьба проверить учебную программу на языке Си на наличие ошибок.

Программа предназначена для копирования фрагмента файла 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;
}

Deleted

В 64-битной версии GNU/Linux программа работает с файлами объемом более 2 Гбайт.

Исходный код на GitLab.

Deleted
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.