190 char *etag = dav_get_property(res, "D:getetag"); |
191 char *etag = dav_get_property(res, "D:getetag"); |
191 struct stat s; |
192 struct stat s; |
192 if(local) { |
193 if(local) { |
193 if(stat(local_path, &s)) { |
194 if(stat(local_path, &s)) { |
194 if(errno == ENOENT) { |
195 if(errno == ENOENT) { |
195 printf("removed %s\n", res->path); |
196 printf("removed: %s\n", res->path); |
196 // the file is in the database, but doesn't exists |
197 // the file is in the database, but doesn't exists |
197 // mark the file as removed to delete it on next push |
198 // mark the file as removed to delete it on next push |
198 ucx_map_cstr_remove(db->resources, local->path); |
199 ucx_map_cstr_remove(db->resources, local->path); |
199 ucx_map_cstr_put(db->remove, local->path, local); |
200 ucx_map_cstr_put(db->remove, local->path, local); |
200 return 0; |
201 return 0; |
201 } else { |
202 } else { |
202 fprintf(stderr, "stat failed: %s\n", local_path); |
203 fprintf(stderr, "Cannot stat file: %s\n", local_path); |
203 free(local_path); |
204 free(local_path); |
204 return -1; |
205 return -1; |
205 } |
206 } |
206 } |
207 } |
207 |
208 |
208 if(local->etag) { |
209 if(local->etag) { |
209 sstr_t e = sstr(etag); |
210 sstr_t e = sstr(etag); |
210 if(sstrprefix(e, S("W/"))) { |
211 if(sstrprefix(e, S("W/"))) { |
211 e = sstrsubs(e, 2); |
212 e = sstrsubs(e, 2); |
212 } |
213 } |
213 if(!strcmp(e.ptr, local->etag)) { |
214 if(!strcmp(e.ptr, local->etag)) { |
214 // resource is already up-to-date on the client |
215 // resource is already up-to-date on the client |
215 return 0; |
216 return 0; |
216 } |
217 } |
217 } |
218 } |
218 } |
219 |
219 |
220 if(s.st_mtim.tv_sec != local->last_modified) { |
|
221 // file modified on the server and on the client |
|
222 rename_local_file(dir, db, local->path); |
|
223 } |
|
224 } else { |
|
225 if(stat(local_path, &s)) { |
|
226 if(errno != ENOENT) { |
|
227 fprintf(stderr, "Cannot stat file: %s\n", local_path); |
|
228 } |
|
229 } else if(!S_ISDIR(s.st_mode)) { |
|
230 rename_local_file(dir, db, res->path); |
|
231 } |
|
232 } |
|
233 |
220 int ret = 0; |
234 int ret = 0; |
221 if(res->iscollection) { |
235 if(res->iscollection) { |
222 mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; |
236 mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; |
223 //printf("mkdir %s\n", local_path); |
237 //printf("mkdir %s\n", local_path); |
224 if(util_mkdir(local_path, mode) && errno != EEXIST) { |
238 if(util_mkdir(local_path, mode) && errno != EEXIST) { |
225 ret = -1; |
239 ret = -1; |
226 } |
240 } |
227 } else { |
241 } else { |
228 FILE *out = fopen(local_path, "w"); |
242 FILE *out = fopen(local_path, "w"); |
229 if(!out) { |
243 if(!out) { |
230 fprintf(stderr, "cannot open output file: %s\n", local_path); |
244 fprintf(stderr, "Cannot open output file: %s\n", local_path); |
231 free(local_path); |
245 free(local_path); |
232 return -1; |
246 return -1; |
233 } |
247 } |
234 printf("get %s\n", res->path); |
248 printf("get: %s\n", res->path); |
235 if(dav_get_content(res, out, (dav_write_func)fwrite)) { |
249 if(dav_get_content(res, out, (dav_write_func)fwrite)) { |
236 ret = -1; |
250 ret = -1; |
237 } |
251 } |
238 fclose(out); |
252 fclose(out); |
|
253 |
|
254 if(stat(local_path, &s)) { |
|
255 fprintf(stderr, "Cannot stat file: %s\n", local_path); |
|
256 } |
239 |
257 |
240 if(ret == 0) { |
258 if(ret == 0) { |
241 if(!local) { |
259 if(!local) { |
242 // new local resource |
260 // new local resource |
243 local = calloc(1, sizeof(LocalResource)); |
261 local = calloc(1, sizeof(LocalResource)); |
275 printf("delete: %s\n", res->path); |
293 printf("delete: %s\n", res->path); |
276 if(unlink(local_path)) { |
294 if(unlink(local_path)) { |
277 fprintf(stderr, "Cannot remove file %s\n", local_path); |
295 fprintf(stderr, "Cannot remove file %s\n", local_path); |
278 } |
296 } |
279 free(local_path); |
297 free(local_path); |
|
298 } |
|
299 |
|
300 void rename_local_file(SyncDirectory *dir, SyncDatabase *db, char *path) { |
|
301 char *local_path = util_concat_path(dir->path, path); |
|
302 char *parent = util_parent_path(local_path); |
|
303 |
|
304 int rev = 0; |
|
305 struct stat s; |
|
306 int loop = 1; |
|
307 do { |
|
308 sstr_t new_path = ucx_asprintf( |
|
309 ucx_default_allocator(), |
|
310 "%sorig.%d.%s", |
|
311 parent, |
|
312 rev, |
|
313 util_resource_name(path)); |
|
314 |
|
315 |
|
316 if(stat(new_path.ptr, &s)) { |
|
317 if(errno == ENOENT) { |
|
318 loop = 0; |
|
319 printf("conflict: %s\n", local_path); |
|
320 if(rename(local_path, new_path.ptr)) { |
|
321 printf("errno: %d\n", errno); |
|
322 fprintf( |
|
323 stderr, |
|
324 "Cannot rename file %s to %s\n", |
|
325 local_path, |
|
326 new_path.ptr); |
|
327 } |
|
328 } |
|
329 } |
|
330 rev++; |
|
331 free(new_path.ptr); |
|
332 } while(loop); |
|
333 free(parent); |
280 } |
334 } |
281 |
335 |
282 int cmd_push(CmdArgs *a) { |
336 int cmd_push(CmdArgs *a) { |
283 if(a->argc != 1) { |
337 if(a->argc != 1) { |
284 fprintf(stderr, "Too %s arguments\n", a->argc < 1 ? "few" : "many"); |
338 fprintf(stderr, "Too %s arguments\n", a->argc < 1 ? "few" : "many"); |