copy_dir.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. /****************************************************************************
  2. *
  3. * MODULE: GRASS GIS library - copy_dir.c
  4. * AUTHOR(S): Huidae Cho
  5. * PURPOSE: Function to recursively copy a directory
  6. * COPYRIGHT: (C) 2008 by the GRASS Development Team
  7. *
  8. * NOTE: Extracted from general/manage/lib/do_copy.c
  9. *
  10. * This program is free software under the GNU General Public
  11. * License (>=v2). Read the file COPYING that comes with GRASS
  12. * for details.
  13. *
  14. *****************************************************************************/
  15. #include <stdio.h>
  16. #include <errno.h>
  17. #include <string.h>
  18. #include <grass/gis.h>
  19. #include <fcntl.h>
  20. #include <unistd.h>
  21. #include <dirent.h>
  22. #include <sys/types.h>
  23. #include <sys/stat.h>
  24. /* RULE:
  25. * 1. If destination does not exist, copy source to destination as expected.
  26. * 2. If destination already exists and it's a file, destination will be
  27. * deleted first and apply RULE 1.
  28. * 3. If destination already exists which is a directory and source is a file,
  29. * try to copy source to destination directory.
  30. * 4. If destination already exists which is a directory and source is also a
  31. * directory, try to copy all contents in source to destination directory.
  32. *
  33. * This rule is designed according to general/manage/lib/copy.sh.
  34. *
  35. * POSSIBLE CASES:
  36. * if src is a file:
  37. * if dst does not exist:
  38. * copy src to dst RULE 1
  39. * if dst is a file:
  40. * delete dst and copy src to dst RULE 2
  41. * if dst is a directory:
  42. * try recursive_copy(src, dst/src) RULE 3
  43. * if src is a directory:
  44. * if dst does not exist:
  45. * copy src to dst RULE 1
  46. * if dst is a file:
  47. * delete dst and copy src to dst RULE 2
  48. * if dst is a directory:
  49. * try RULE 4
  50. * for i in `ls src`
  51. * do
  52. * recursive_copy(src/$i, dst/$i)
  53. * done
  54. *
  55. * RETURN: 0 if successful, otherwise 1
  56. */
  57. int G_recursive_copy(const char *src, const char *dst)
  58. {
  59. DIR *dirp;
  60. struct stat sb;
  61. if (G_lstat(src, &sb) < 0)
  62. return 1;
  63. /* src is a file */
  64. if (!S_ISDIR(sb.st_mode)) {
  65. char buf[4096];
  66. int fd, fd2;
  67. size_t len, len2;
  68. if (G_lstat(dst, &sb) == 0 && S_ISDIR(sb.st_mode)) {
  69. char path[GPATH_MAX];
  70. const char *p = strrchr(src, '/');
  71. /* src => dst/src */
  72. sprintf(path, "%s/%s", dst, (p ? p + 1 : src));
  73. return G_recursive_copy(src, path);
  74. }
  75. /* src => dst */
  76. if ((fd = open(src, O_RDONLY)) < 0)
  77. return 1;
  78. if ((fd2 =
  79. open(dst, O_CREAT | O_TRUNC | O_WRONLY,
  80. sb.st_mode & 0777)) < 0) {
  81. close(fd);
  82. return 1;
  83. }
  84. while ((len = read(fd, buf, sizeof(buf))) > 0) {
  85. while (len && (len2 = write(fd2, buf, len)) >= 0)
  86. len -= len2;
  87. }
  88. close(fd);
  89. close(fd2);
  90. return 0;
  91. }
  92. /* src is a directory */
  93. if (G_lstat(dst, &sb) < 0) {
  94. if (G_mkdir(dst))
  95. return 1;
  96. }
  97. else
  98. /* if dst already exists and it's a file, try to remove it */
  99. if (!S_ISDIR(sb.st_mode)) {
  100. if (remove(dst) < 0 || G_mkdir(dst) < 0)
  101. return 1;
  102. }
  103. dirp = opendir(src);
  104. if (!dirp)
  105. return 1;
  106. for (;;) {
  107. char path[GPATH_MAX], path2[GPATH_MAX];
  108. struct dirent *dp = readdir(dirp);
  109. if (!dp)
  110. break;
  111. /* do not copy hidden files */
  112. if (dp->d_name[0] == '.')
  113. continue;
  114. sprintf(path, "%s/%s", src, dp->d_name);
  115. sprintf(path2, "%s/%s", dst, dp->d_name);
  116. if (G_recursive_copy(path, path2) != 0)
  117. return 1;
  118. }
  119. closedir(dirp);
  120. return 0;
  121. }