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