copy_file.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * Mini copy_file implementation for busybox
  4. *
  5. * Copyright (C) 2001 by Matt Kraai <kraai@alumni.carnegiemellon.edu>
  6. *
  7. * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
  8. *
  9. */
  10. #include <sys/types.h>
  11. #include <sys/stat.h>
  12. #include <unistd.h>
  13. #include <fcntl.h>
  14. #include <utime.h>
  15. #include <errno.h>
  16. #include <dirent.h>
  17. #include <stdlib.h>
  18. #include <string.h>
  19. #include "busybox.h"
  20. /* Compiler version-specific crap that should be in a header file somewhere. */
  21. #if !((__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1))
  22. #define lchown chown
  23. #endif
  24. int copy_file(const char *source, const char *dest, int flags)
  25. {
  26. struct stat source_stat;
  27. struct stat dest_stat;
  28. int dest_exists = 0;
  29. int status = 0;
  30. if ((!(flags & FILEUTILS_DEREFERENCE) &&
  31. lstat(source, &source_stat) < 0) ||
  32. ((flags & FILEUTILS_DEREFERENCE) &&
  33. stat(source, &source_stat) < 0)) {
  34. bb_perror_msg("%s", source);
  35. return -1;
  36. }
  37. if (lstat(dest, &dest_stat) < 0) {
  38. if (errno != ENOENT) {
  39. bb_perror_msg("unable to stat `%s'", dest);
  40. return -1;
  41. }
  42. } else {
  43. if (source_stat.st_dev == dest_stat.st_dev &&
  44. source_stat.st_ino == dest_stat.st_ino)
  45. {
  46. bb_error_msg("`%s' and `%s' are the same file", source, dest);
  47. return -1;
  48. }
  49. dest_exists = 1;
  50. }
  51. if (S_ISDIR(source_stat.st_mode)) {
  52. DIR *dp;
  53. struct dirent *d;
  54. mode_t saved_umask = 0;
  55. if (!(flags & FILEUTILS_RECUR)) {
  56. bb_error_msg("%s: omitting directory", source);
  57. return -1;
  58. }
  59. /* Create DEST. */
  60. if (dest_exists) {
  61. if (!S_ISDIR(dest_stat.st_mode)) {
  62. bb_error_msg("`%s' is not a directory", dest);
  63. return -1;
  64. }
  65. } else {
  66. mode_t mode;
  67. saved_umask = umask(0);
  68. mode = source_stat.st_mode;
  69. if (!(flags & FILEUTILS_PRESERVE_STATUS))
  70. mode = source_stat.st_mode & ~saved_umask;
  71. mode |= S_IRWXU;
  72. if (mkdir(dest, mode) < 0) {
  73. umask(saved_umask);
  74. bb_perror_msg("cannot create directory `%s'", dest);
  75. return -1;
  76. }
  77. umask(saved_umask);
  78. }
  79. /* Recursively copy files in SOURCE. */
  80. if ((dp = opendir(source)) == NULL) {
  81. bb_perror_msg("unable to open directory `%s'", source);
  82. status = -1;
  83. goto preserve_status;
  84. }
  85. while ((d = readdir(dp)) != NULL) {
  86. char *new_source, *new_dest;
  87. new_source = concat_subpath_file(source, d->d_name);
  88. if(new_source == NULL)
  89. continue;
  90. new_dest = concat_path_file(dest, d->d_name);
  91. if (copy_file(new_source, new_dest, flags) < 0)
  92. status = -1;
  93. free(new_source);
  94. free(new_dest);
  95. }
  96. /* closedir have only EBADF error, but "dp" not changes */
  97. closedir(dp);
  98. if (!dest_exists &&
  99. chmod(dest, source_stat.st_mode & ~saved_umask) < 0) {
  100. bb_perror_msg("unable to change permissions of `%s'", dest);
  101. status = -1;
  102. }
  103. } else if (S_ISREG(source_stat.st_mode) || (flags & FILEUTILS_DEREFERENCE))
  104. {
  105. int src_fd;
  106. int dst_fd;
  107. #ifdef CONFIG_FEATURE_PRESERVE_HARDLINKS
  108. char *link_name;
  109. if (!(flags & FILEUTILS_DEREFERENCE) &&
  110. is_in_ino_dev_hashtable(&source_stat, &link_name)) {
  111. if (link(link_name, dest) < 0) {
  112. bb_perror_msg("unable to link `%s'", dest);
  113. return -1;
  114. }
  115. return 0;
  116. }
  117. add_to_ino_dev_hashtable(&source_stat, dest);
  118. #endif
  119. src_fd = open(source, O_RDONLY);
  120. if (src_fd == -1) {
  121. bb_perror_msg("unable to open `%s'", source);
  122. return(-1);
  123. }
  124. if (dest_exists) {
  125. if (flags & FILEUTILS_INTERACTIVE) {
  126. fprintf(stderr, "%s: overwrite `%s'? ", bb_applet_name, dest);
  127. if (!bb_ask_confirmation()) {
  128. close (src_fd);
  129. return 0;
  130. }
  131. }
  132. dst_fd = open(dest, O_WRONLY|O_TRUNC);
  133. if (dst_fd == -1) {
  134. if (!(flags & FILEUTILS_FORCE)) {
  135. bb_perror_msg("unable to open `%s'", dest);
  136. close(src_fd);
  137. return -1;
  138. }
  139. if (unlink(dest) < 0) {
  140. bb_perror_msg("unable to remove `%s'", dest);
  141. close(src_fd);
  142. return -1;
  143. }
  144. goto dest_removed;
  145. }
  146. } else {
  147. dest_removed:
  148. dst_fd = open(dest, O_WRONLY|O_CREAT, source_stat.st_mode);
  149. if (dst_fd == -1) {
  150. bb_perror_msg("unable to open `%s'", dest);
  151. close(src_fd);
  152. return(-1);
  153. }
  154. }
  155. if (bb_copyfd_eof(src_fd, dst_fd) == -1)
  156. status = -1;
  157. if (close(dst_fd) < 0) {
  158. bb_perror_msg("unable to close `%s'", dest);
  159. status = -1;
  160. }
  161. if (close(src_fd) < 0) {
  162. bb_perror_msg("unable to close `%s'", source);
  163. status = -1;
  164. }
  165. } else if (S_ISBLK(source_stat.st_mode) || S_ISCHR(source_stat.st_mode) ||
  166. S_ISSOCK(source_stat.st_mode) || S_ISFIFO(source_stat.st_mode) ||
  167. S_ISLNK(source_stat.st_mode)) {
  168. if (dest_exists) {
  169. if((flags & FILEUTILS_FORCE) == 0) {
  170. fprintf(stderr, "`%s' exists\n", dest);
  171. return -1;
  172. }
  173. if(unlink(dest) < 0) {
  174. bb_perror_msg("unable to remove `%s'", dest);
  175. return -1;
  176. }
  177. }
  178. if (S_ISFIFO(source_stat.st_mode)) {
  179. if (mkfifo(dest, source_stat.st_mode) < 0) {
  180. bb_perror_msg("cannot create fifo `%s'", dest);
  181. return -1;
  182. }
  183. } else if (S_ISLNK(source_stat.st_mode)) {
  184. char *lpath;
  185. lpath = xreadlink(source);
  186. if (symlink(lpath, dest) < 0) {
  187. bb_perror_msg("cannot create symlink `%s'", dest);
  188. return -1;
  189. }
  190. free(lpath);
  191. if (flags & FILEUTILS_PRESERVE_STATUS)
  192. if (lchown(dest, source_stat.st_uid, source_stat.st_gid) < 0)
  193. bb_perror_msg("unable to preserve ownership of `%s'", dest);
  194. return 0;
  195. } else {
  196. if (mknod(dest, source_stat.st_mode, source_stat.st_rdev) < 0) {
  197. bb_perror_msg("unable to create `%s'", dest);
  198. return -1;
  199. }
  200. }
  201. } else {
  202. bb_error_msg("internal error: unrecognized file type");
  203. return -1;
  204. }
  205. preserve_status:
  206. if (flags & FILEUTILS_PRESERVE_STATUS) {
  207. struct utimbuf times;
  208. char *msg="unable to preserve %s of `%s'";
  209. times.actime = source_stat.st_atime;
  210. times.modtime = source_stat.st_mtime;
  211. if (utime(dest, &times) < 0)
  212. bb_perror_msg(msg, "times", dest);
  213. if (chown(dest, source_stat.st_uid, source_stat.st_gid) < 0) {
  214. source_stat.st_mode &= ~(S_ISUID | S_ISGID);
  215. bb_perror_msg(msg, "ownership", dest);
  216. }
  217. if (chmod(dest, source_stat.st_mode) < 0)
  218. bb_perror_msg(msg, "permissions", dest);
  219. }
  220. return status;
  221. }