libite 2.6.1
rsync.c
Go to the documentation of this file.
1/* Micro "rsync" implementation.
2 *
3 * Copyright (c) 2011-2021 Joachim Wiberg <troglobit@gmail.com>
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
24
25#include <errno.h>
26#include <fcntl.h> /* AT_* macros */
27#include <stdlib.h> /* NULL, free() */
28#include <string.h> /* strlen() */
29#include <strings.h> /* rindex() */
30#include <stdio.h>
31#include <sys/param.h> /* MAX(), isset(), setbit(), TRUE, FALSE, et consortes. :-) */
32#include <sys/stat.h>
33#include <sys/types.h>
34
35#include "lite.h"
36
37static int copy(char *src, char *dst, int opt);
38static int mdir(char *buf, size_t buf_len, char *dir, char *name, struct stat *st);
39static int prune(char *dst, char **new_files, int new_num);
40static int set_mtime(char *fn, struct stat *st);
41
42
70int rsync(char *src, char *dst, int opt, int (*filter)(const char *file))
71{
72 char source[256];
73 char dest[256];
74 int delete = (opt & LITE_FOPT_RSYNC_DELETE) != 0;
75 int keep_mtim = (opt & LITE_FOPT_KEEP_MTIME);
76 int i = 0, num = 0, result = 0, do_mtim = 0;
77 char **files; /* Array of file names. */
78 struct stat st;
79
80 errno = 0;
81
82 if (stat(dst, &st) && fisslashdir(dst))
83 makedir(dst, 0755);
84
85 if (!fisdir(src)) {
86 if (!fexist(src))
87 return 1;
88
89 if (copy(src, dst, keep_mtim))
90 return 1;
91
92 return 0;
93 }
94
95 /* Copy dir as well? */
96 if (!fisslashdir(src)) {
97 char *ptr = rindex(src, '/');
98
99 if (!ptr)
100 ptr = src;
101 else
102 ptr++;
103
104 if (stat(src, &st))
105 return 1;
106
107 if (mdir(dest, sizeof(dest), dst, ptr, &st))
108 return 1;
109 dst = dest;
110 do_mtim = keep_mtim;
111 }
112
113 num = dir(src, "", filter, &files, 0);
114 for (i = 0; i < num; i++) {
115 /* Recursively copy sub-directries */
116 snprintf(source, sizeof(source), "%s%s%s", src, fisslashdir(src) ? "" : "/", files[i]);
117 if (fisdir(source)) {
118 char dst2[256];
119 struct stat sb;
120
121 strcat(source, "/");
122 if (stat(source, &sb)) {
123 result++;
124 continue;
125 }
126
127 if (mdir(dst2, sizeof(dst2), dst, files[i], &sb)) {
128 result++;
129 continue;
130 }
131
132 rsync(source, dst2, opt, filter);
133 if (keep_mtim)
134 set_mtime(dst2, &sb);
135
136 continue; /* Next file/dir in @src to copy... */
137 }
138
139 if (copy(source, dst, keep_mtim))
140 result++;
141 }
142
143 if (do_mtim)
144 set_mtime(dest, &st);
145
146 /* We ignore any errors from the pruning, that phase albeit useful is only
147 * cosmetic. --Jocke 2011-03-24 */
148 if (delete)
149 prune(dst, files, num);
150
151 if (num) {
152 for (i = 0; i < num; i++)
153 free(files[i]);
154 free(files);
155 }
156
157 return result;
158}
159
160static int copy(char *src, char *dst, int opt)
161{
162 copyfile(src, dst, 0, opt | LITE_FOPT_COPYFILE_SYM);
163 if (errno) {
164 if (errno != EEXIST)
165 return 1;
166
167 errno = 0;
168 }
169
170 return 0;
171}
172
173/* Creates dir/name @mode ... skipping / if dir already ends so. */
174static int mdir(char *buf, size_t buf_len, char *dir, char *name, struct stat *st)
175{
176 snprintf(buf, buf_len, "%s%s%s", dir, fisslashdir(dir) ? "" : "/", name);
177 if (mkdir(buf, st->st_mode)) {
178 if (EEXIST != errno)
179 return 1;
180
181 errno = 0;
182 }
183
184 return 0;
185}
186
187
188static int find(char *file, char **files, int num)
189{
190 int n;
191
192 for (n = 0; n < num; n++)
193 if (!strncmp (files[n], file, MAX(strlen(files[n]), strlen(file))))
194 return 1;
195
196 return 0;
197}
198
199
200/* Prune old files, no longer existing on source, from destination directory. */
201static int prune(char *dst, char **new_files, int new_num)
202{
203 int num, result = 0;
204 char **files;
205
206 num = dir(dst, "", NULL, &files, 0);
207 if (num) {
208 int i;
209
210 for (i = 0; i < num; i++) {
211 if (!find(files[i], new_files, new_num)) {
212 char *name;
213 size_t len = strlen(files[i]) + 2 + strlen(dst);
214
215 name = malloc(len);
216 if (name) {
217 snprintf(name, len, "%s%s%s", dst, fisslashdir(dst) ? "" : "/", files[i]);
218 if (remove(name))
219 result++;
220 free(name);
221 }
222 }
223 free(files[i]);
224 }
225 free(files);
226 }
227
228 return result;
229}
230
231static int set_mtime(char *fn, struct stat *st)
232{
233 struct timespec tv[2];
234
235 tv[0] = st->st_atim;
236 tv[1] = st->st_mtim;
237
238 return utimensat(AT_FDCWD, fn, tv, AT_SYMLINK_NOFOLLOW);
239}
240
ssize_t copyfile(const char *src, const char *dst, int len, int opt)
Definition copyfile.c:144
int dir(const char *dir, const char *type, int(*filter)(const char *file), char ***list, int strip)
Definition dir.c:82
int fexist(const char *file)
Definition fexist.c:45
int fisdir(const char *path)
Definition fisdir.c:40
#define LITE_FOPT_RSYNC_DELETE
Definition lite.h:67
#define LITE_FOPT_KEEP_MTIME
Definition lite.h:69
#define LITE_FOPT_COPYFILE_SYM
Definition lite.h:68
int rsync(char *src, char *dst, int opt, int(*filter)(const char *file))
Definition rsync.c:70