gocha

Lightweight safe and fast file copy function

May 8th, 2014
213
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 3.73 KB | None | 0 0
  1. /**
  2.  * Lightweight safe and fast file copy function in C. (zlib license)
  3.  * (Windows CopyFile wrapper for Unix/Linux)
  4.  */
  5.  
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <errno.h>
  9. #include <sys/types.h>
  10. #include <sys/stat.h>
  11.  
  12. #ifdef WIN32
  13. #include <windows.h>
  14. #else
  15. #include <unistd.h>
  16. #include <sys/time.h>
  17. #endif
  18.  
  19. /* require bool (C99) */
  20. #ifdef HAVE_STDBOOL_H
  21. # include <stdbool.h>
  22. #else
  23. # ifndef HAVE__BOOL
  24. #  ifdef __cplusplus
  25. typedef bool _Bool;
  26. #  else
  27. #   define _Bool signed char
  28. #  endif
  29. # endif
  30. # define bool _Bool
  31. # define false 0
  32. # define true 1
  33. # define __bool_true_false_are_defined 1
  34. #endif
  35.  
  36. #define FILE_IO_MEMBLOCK_SIZE   7
  37.  
  38. /**
  39.  * Copy a file to another file.
  40.  * @param src_path Source file path.
  41.  * @param dst_path Destination file path.
  42.  * @param fail_if_exist true if the operation should be failed when the destination file already exists.
  43.  * @return true if the source file is successfully copied to the destination path, false otherwise.
  44.  * Additional error code can be retrieved from errno, or GetLastError() in Windows system.
  45.  */
  46. bool copy_file(const char *src_path, const char *dst_path, bool fail_if_exist)
  47. {
  48. #ifdef WIN32
  49.     return CopyFileA(src_path, dst_path, fail_if_exist);
  50. #else
  51.     struct stat src_stat;
  52.     struct stat dst_stat;
  53.     FILE * src_file = NULL;
  54.     FILE * dst_file = NULL;
  55.     char * buf = NULL;
  56.     const int buf_size = 512 * 1024;
  57.     off_t transferred_bytes;
  58.     bool succeeded = false;
  59.     int errno_saved;
  60.     int ret;
  61.  
  62.     /* get source file attributes */
  63.     ret = stat(src_path, &src_stat);
  64.     if (ret == -1) {
  65.         goto finish;
  66.     }
  67.  
  68.     /* get destination file attributes */
  69.     ret = stat(dst_path, &dst_stat);
  70.     if (ret == -1 && errno != ENOENT) {
  71.         goto finish;
  72.     }
  73.     /* prevent overwriting to existing file, if necessary */
  74.     if (ret == 0 && fail_if_exist) {
  75.         errno = EEXIST;
  76.         goto finish;
  77.     }
  78.  
  79.     /* open source file */
  80.     src_file = fopen(src_path, "rb");
  81.     if (src_file == NULL) {
  82.         goto finish;
  83.     }
  84.  
  85.     /* open destination file */
  86.     dst_file = fopen(dst_path, "wb");
  87.     if (dst_file == NULL) {
  88.         goto finish;
  89.     }
  90.  
  91.     /* copy content of file unless source file is empty */
  92.     if (src_stat.st_size > 0) {
  93.         /* allocate memory block for copying */
  94.         buf = (char *) malloc(buf_size);
  95.         if (buf == NULL) {
  96.             goto finish;
  97.         }
  98.  
  99.         /* read and write blocks */
  100.         transferred_bytes = 0;
  101.         while (transferred_bytes < src_stat.st_size) {
  102.             int transfer_bytes = buf_size;
  103.             if (transferred_bytes + transfer_bytes > src_stat.st_size) {
  104.                 transfer_bytes = src_stat.st_size - transferred_bytes;
  105.             }
  106.  
  107.             if (fread(buf, 1, transfer_bytes, src_file) != transfer_bytes) {
  108.                 errno = EIO;
  109.                 goto finish;
  110.             }
  111.  
  112.             if (fwrite(buf, 1, transfer_bytes, dst_file) != transfer_bytes) {
  113.                 errno = EIO;
  114.                 goto finish;
  115.             }
  116.  
  117.             transferred_bytes += transfer_bytes;
  118.         }
  119.     }
  120.  
  121.     /* finish the file creation */
  122.     fclose(dst_file);
  123.     dst_file = NULL;
  124.  
  125.     /* copy file permissions as well */
  126.     chmod(dst_path, src_stat.st_mode);
  127.  
  128.     /* everything has been done */
  129.     succeeded = true;
  130.  
  131. finish:
  132.     errno_saved = errno;
  133.  
  134.     if (src_file != NULL) {
  135.         fclose(src_file);
  136.     }
  137.  
  138.     if (dst_file != NULL) {
  139.         fclose(dst_file);
  140.     }
  141.  
  142.     if (buf != NULL) {
  143.         free(buf);
  144.     }
  145.  
  146.     errno = errno_saved;
  147.     return succeeded;
  148. #endif
  149. }
  150.  
  151. #include <time.h>
  152. int main(void)
  153. {
  154.     time_t start_time;
  155.     time_t end_time;
  156.  
  157. #ifdef WIN32
  158.     printf("Platform: Windows\n");
  159.     printf("\n");
  160. #else
  161.     printf("Platform: Unix\n");
  162.     printf("\n");
  163. #endif
  164.  
  165.     time(&start_time);
  166.  
  167.     if (copy_file("a.bin", "b.bin", true)) {
  168.         printf("Success.\n");
  169.     }
  170.     else {
  171. #ifdef WIN32
  172.         printf("Failed. %d\n", GetLastError());
  173. #else
  174.         printf("Failed. %d\n", errno);
  175. #endif
  176.     }
  177.  
  178.     time(&end_time);
  179.  
  180.     printf("Elapsed: %d seconds.\n", end_time - start_time);
  181. }
Add Comment
Please, Sign In to add comment