00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include <Basics.H>
00027 #include <Text.H>
00028 #include <VestaConfig.H>
00029 #include <VestaSource.H>
00030 #include <VDirSurrogate.H>
00031 #include <signal.h>
00032 #include <ReposUI.H>
00033
00034 extern "C" {
00035 #include <getopt.h>
00036 }
00037
00038 using std::cerr;
00039 using std::endl;
00040
00041 Text program_name;
00042
00043 void usage()
00044 {
00045 cerr << "Usage: " << program_name << endl <<
00046 " [-c] [-R repos]" << endl <<
00047 " directory" << endl << endl;
00048 exit(1);
00049 }
00050
00051 struct EntryData
00052 {
00053 struct EntryData *next;
00054
00055 VestaSource::typeTag type;
00056 Text arc;
00057 unsigned int index;
00058 Bit32 pseudoInode;
00059 ShortId fileSid;
00060 bool master;
00061
00062 EntryData(VestaSource::typeTag type, Arc arc,
00063 unsigned int index, Bit32 pseudoInode,
00064 ShortId fileSid, bool master)
00065 : type(type), arc(arc), index(index), pseudoInode(pseudoInode),
00066 fileSid(fileSid), master(master), next(0)
00067 { }
00068 };
00069
00070 struct RecordClosure
00071 {
00072 struct EntryData *first, *last;
00073
00074 RecordClosure()
00075 : first(0), last(0)
00076 { }
00077 };
00078
00079 bool recordListCB(void* closure, VestaSource::typeTag type, Arc arc,
00080 unsigned int index, Bit32 pseudoInode,
00081 ShortId fileSid, bool master)
00082 {
00083 RecordClosure *rclosure = (RecordClosure *) closure;
00084
00085 EntryData *thisEntry = NEW_CONSTR(EntryData,
00086 (type, arc, index, pseudoInode,
00087 fileSid, master));
00088
00089 if(rclosure->last == 0)
00090 {
00091 rclosure->last = thisEntry;
00092 rclosure->first = thisEntry;
00093 }
00094 else
00095 {
00096 assert(rclosure->last->next == 0);
00097 rclosure->last->next = thisEntry;
00098 rclosure->last = thisEntry;
00099 assert(rclosure->first != 0);
00100 }
00101
00102 return true;
00103 }
00104
00105 struct CompareClosure
00106 {
00107 const struct EntryData *list;
00108 unsigned int raw_index;
00109 bool miscompare;
00110
00111 CompareClosure(const struct EntryData *list)
00112 : list(list), raw_index(0), miscompare(false)
00113 { }
00114
00115 void advance()
00116 {
00117 raw_index++;
00118 if(list != 0)
00119 list = list->next;
00120 }
00121 };
00122
00123 bool compareListCB(void* closure, VestaSource::typeTag type, Arc arc,
00124 unsigned int index, Bit32 pseudoInode,
00125 ShortId fileSid, bool master)
00126 {
00127 CompareClosure *cclosure = (CompareClosure *) closure;
00128
00129 if(cclosure->list == 0)
00130 {
00131 cclosure->miscompare = true;
00132 cerr << "directory entry " << cclosure->raw_index
00133 << " not present in original:" << endl
00134 << "\tarc = \"" << arc << "\"" << endl
00135 << "\ttype = " << VestaSource::typeTagString(type) << endl
00136 << "\tindex = " << index << endl;
00137 }
00138 else
00139 {
00140 bool type_match = (cclosure->list->type == type);
00141 bool arc_match = (cclosure->list->arc == arc);
00142 bool index_match = (cclosure->list->index == index);
00143 bool pinode_match = (cclosure->list->pseudoInode == pseudoInode);
00144 bool sid_match = (cclosure->list->fileSid == fileSid);
00145 bool master_match = ((cclosure->list->master && master) ||
00146 (!cclosure->list->master && !master));
00147
00148
00149 if(!type_match || !arc_match || !index_match ||
00150 !pinode_match || !sid_match || !master_match)
00151 {
00152 cclosure->miscompare = true;
00153 cerr << "directory entry " << cclosure->raw_index
00154 << "mismatch:" << endl;
00155
00156
00157
00158 if(arc_match)
00159 {
00160 cerr << "\tarc = \"" << arc << "\"" << endl;
00161 }
00162 if(type_match)
00163 {
00164 cerr << "\ttype = " << VestaSource::typeTagString(type) << endl;
00165 }
00166 if(index_match)
00167 {
00168 cerr << "\tindex = " << index << endl;
00169 }
00170
00171 if(!arc_match)
00172 {
00173 cerr << "\tarc was \"" << cclosure->list->arc
00174 << "\", is \"" << arc << "\"" << endl;
00175 }
00176 if(!type_match)
00177 {
00178 cerr << "\ttype was "
00179 << VestaSource::typeTagString(cclosure->list->type)
00180 << ", is " << VestaSource::typeTagString(type) << endl;
00181 }
00182 if(!index_match)
00183 {
00184 cerr << "\tindex was " << cclosure->list->index
00185 << ", is " << index << endl;
00186 }
00187 if(!pinode_match)
00188 {
00189 cerr << "\tpseudoInode was " << cclosure->list->pseudoInode
00190 << ", is " << pseudoInode << endl;
00191 }
00192 if(!pinode_match)
00193 {
00194 cerr << "\tfileSid was " << cclosure->list->fileSid
00195 << ", is " << fileSid << endl;
00196 }
00197 if(!master_match)
00198 {
00199 cerr << "\tmaster was " << (cclosure->list->master
00200 ?"true":"false")
00201 << ", is " << (master?"true":"false") << endl;
00202 }
00203 }
00204 }
00205
00206
00207 cclosure->advance();
00208
00209 return true;
00210 }
00211
00212 int
00213 main(int argc, char* argv[])
00214 {
00215
00216 program_name = Text(argv[0]);
00217
00218 bool consistency_check = false;
00219 Text repos;
00220 bool default_repos = true;
00221
00222 VestaSource::errorCode err;
00223
00224 try
00225 {
00226
00227 Text host(VDirSurrogate::defaultHost());
00228 Text port(VDirSurrogate::defaultPort());
00229
00230
00231 opterr = 0;
00232 for(;;)
00233 {
00234 int c = getopt(argc, argv, "cR:");
00235 if(c == EOF) break;
00236 switch(c)
00237 {
00238 case 'c':
00239 consistency_check = true;
00240 break;
00241 case 'R':
00242 repos = optarg;
00243 default_repos = false;
00244 break;
00245 case '?':
00246 default:
00247 usage();
00248 }
00249 }
00250 if (argc <= optind)
00251 {
00252 usage();
00253 }
00254
00255
00256 if (!default_repos)
00257 {
00258 int colon = repos.FindCharR(':');
00259 if (colon == -1)
00260 {
00261 host = repos;
00262 repos = repos + ":" + port;
00263 }
00264 else
00265 {
00266 host = repos.Sub(0, colon);
00267 port = repos.Sub(colon+1);
00268 }
00269 }
00270
00271 for(unsigned int i = optind; i < argc; i++)
00272 {
00273
00274 Text name = Text(argv[i]);
00275 Text cname = ReposUI::canonicalize(name);
00276
00277
00278 VestaSource *vs = ReposUI::filenameToVS(cname, host, port);
00279
00280
00281
00282 RecordClosure recorded;
00283 if(consistency_check)
00284 {
00285 err = vs->list(0, recordListCB, &recorded);
00286 if (err != VestaSource::ok)
00287 {
00288 cerr << program_name
00289 << ": error listing directory " << name
00290 << " (recording): "
00291 << ReposUI::errorCodeText(err) << endl;
00292 exit(1);
00293 }
00294 }
00295
00296
00297 err = vs->collapseBase();
00298 if (err != VestaSource::ok)
00299 {
00300 cerr << program_name
00301 << ": error collapsing base of directory " << name << ": "
00302 << ReposUI::errorCodeText(err) << endl;
00303 exit(1);
00304 }
00305
00306
00307
00308 if(consistency_check)
00309 {
00310 CompareClosure compare(recorded.first);
00311 err = vs->list(0, compareListCB, &compare);
00312 if (err != VestaSource::ok)
00313 {
00314 cerr << program_name
00315 << ": error listing directory " << name
00316 << " (comparing): "
00317 << ReposUI::errorCodeText(err) << endl;
00318 exit(1);
00319 }
00320
00321 if(compare.miscompare)
00322 {
00323 cerr << program_name
00324 << ": collapseBase changed directory " << name << "!"
00325 << endl;
00326 exit(1);
00327 }
00328 }
00329 }
00330 }
00331 catch(VestaConfig::failure f)
00332 {
00333 cerr << program_name << ": " << f.msg << endl;
00334 exit(2);
00335 }
00336 catch(SRPC::failure f)
00337 {
00338 cerr << program_name
00339 << ": SRPC failure; " << f.msg << " (" << f.r << ")" << endl;
00340 exit(2);
00341 }
00342 catch(ReposUI::failure f)
00343 {
00344 cerr << program_name << ": " << f.msg << endl;
00345 exit(2);
00346 }
00347 }