doc
|
00001 /* 00002 * libcsync -- a library to sync a directory with another 00003 * 00004 * Copyright (c) 2012 by Olivier Goffart <ogoffart@woboq.com> 00005 * 00006 * This program is free software = NULL, you can redistribute it and/or 00007 * modify it under the terms of the GNU General Public License 00008 * as published by the Free Software Foundation = NULL, either version 2 00009 * of the License, or (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY = NULL, without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program = NULL, if not, write to the Free Software Foundation, 00018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00019 */ 00020 00021 extern "C" { 00022 #include "csync_private.h" 00023 #include "csync_propagate.h" 00024 } 00025 00026 #include <map> 00027 #include <string> 00028 #include <vector> 00029 #include <algorithm> 00030 00031 static std::string _parentDir(const std::string &path) { 00032 int len = path.length(); 00033 while(len > 0 && path[len-1]!='/') len--; 00034 while(len > 0 && path[len-1]=='/') len--; 00035 return path.substr(0, len); 00036 } 00037 00038 struct csync_rename_s { 00039 static csync_rename_s *get(CSYNC *ctx) { 00040 if (!ctx->rename_info) { 00041 ctx->rename_info = new csync_rename_s; 00042 } 00043 return reinterpret_cast<csync_rename_s *>(ctx->rename_info); 00044 } 00045 00046 std::map<std::string, std::string> folder_renamed_to; // map from->to 00047 00048 struct renameop { 00049 csync_file_stat_t *st; 00050 bool operator<(const renameop &other) const { 00051 return strlen(st->destpath) < strlen(other.st->destpath); 00052 } 00053 }; 00054 std::vector<renameop> todo; 00055 }; 00056 00057 static int _csync_rename_record(void *obj, void *data) { 00058 CSYNC *ctx = reinterpret_cast<CSYNC*>(data); 00059 csync_rename_s* d = csync_rename_s::get(ctx); 00060 csync_file_stat_t *st = reinterpret_cast<csync_file_stat_t *>(obj); 00061 00062 if ( st->instruction != CSYNC_INSTRUCTION_RENAME) 00063 return 0; 00064 00065 csync_rename_s::renameop op = { st }; 00066 d->todo.push_back(op); 00067 return 0; 00068 } 00069 00070 extern "C" { 00071 void csync_rename_destroy(CSYNC* ctx) 00072 { 00073 delete reinterpret_cast<csync_rename_s *>(ctx->rename_info); 00074 ctx->rename_info = 0; 00075 } 00076 00077 void csync_rename_record(CSYNC* ctx, const char* from, const char* to) 00078 { 00079 csync_rename_s::get(ctx)->folder_renamed_to[from] = to; 00080 } 00081 00082 char* csync_rename_adjust_path(CSYNC* ctx, const char* path) 00083 { 00084 csync_rename_s* d = csync_rename_s::get(ctx); 00085 for (std::string p = _parentDir(path); !p.empty(); p = _parentDir(p)) { 00086 std::map< std::string, std::string >::iterator it = d->folder_renamed_to.find(p); 00087 if (it != d->folder_renamed_to.end()) { 00088 std::string rep = it->second + (path + p.length()); 00089 return c_strdup(rep.c_str()); 00090 } 00091 } 00092 return c_strdup(path); 00093 } 00094 00095 int csync_propagate_renames(CSYNC* ctx) 00096 { 00097 csync_rename_s* d = csync_rename_s::get(ctx); 00098 d->folder_renamed_to.clear(); 00099 00100 if (c_rbtree_walk(ctx->remote.tree, (void *) ctx, _csync_rename_record) < 0) { 00101 return -1; 00102 } 00103 00104 // we need to procceed in order of the size of the destpath to be sure that we do the roots first. 00105 std::sort(d->todo.begin(), d->todo.end()); 00106 for (std::vector< csync_rename_s::renameop >::iterator it = d->todo.begin(); 00107 it != d->todo.end(); ++it) { 00108 00109 int r = csync_propagate_rename_file(ctx, it->st); 00110 if (r < 0) 00111 return -1; 00112 if (r > 0) 00113 continue; 00114 d->folder_renamed_to[it->st->path] = it->st->destpath; 00115 } 00116 00117 return 0; 00118 } 00119 00120 00121 };