3 // Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; version 2 of the License.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 #include "vunify-matchlist.h"
24 #include "wrappers-dirent.h"
25 #include "vunify-operations.h"
29 #include <sys/types.h>
34 int wrapper_exit_code = 1;
39 struct MatchList dst_list;
47 static struct WalkdownInfo global_info;
48 static struct Operations operations;
50 static void visitDirEntry(struct dirent const *) NONNULL((1));
51 static void visitDir(char const *, struct stat const *) NONNULL((1));
52 static bool checkFstat(struct MatchList const * const,
53 PathInfo const * const,
54 PathInfo const * const,
55 struct stat const ** const,
56 struct stat * const) NONNULL((1,2,3,4,5));
58 static struct MatchList const *
59 checkDirEntry(PathInfo const *,
61 bool *, struct stat *) NONNULL((1,2,3,4));
63 static bool updateSkipDepth(PathInfo const *, bool) NONNULL((1));
64 static void EsafeChdir(char const *, struct stat const *) NONNULL((1,2));
65 static bool doit(struct MatchList const *, PathInfo const *,
66 char const *dst_path) NONNULL((1,2,3));
70 // Returns 'false' iff one of the files is not existing, or of the files are different/not unifyable
72 checkFstat(struct MatchList const * const mlist,
73 PathInfo const * const basename,
74 PathInfo const * const path,
75 struct stat const ** const result, struct stat * const result_buf)
77 assert(basename->d[0] != '/');
80 // local file does not exist... strange
82 if (lstat(basename->d, result_buf)==-1) return false;
89 struct stat src_fstat;
90 PathInfo src_path = mlist->root;
91 char src_path_buf[ENSC_PI_APPSZ(src_path, *path)];
93 PathInfo_append(&src_path, path, src_path_buf);
95 // source file does not exist
96 if (lstat(src_path.d, &src_fstat)==-1) return false;
98 // both files are different, so return false
99 if (!(operations.compare)(*result, &src_fstat)) return false;
102 // these are the same files
106 static struct MatchList const *
107 checkDirEntry(PathInfo const *path,
108 PathInfo const *d_path, bool *is_dir, struct stat *f_stat)
110 struct WalkdownInfo const * const info = &global_info;
111 struct MatchList const * mlist;
112 struct stat const * cache_stat = 0;
114 // Check if it is in the exclude/include list of the destination vserver and
115 // abort when it is not matching an allowed entry
116 if (!MatchList_compare(&info->dst_list, path->d)) return 0;
118 // Now, go through the reference vservers and do the lightweigt list-check
119 // first and compare then the fstat's.
120 for (mlist=info->src_lists.v; mlist<info->src_lists.v+info->src_lists.l; ++mlist) {
121 if (MatchList_compare(mlist, path->d) &&
122 checkFstat(mlist, d_path, path, &cache_stat, f_stat)) {
124 // Failed the check or is it a symlink which can not be handled
125 if (cache_stat==0 || S_ISLNK(f_stat->st_mode)) return 0;
127 *is_dir = S_ISDIR(f_stat->st_mode);
137 updateSkipDepth(PathInfo const *path, bool walk_down)
139 struct WalkdownInfo const * const info = &global_info;
140 struct MatchList * mlist;
143 for (mlist=info->src_lists.v; mlist<info->src_lists.v+info->src_lists.l; ++mlist) {
144 // The easy way... this path is being skipped already
145 if (mlist->skip_depth>0) {
146 if (walk_down) ++mlist->skip_depth;
147 else --mlist->skip_depth;
150 else if (walk_down) {
151 PathInfo src_path = mlist->root;
152 char src_path_buf[ENSC_PI_APPSZ(src_path, *path)];
153 struct stat src_fstat;
155 PathInfo_append(&src_path, path, src_path_buf);
157 // when the file/dir exist, we have do go deeper.
158 // else skip it in deeper runs for *this* matchlist
159 if (lstat(src_path.d, &src_fstat)!=-1) result = true;
160 else ++mlist->skip_depth;
171 EsafeChdir(char const *path, struct stat const *exp_stat)
173 FatalErrnoError(safeChdir(path, exp_stat)==-1, "safeChdir()");
177 doit(struct MatchList const *mlist, PathInfo const *src_path,
178 char const *dst_path)
180 PathInfo path = mlist->root;
181 char path_buf[ENSC_PI_APPSZ(path, *src_path)];
183 PathInfo_append(&path, src_path, path_buf);
184 return (operations.doit)(path.d, dst_path);
189 visitDirEntry(struct dirent const *ent)
192 struct MatchList const * match;
194 char const * dirname = ent->d_name;
195 size_t path_len = strlen(ent->d_name);
196 PathInfo path = global_info.state;
201 char path_buf[ENSC_PI_APPSZ(path, d_path)];
203 PathInfo_append(&path, &d_path, path_buf);
205 if ((dirname[0]=='.' &&
206 (dirname[1]=='\0' || (dirname[1]=='.' && dirname[2]=='\0'))) ||
207 (match=checkDirEntry(&path, &d_path, &is_dir, &f_stat))==0) {
208 WRITE_MSG(1, "skipping '");
209 WRITE_STR(1, dirname);
215 if (updateSkipDepth(&path, true)) {
216 visitDir(dirname, &f_stat);
217 updateSkipDepth(&path, false);
220 else if (!doit(match, &path, dirname)) {
226 visitDir(char const *name, struct stat const *expected_stat)
228 int fd = Eopen(".", O_RDONLY, 0);
229 PathInfo old_state = global_info.state;
230 PathInfo rhs_path = {
234 char new_path[ENSC_PI_APPSZ(global_info.state, rhs_path)];
237 PathInfo_append(&global_info.state, &rhs_path, new_path);
239 if (expected_stat!=0)
240 EsafeChdir(name, expected_stat);
245 struct dirent *ent = Ereaddir(dir);
256 global_info.state = old_state;
260 int main(int argc, char *argv[])
262 global_info.state.d = "";
263 global_info.state.l = 0;
265 Operations_init(&operations, opUNIFY, false);
266 MatchList_init(&global_info.dst_list, argv[1], 0);
268 global_info.src_lists.v = malloc(sizeof(struct MatchList));
269 global_info.src_lists.l = 1;
270 MatchList_init(global_info.src_lists.v+0, argv[2], 0);
272 Echdir(global_info.dst_list.root.d);