1 /*
2 sitecopy, for managing remote web sites.
3 Copyright (C) 1999-2005, Joe Orton <joe@manyfish.co.uk>
4
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; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 #ifndef SITESI_H
21 #define SITESI_H
22
23 #include <sys/stat.h>
24
25 #include "common.h"
26 #include "sites.h"
27 #include "frontend.h" /* for fe_*_abort */
28
29 #include "ne_md5.h" /* for ne_md5_* */
30
31 /* Internal sites code handling */
32
33 void file_uploaded(struct site_file *file, struct site *site);
34 void file_downloaded(struct site_file *file, struct site *site);
35
36 int file_contents_changed(struct site_file *file, struct site *site);
37 int file_perms_changed(struct site_file *file, struct site *site);
38
39 #define DEBUG_GIVE_DIFF(diff) \
40 diff==file_new?"new":( \
41 diff==file_changed?"changed":( \
42 diff==file_unchanged?"unchanged":( \
43 diff==file_deleted?"deleted":"moved")))
44
45 /* Macro, used mainly internally to the sites code to dump a file. */
46 #define DEBUG_DUMP_FILE(ch, file) \
47 NE_DEBUG(ch, "%s: local=%s stored=%s, %s%s\n", \
48 (file->type==file_file)?"File":( \
49 file->type==file_dir?"Dir":"Link"), \
50 file->local.filename?file->local.filename:".", \
51 file->stored.filename?file->stored.filename:".", \
52 DEBUG_GIVE_DIFF(file->diff), \
53 file->ignore?" (ignored)":"")
54
55 #define DEBUG_DUMP_FILE_PROPS(ch, file, site) \
56 DEBUG_DUMP_FILE(ch, file); \
57 if (site->state_method == state_timesize) { \
58 NE_DEBUG(ch, "Time: %ld/%ld Size: %" NE_FMT_OFF_T "/%" NE_FMT_OFF_T, \
59 file->local.time, file->stored.time, \
60 file->local.size, file->stored.size); \
61 } else { \
62 char l[33], s[33]; \
63 ne_md5_to_ascii(file->local.checksum, l); \
64 ne_md5_to_ascii(file->stored.checksum, s); \
65 NE_DEBUG(ch, "Checksum: %32s/%32s\n", l, s); \
66 } \
67 NE_DEBUG(ch, "ASCII:%c/%c Perms:%03o/%03o\n", \
68 file->local.ascii?'y':'n', file->stored.ascii?'y':'n', \
69 file->local.mode, file->stored.mode ); \
70 if (file->server.exists) { \
71 NE_DEBUG(ch, "Server: %ld\n", file->server.time); \
72 }
73
74 /* Use to iterate over a files list. */
75 #define for_each_file(file, site) \
76 for (file = site->files; file != NULL; file = file->next)
77
78
79 /* Remove a file from the files list */
80 void file_delete(struct site *site, struct site_file *item);
81
82 /* Destroys a file state */
83 void file_state_destroy(struct file_state *state);
84 /* Copies a file state from src to dest */
85 void file_state_copy(struct file_state *dest, const struct file_state *src,
86 struct site *site);
87
88 /* This *MUST* be called after you change the local or stored state
89 * of a file. It sets the ->diff appropriately, and updates the
90 * site's num* and total* fields. */
91 void file_set_diff(struct site_file *file, struct site *site);
92
93 struct site_file *
94 file_find(struct site *site, const char *fname, enum file_type type);
95
96 struct site_file *
97 file_set_stored(enum file_type type, struct file_state *state,
98 struct site *site);
99
100 struct site_file *
101 file_set_local(enum file_type type, struct file_state *state,
102 struct site *site);
103
104 static inline void
105 site_stats_increase(const struct site_file *file, struct site *site);
106
107 static inline void
108 site_stats_decrease(const struct site_file *file, struct site *site);
109
110 void site_stats_update(struct site *site);
111
112 static inline void
site_stats_increase(const struct site_file * file,struct site * site)113 site_stats_increase(const struct site_file *file, struct site *site) {
114 switch (file->diff) {
115 case file_unchanged:
116 site->numunchanged++;
117 break;
118 case file_changed:
119 if (file->ignore) {
120 site->numignored++;
121 } else {
122 site->numchanged++;
123 site->totalchanged += file->local.size;
124 }
125 break;
126 case file_new:
127 site->numnew++;
128 site->totalnew += file->local.size;
129 break;
130 case file_moved:
131 site->nummoved++;
132 break;
133 case file_deleted:
134 site->numdeleted++;
135 break;
136 default:
137 /* Do nothing */
138 break;
139 }
140 }
141
142 static inline void
site_stats_decrease(const struct site_file * file,struct site * site)143 site_stats_decrease(const struct site_file *file, struct site *site) {
144 switch (file->diff) {
145 case file_unchanged:
146 site->numunchanged--;
147 break;
148 case file_changed:
149 if (file->ignore) {
150 site->numignored--;
151 } else {
152 site->numchanged--;
153 site->totalchanged -= file->local.size;
154 }
155 break;
156 case file_new:
157 site->numnew--;
158 site->totalnew -= file->local.size;
159 break;
160 case file_moved:
161 site->nummoved--;
162 break;
163 case file_deleted:
164 site->numdeleted--;
165 break;
166 default:
167 /* Do nothing */
168 break;
169 }
170 }
171
172 /* Returns the difference between the local and stored state of the
173 * given file in the given state.
174 * Returns:
175 * file_changed if changed
176 * file_unchanged otherwise
177 */
178 enum file_diff inline static
file_compare(const enum file_type type,const struct file_state * first,const struct file_state * second,const struct site * site)179 file_compare(const enum file_type type,
180 const struct file_state *first, const struct file_state *second,
181 const struct site *site) {
182
183 /* Handle the special cases */
184 if (!first->exists)
185 return file_deleted;
186 if (!second->exists)
187 return file_new;
188
189 /* They're both there... compare them properly */
190 switch (type) {
191 case file_dir:
192 if (site->dirperms) {
193 return (first->mode != second->mode ?
194 file_changed : file_unchanged);
195 }
196 break;
197
198 case file_link:
199 if (strcmp(first->linktarget, second->linktarget) != 0) {
200 return file_changed;
201 }
202 break;
203
204 case file_file:
205 switch (site->state_method) {
206 case state_timesize:
207 if ((first->time != second->time)
208 || (first->size!=second->size)) {
209 return file_changed;
210 }
211 break;
212 case state_checksum:
213 if (memcmp(first->checksum, second->checksum, 16) != 0) {
214 return file_changed;
215 }
216 break;
217 }
218 /* Check permissions and ASCIIness.
219 * There's a twist for permissions: if EITHER local or
220 * remote file has an EXEC bit set, then in 'perms exec' mode,
221 * perms are compared. */
222 if (first->ascii != second->ascii) {
223 return file_changed;
224 } else if (((site->perms == sitep_all) ||
225 (((first->mode & S_IXUSR) || (second->mode & S_IXUSR)) &&
226 (site->perms == sitep_exec)))
227 && (first->mode != second->mode)) {
228 return file_changed;
229 }
230 if (site->checkmoved && strcmp(first->filename, second->filename)) {
231 return file_moved;
232 }
233 break;
234 }
235 return file_unchanged;
236 }
237
238 /* Places the checksum of the given filename in the given file state.
239 * The checksum algorithm may in the future be determined from the
240 * site. Returns 0 on success or -1 on error.
241 */
242 int file_checksum(const char *fname, struct file_state *state, struct site *s);
243
244 /* Returns whether a file of given name is exclude from the given site */
245 int file_isexcluded(const char *filename, struct site *site);
246 /* Returns whether a file is ASCII text or binary */
247 int file_isascii(const char *filename, struct site *site);
248 /* Returns whether a file is ignored or not */
249 int file_isignored(const char *filename, struct site *site);
250
251 #endif /* SITESI_H */
252