00001 #ifndef DIRECTORY_TREE_IMPLEMENTATION_FILE
00002 #define DIRECTORY_TREE_IMPLEMENTATION_FILE
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "directory.h"
00019 #include "directory_tree.h"
00020 #include "filename.h"
00021 #include "filename_list.h"
00022 #include "filename_tree.h"
00023
00024 #include <basis/function.h>
00025 #include <basis/log_base.h>
00026 #include <basis/string_array.h>
00027 #include <nodes/node.h>
00028 #include <textual/string_manipulation.h>
00029
00030 using namespace basis;
00031 using namespace nodes;
00032
00033
00034
00035
00036 #undef LOG
00037 #define LOG(s) CLASS_EMERGENCY_LOG(program_wide_logger(), s)
00038
00040
00041 class dir_tree_iterator : public filename_tree::iterator
00042 {
00043 public:
00044 filename_tree *_current;
00045
00046 dir_tree_iterator(const filename_tree *initial,
00047 tree::traversal_directions dir)
00048 : filename_tree::iterator(initial, dir), _current(NIL) {}
00049 };
00050
00052
00053 directory_tree::directory_tree()
00054 : _scanned_okay(false),
00055 _path(new istring),
00056 _pattern(new istring),
00057 _real_tree(new filename_tree),
00058 _ignore_files(false),
00059 _creator(new fname_tree_creator)
00060 {
00061 }
00062
00063 directory_tree::directory_tree(const istring &path, const char *pattern,
00064 bool ignore_files)
00065 : _scanned_okay(false),
00066 _path(new istring(path)),
00067 _pattern(new istring(pattern)),
00068 _real_tree(NIL),
00069 _ignore_files(ignore_files),
00070 _creator(new fname_tree_creator)
00071 {
00072 reset(path, pattern);
00073 }
00074
00075 directory_tree::~directory_tree()
00076 {
00077 _scanned_okay = false;
00078 WHACK(_path);
00079 WHACK(_pattern);
00080 WHACK(_real_tree);
00081 WHACK(_creator);
00082 }
00083
00084 const istring &directory_tree::path() const { return *_path; }
00085
00086 void directory_tree::pack(byte_array &packed_form) const
00087 {
00088 attach(packed_form, int(_scanned_okay));
00089 attach(packed_form, int(_ignore_files));
00090 _path->pack(packed_form);
00091 _pattern->pack(packed_form);
00092 _real_tree->recursive_pack(packed_form);
00093 }
00094
00095 bool directory_tree::unpack(byte_array &packed_form)
00096 {
00097 int temp;
00098 if (!detach(packed_form, temp)) return false;
00099 _scanned_okay = temp;
00100 if (!detach(packed_form, temp)) return false;
00101 _ignore_files = temp;
00102 if (!_path->unpack(packed_form)) return false;
00103 if (!_pattern->unpack(packed_form)) return false;
00104 WHACK(_real_tree);
00105 _real_tree = (filename_tree *)packable_tree::recursive_unpack
00106 (packed_form, *_creator);
00107 if (!_real_tree) {
00108 _real_tree = new filename_tree;
00109 return false;
00110 }
00111 return true;
00112 }
00113
00114 void directory_tree::text_form(istring &target, bool show_files)
00115 {
00116 dir_tree_iterator *ted = start(directory_tree::prefix);
00117
00118
00119 int depth;
00120 filename curr;
00121 string_array files;
00122
00123 while (current(*ted, curr, files)) {
00124
00125 directory_tree::depth(*ted, depth);
00126 target += string_manipulation::indentation(depth * 2) + istring("[")
00127 + curr.raw() + "]" + log_base::platform_ending();
00128 if (show_files) {
00129 istring names;
00130 for (int i = 0; i < files.length(); i++) names += files[i] + " ";
00131 if (names.length()) {
00132 istring split;
00133 string_manipulation::split_lines(names, split, depth * 2 + 2);
00134 target += split + log_base::platform_ending();
00135 }
00136 }
00137
00138
00139 next(*ted);
00140 }
00141
00142 throw_out(ted);
00143 }
00144
00145 void directory_tree::traverse(const istring &path, const char *pattern,
00146 filename_tree &add_to)
00147 {
00148 FUNCDEF("traverse");
00149
00150 add_to._dirname = filename(path, istring::empty_string());
00151 add_to._files.reset();
00152 #ifdef DEBUG_DIRECTORY_TREE
00153 LOG(istring("working on node ") + add_to._dirname.raw());
00154 #endif
00155
00156
00157 directory curr(path, "*");
00158 if (!curr.good()) return;
00159
00160 if (!_ignore_files) {
00161
00162 directory curr_stringent(path, pattern);
00163 add_to._files = curr_stringent.files();
00164 }
00165
00166
00167
00168 const string_array &dirs = curr.directories();
00169 for (int i = 0; i < dirs.length(); i++) {
00170 filename_tree *new_branch = NIL;
00171 istring new_path = path + filename::default_separator() + dirs[i];
00172 #ifdef DEBUG_DIRECTORY_TREE
00173 LOG(istring("seeking path: ") + new_path);
00174 #endif
00175 for (int q = 0; q < add_to.branches(); q++) {
00176 filename_tree *curr_kid = (filename_tree *)add_to.branch(q);
00177 #ifdef DEBUG_DIRECTORY_TREE
00178 LOG(istring("curr kid: ") + curr_kid->_dirname);
00179 #endif
00180 if (filename(new_path).raw().iequals(filename
00181 (curr_kid->_dirname).raw())) {
00182 new_branch = curr_kid;
00183 #ifdef DEBUG_DIRECTORY_TREE
00184 LOG(istring("using existing branch for ") + new_path);
00185 #endif
00186 break;
00187 }
00188 }
00189 if (!new_branch) {
00190 #ifdef DEBUG_DIRECTORY_TREE
00191 LOG(istring("adding new branch for ") + new_path);
00192 #endif
00193 new_branch = new filename_tree;
00194 add_to.attach(new_branch);
00195 new_branch->_depth = add_to._depth + 1;
00196 }
00197 #ifdef DEBUG_DIRECTORY_TREE
00198 LOG(istring("traversing sub-node ") + new_path);
00199 #endif
00200 traverse(new_path, pattern, *new_branch);
00201 }
00202 }
00203
00204 bool directory_tree::reset(const istring &path, const char *pattern)
00205 {
00206 _scanned_okay = false;
00207 WHACK(_real_tree);
00208 *_path = path;
00209 *_pattern = pattern;
00210 _real_tree = new filename_tree;
00211
00212
00213 directory curr(path, "*");
00214 if (!curr.good()) return false;
00215
00216
00217
00218
00219 traverse(path, pattern, *_real_tree);
00220 _scanned_okay = true;;
00221 return true;
00222 }
00223
00224 dir_tree_iterator *directory_tree::start_at(filename_tree *start,
00225 traversal_types type) const
00226 {
00227
00228 tree::traversal_directions dir = tree::prefix;
00229 if (type == infix) dir = tree::infix;
00230 else if (type == postfix) dir = tree::postfix;
00231
00232 return new dir_tree_iterator(start, dir);
00233 }
00234
00235 dir_tree_iterator *directory_tree::start(traversal_types type) const
00236 {
00237
00238 tree::traversal_directions dir = tree::prefix;
00239 if (type == infix) dir = tree::infix;
00240 else if (type == postfix) dir = tree::postfix;
00241
00242 return new dir_tree_iterator(_real_tree, dir);
00243 }
00244
00245 bool directory_tree::jump_to(dir_tree_iterator &scanning,
00246 const istring &sub_path)
00247 {
00248 FUNCDEF("jump_to");
00249 string_array pieces;
00250 filename(sub_path).separate(pieces);
00251 for (int i = 0; i < pieces.length(); i++) {
00252 filename_tree *curr = dynamic_cast<filename_tree *>(scanning.current());
00253 #ifdef DEBUG_DIRECTORY_TREE
00254 LOG(istring("at ") + curr->_dirname.raw());
00255 #endif
00256 string_array sub_pieces = pieces.subarray(i, i);
00257 filename curr_path;
00258 curr_path.join(sub_pieces);
00259 curr_path = filename(curr->_dirname.raw() + filename::default_separator()
00260 + curr_path.raw());
00261 #ifdef DEBUG_DIRECTORY_TREE
00262 LOG(istring("made curr path ") + curr_path.raw());
00263 #endif
00264 if (!curr) return false;
00265 bool found_it = false;
00266 for (int j = 0; j < curr->branches(); j++) {
00267 filename_tree *sub = dynamic_cast<filename_tree *>(curr->branch(j));
00268 #ifdef DEBUG_DIRECTORY_TREE
00269 LOG(istring("looking at ") + sub->_dirname.raw());
00270 #endif
00271 if (sub->_dirname.compare_prefix(curr_path)) {
00272
00273 scanning.push(sub);
00274 #ifdef DEBUG_DIRECTORY_TREE
00275 LOG(istring("found at ") + sub->_dirname.raw());
00276 #endif
00277 found_it = true;
00278 break;
00279 }
00280 }
00281 if (!found_it) {
00282 #ifdef DEBUG_DIRECTORY_TREE
00283 LOG(istring("could not find ") + curr_path.raw());
00284 #endif
00285 return false;
00286 }
00287 }
00288 return true;
00289 }
00290
00291 filename_tree *directory_tree::goto_current(dir_tree_iterator &scanning)
00292 {
00293 if (!scanning._current) {
00294
00295 scanning._current = (filename_tree *)scanning.next();
00296 }
00297
00298 if (!scanning._current) return NIL;
00299
00300
00301 return dynamic_cast<filename_tree *>(scanning._current);
00302 }
00303
00304 bool directory_tree::current_dir(dir_tree_iterator &scanning,
00305 filename &dir_name)
00306 {
00307 dir_name = istring::empty_string();
00308 filename_tree *tof = goto_current(scanning);
00309 if (!tof) return false;
00310 dir_name = tof->_dirname;
00311 return true;
00312 }
00313
00314 bool directory_tree::current(dir_tree_iterator &scanning,
00315 filename &dir_name, string_array &to_fill)
00316 {
00317
00318 dir_name = istring::empty_string();
00319 to_fill.reset();
00320
00321 filename_tree *tof = goto_current(scanning);
00322 if (!tof) return false;
00323
00324
00325 dir_name = tof->_dirname;
00326 tof->_files.fill(to_fill);
00327
00328 return true;
00329 }
00330
00331 bool directory_tree::current(dir_tree_iterator &scanning,
00332 filename &dir_name, filename_list &to_fill)
00333 {
00334
00335 dir_name = istring::empty_string();
00336 to_fill.reset();
00337
00338 filename_tree *tof = goto_current(scanning);
00339 if (!tof) return false;
00340
00341
00342 dir_name = tof->_dirname;
00343 to_fill = tof->_files;
00344
00345 return true;
00346 }
00347
00348 filename_list *directory_tree::access(dir_tree_iterator &scanning)
00349 {
00350 filename_tree *tof = goto_current(scanning);
00351 if (!tof) return NIL;
00352 return &tof->_files;
00353 }
00354
00355 bool directory_tree::depth(dir_tree_iterator &scanning, int &depth)
00356 {
00357 depth = -1;
00358 filename_tree *tof = goto_current(scanning);
00359 if (!tof) return false;
00360 depth = tof->_depth;
00361 return true;
00362 }
00363
00364 bool directory_tree::children(dir_tree_iterator &scanning, int &kids)
00365 {
00366 kids = -1;
00367 filename_tree *tof = goto_current(scanning);
00368 if (!tof) return false;
00369 kids = tof->branches();
00370 return true;
00371 }
00372
00373 bool directory_tree::next(dir_tree_iterator &scanning)
00374 {
00375 scanning._current = (filename_tree *)scanning.next();
00376 return !!scanning._current;
00377 }
00378
00379 void directory_tree::throw_out(dir_tree_iterator * &to_whack)
00380 {
00381 WHACK(to_whack);
00382 }
00383
00384 filename_tree *directory_tree::seek(const istring &dir_name_in,
00385 bool ignore_initial) const
00386 {
00387 FUNCDEF("seek");
00388 array<filename_tree *> examining;
00389
00390
00391 #ifdef DEBUG_DIRECTORY_TREE
00392 LOG(istring("seeking on root of: ") + *_path);
00393 #endif
00394
00395 istring dir_name = filename(dir_name_in).raw();
00396
00397 if (ignore_initial)
00398 dir_name = path() + filename::default_separator()
00399 + filename(dir_name_in).raw();
00400
00401 #ifdef DEBUG_DIRECTORY_TREE
00402 LOG(istring("adding root: ") + _real_tree->_dirname);
00403 #endif
00404 examining += _real_tree;
00405
00406 istring sequel;
00407
00408
00409 while (examining.length()) {
00410 int posn;
00411 bool found = false;
00412
00413
00414 filename_tree *check = NIL;
00415 for (posn = 0; posn < examining.length(); posn++) {
00416 check = examining[posn];
00417 filename current(check->_dirname);
00418 #ifdef DEBUG_DIRECTORY_TREE
00419 LOG(istring("looking at ") + current.raw());
00420 #endif
00421 if (current.compare_prefix(dir_name, sequel)) {
00422
00423 #ifdef DEBUG_DIRECTORY_TREE
00424 LOG(istring("matched! at ") + current.raw());
00425 #endif
00426 found = true;
00427 if (!sequel) {
00428
00429 #ifdef DEBUG_DIRECTORY_TREE
00430 LOG(istring("exact match at ") + current.raw() + "! done!!!");
00431 #endif
00432 return check;
00433 } else {
00434 #ifdef DEBUG_DIRECTORY_TREE
00435 LOG(istring("inexact match because sequel=") + sequel);
00436 #endif
00437 }
00438 break;
00439 }
00440 }
00441 if (!found) return NIL;
00442
00443
00444
00445 if (!check) {
00446
00447 LOG("serious logical error: tree was not located.");
00448 return NIL;
00449 }
00450 examining.reset();
00451 for (int i = 0; i < check->branches(); i++)
00452 examining += (filename_tree *)check->branch(i);
00453 }
00454
00455 return NIL;
00456 }
00457
00458 bool directory_tree::calculate(bool just_size)
00459 { return calculate(_real_tree, just_size); }
00460
00461 bool directory_tree::calculate(filename_tree *start, bool just_size)
00462 {
00463 FUNCDEF("calculate");
00464 dir_tree_iterator *ted = start_at(start, directory_tree::postfix);
00465
00466
00467
00468
00469 int depth;
00470 filename curr;
00471 filename_list *files;
00472
00473 while (directory_tree::current_dir(*ted, curr)) {
00474
00475 #ifdef DEBUG_DIRECTORY_TREE
00476 LOG(istring("calcing node ") + curr.raw());
00477 #endif
00478 files = directory_tree::access(*ted);
00479 directory_tree::depth(*ted, depth);
00480 for (int i = 0; i < files->elements(); i++) {
00481 if (!files->borrow(i)->calculate(curr.raw(), just_size)) {
00482 LOG(istring("failure to calculate ") + files->get(i)->text_form());
00483 }
00484 }
00485
00486 directory_tree::next(*ted);
00487 }
00488
00489 directory_tree::throw_out(ted);
00490 return true;
00491 }
00492
00493 bool directory_tree::compare_trees(const directory_tree &source,
00494 const directory_tree &target, filename_list &differences,
00495 bool compare_size, bool compare_checksum)
00496 {
00497 return compare_trees(source, istring::empty_string(), target,
00498 istring::empty_string(), differences, compare_size, compare_checksum);
00499 }
00500
00501 bool directory_tree::compare_trees(const directory_tree &source,
00502 const istring &source_start_in, const directory_tree &target,
00503 const istring &target_start_in, filename_list &differences,
00504 bool compare_size, bool compare_checksum)
00505 {
00506 FUNCDEF("compare_trees");
00507 differences.reset();
00508
00509
00510 filename source_start(source_start_in);
00511 filename target_start(target_start_in);
00512
00513 dir_tree_iterator *ted = source.start(directory_tree::prefix);
00514
00515
00516 istring real_source_start = source.path();
00517 if (source_start.raw().t()) {
00518
00519 real_source_start = real_source_start + filename::default_separator()
00520 + source_start.raw();
00521 if (!directory_tree::jump_to(*ted, source_start.raw())) {
00522
00523 LOG(istring("failed to find source start in tree, given as ")
00524 + source_start.raw());
00525 return false;
00526 }
00527 }
00528
00529 filename curr;
00530 filename_list files;
00531
00532
00533 int source_pieces = 0;
00534 {
00535 string_array temp;
00536 filename(real_source_start).separate(temp);
00537 source_pieces = temp.length();
00538 }
00539
00540 bool seen_zero_pieces = false;
00541 while (directory_tree::current(*ted, curr, files)) {
00542
00543
00544
00545 #ifdef DEBUG_DIRECTORY_TREE
00546 LOG(istring("curr dir in tree: ") + curr.raw());
00547 #endif
00548
00549 string_array pieces;
00550 curr.separate(pieces);
00551 #ifdef DEBUG_DIRECTORY_TREE
00552 LOG(istring("name in pieces:") + pieces.text_form());
00553 #endif
00554 pieces.zap(0, source_pieces - 1);
00555
00556
00557 filename corresponding_name;
00558 corresponding_name.join(pieces);
00559 #ifdef DEBUG_DIRECTORY_TREE
00560 LOG(istring("computed target name as: ") + corresponding_name);
00561 #endif
00562 filename original_correspondence(corresponding_name);
00563
00564 if (!corresponding_name.raw().t()) {
00565 if (seen_zero_pieces) {
00566 #ifdef DEBUG_DIRECTORY_TREE
00567 LOG(istring("breaking out now due to empty correspondence"));
00568 #endif
00569 break;
00570 }
00571 seen_zero_pieces = true;
00572 }
00573 if (target_start.raw().t()) {
00574 corresponding_name = filename(target_start.raw()
00575 + filename::default_separator() + corresponding_name.raw());
00576 }
00577 #ifdef DEBUG_DIRECTORY_TREE
00578 LOG(istring("target with start is: ") + corresponding_name);
00579 #endif
00580
00581 filename_tree *target_now = target.seek(corresponding_name.raw(), true);
00582 if (!target_now) {
00583
00584
00585 #ifdef DEBUG_DIRECTORY_TREE
00586 LOG(istring("could not find dir in target for ") + curr.raw()
00587 + " which we computed corresp as " + corresponding_name.raw());
00588 #endif
00589 }
00590
00591
00592 for (int i = 0; i < files.elements(); i++) {
00593 if (!target_now
00594 || !target_now->_files.member(*files[i], compare_size,
00595 compare_checksum) ) {
00596
00597
00598 #ifdef DEBUG_DIRECTORY_TREE
00599 LOG(istring("adding record: ") + files[i]->text_form());
00600 #endif
00601
00602 file_info *new_record = new file_info(*files[i]);
00603 istring original = new_record->raw();
00604 #ifdef DEBUG_DIRECTORY_TREE
00605 LOG(istring("current: ") + new_record->raw());
00606 #endif
00607
00608 istring actual_name = source_start.raw();
00609 #ifdef DEBUG_DIRECTORY_TREE
00610 if (actual_name.t()) LOG(istring("sname=") + actual_name);
00611 #endif
00612 if (actual_name.length()) actual_name += filename::default_separator();
00613 actual_name += original_correspondence.raw();
00614 if (actual_name.length()) actual_name += filename::default_separator();
00615 actual_name += new_record->raw();
00616 #ifdef DEBUG_DIRECTORY_TREE
00617 if (actual_name.t()) LOG(istring("sname=") + actual_name);
00618 #endif
00619 (filename &)(*new_record) = filename(actual_name);
00620
00621 istring targ_name = corresponding_name.raw();
00622 #ifdef DEBUG_DIRECTORY_TREE
00623 if (targ_name.t()) LOG(istring("tname=") + targ_name);
00624 #endif
00625 if (targ_name.length()) targ_name += filename::default_separator();
00626 targ_name += original;
00627 #ifdef DEBUG_DIRECTORY_TREE
00628 if (targ_name.t()) LOG(istring("tname=") + targ_name);
00629 #endif
00630
00631 new_record->secondary(targ_name);
00632
00633 differences += new_record;
00634 #ifdef DEBUG_DIRECTORY_TREE
00635 LOG(istring("came out as: ") + new_record->text_form());
00636 #endif
00637 }
00638 }
00639
00640
00641 directory_tree::next(*ted);
00642 }
00643
00644 directory_tree::throw_out(ted);
00645
00646 return true;
00647 }
00648
00649 outcome directory_tree::find_common_root(const istring &finding, bool exists,
00650 filename_tree * &found, istring &reassembled, string_array &pieces,
00651 int &match_place)
00652 {
00653 FUNCDEF("find_common_root");
00654
00655 filename adding(finding);
00656 if (exists && !adding.good())
00657 return common::BAD_INPUT;
00658 int file_subtract = 0;
00659 if (exists && !adding.is_directory()) file_subtract = 1;
00660
00661
00662 pieces.reset();
00663 adding.separate(pieces);
00664
00665
00666
00667 string_array root_pieces;
00668 filename temp_file(path());
00669 temp_file.separate(root_pieces);
00670
00671
00672
00673 filename_tree *last_match = _real_tree;
00674 int list_length = pieces.length() - file_subtract;
00675 reassembled = "";
00676
00677
00678 for (int i = 0; i < root_pieces.length() - 1; i++) {
00679 bool add_slash = false;
00680 if (reassembled.length() && (reassembled[reassembled.end()] != '/') )
00681 add_slash = true;
00682 if (add_slash) reassembled += "/";
00683 reassembled += pieces[i];
00684 if (reassembled[reassembled.end()] == ':') {
00685 #ifdef DEBUG_DIRECTORY_TREE
00686 LOG(istring("skipping drive component ") + reassembled);
00687 #endif
00688 continue;
00689 }
00690 }
00691
00692 #ifdef DEBUG_DIRECTORY_TREE
00693 LOG(istring("after pre-assembly, path is ") + reassembled);
00694 #endif
00695
00696 outcome to_return = common::NOT_FOUND;
00697
00698 for (match_place = root_pieces.length() - 1; match_place < list_length;
00699 match_place++) {
00700
00701 bool add_slash = false;
00702 if (reassembled.length() && (reassembled[reassembled.end()] != '/') )
00703 add_slash = true;
00704
00705 if (add_slash) reassembled += "/";
00706 reassembled += pieces[match_place];
00707
00708 if (reassembled[reassembled.end()] == ':') {
00709 #ifdef DEBUG_DIRECTORY_TREE
00710 LOG(istring("skipping drive component ") + reassembled);
00711 #endif
00712 continue;
00713 }
00714 reassembled = filename(reassembled).raw();
00715 #ifdef DEBUG_DIRECTORY_TREE
00716 LOG(istring("now seeking ") + reassembled);
00717 #endif
00718 filename_tree *sought = seek(reassembled, false);
00719 if (!sought) {
00720 #ifdef DEBUG_DIRECTORY_TREE
00721 LOG(istring("couldn't find ") + reassembled);
00722 #endif
00723 if (!exists && (match_place == list_length - 1)) {
00724
00725
00726 if (last_match->_files.member(pieces[match_place])) {
00727
00728 to_return = common::OKAY;
00729 match_place--;
00730 break;
00731 }
00732 }
00733 match_place--;
00734 break;
00735 } else {
00736
00737 #ifdef DEBUG_DIRECTORY_TREE
00738 LOG(istring("found subtree for ") + reassembled);
00739 #endif
00740 last_match = sought;
00741 }
00742 }
00743
00744
00745 if (match_place >= list_length) {
00746 match_place = list_length - 1;
00747 to_return = common::OKAY;
00748 }
00749
00750 found = last_match;
00751 return to_return;
00752 }
00753
00754 outcome directory_tree::add_path(const istring &new_item, bool just_size)
00755 {
00756 FUNCDEF("add_path");
00757
00758 filename adding(new_item);
00759 if (!adding.good()) {
00760 LOG(istring("non-existent new item! ") + new_item);
00761 return common::BAD_INPUT;
00762 }
00763 int file_subtract = 0;
00764 if (!adding.is_directory()) file_subtract = 1;
00765 #ifdef DEBUG_DIRECTORY_TREE
00766 if (file_subtract) LOG(istring("adding a file ") + new_item)
00767 else LOG(istring("adding a directory ") + new_item);
00768 #endif
00769
00770
00771
00772 string_array pieces;
00773 filename_tree *last_match = NIL;
00774 int comp_index;
00775 istring reassembled;
00776 outcome ret = find_common_root(new_item, true, last_match, reassembled,
00777 pieces, comp_index);
00778 if (!last_match) {
00779 LOG(istring("serious error finding common root for ") + new_item
00780 + ", got NIL tree.");
00781 return common::FAILURE;
00782 }
00783
00784 if (!file_subtract) {
00785 if (ret != common::OKAY) {
00786
00787 #ifdef DEBUG_DIRECTORY_TREE
00788 LOG(istring("now adding node for ") + reassembled);
00789 #endif
00790 filename_tree *new_branch = new filename_tree;
00791 new_branch->_depth = last_match->_depth + 1;
00792 last_match->attach(new_branch);
00793 last_match = new_branch;
00794 } else {
00795 #ifdef DEBUG_DIRECTORY_TREE
00796 LOG(istring("matched properly. reassembled set to ") + reassembled);
00797 #endif
00798 }
00799 }
00800
00801 if (file_subtract) {
00802 if (ret != common::OKAY) {
00803 #ifdef DEBUG_DIRECTORY_TREE
00804 LOG(istring("common gave us posn of: ") + reassembled);
00805 #endif
00806
00807 string_array partial_pieces;
00808 filename(reassembled).separate(partial_pieces);
00809 int levels_missing = pieces.length() - partial_pieces.length();
00810
00811
00812
00813 for (int i = 0; i < levels_missing; i++) {
00814 #ifdef DEBUG_DIRECTORY_TREE
00815 LOG(istring("adding intermediate directory: ") + reassembled);
00816 #endif
00817 filename_tree *new_branch = new filename_tree;
00818 new_branch->_depth = last_match->_depth + 1;
00819 new_branch->_dirname = filename(reassembled).raw();
00820 last_match->attach(new_branch);
00821 last_match = new_branch;
00822 reassembled += istring("/") + pieces[partial_pieces.length() + i];
00823 reassembled = filename(reassembled).raw();
00824 }
00825 }
00826
00827 if (!last_match->_files.find(pieces[pieces.last()])) {
00828 #ifdef DEBUG_DIRECTORY_TREE
00829 LOG(istring("adding new file ") + pieces[pieces.last()]
00830 + " at " + reassembled);
00831 #endif
00832 file_info *to_add = new file_info(pieces[pieces.last()]);
00833 to_add->calculate(reassembled, just_size);
00834 last_match->_files += to_add;
00835 } else {
00836 #ifdef DEBUG_DIRECTORY_TREE
00837 LOG(istring("not adding existing file ") + pieces[pieces.last()]
00838 + " at " + reassembled);
00839 #endif
00840 }
00841 } else {
00842
00843 #ifdef DEBUG_DIRECTORY_TREE
00844 LOG(istring("doing traverse in ") + last_match->_dirname
00845 + " to add " + reassembled);
00846 #endif
00847 traverse(reassembled, "*", *last_match);
00848
00849 calculate(last_match, just_size);
00850 }
00851
00852 return common::OKAY;
00853 }
00854
00855 outcome directory_tree::remove_path(const istring &zap_item)
00856 {
00857 FUNCDEF("remove_path");
00858
00859 string_array pieces;
00860 filename_tree *last_match = NIL;
00861 int comp_index;
00862 istring reassembled;
00863 outcome ret = find_common_root(zap_item, false, last_match, reassembled,
00864 pieces, comp_index);
00865 if (!last_match) return common::NOT_FOUND;
00866
00867
00868 if (ret != common::OKAY) {
00869 #ifdef DEBUG_DIRECTORY_TREE
00870 LOG(istring("got error seeking ") + zap_item + " of "
00871 + common::outcome_name(ret));
00872 #endif
00873 return ret;
00874 }
00875
00876 if (comp_index == pieces.last()) {
00877
00878 #ifdef DEBUG_DIRECTORY_TREE
00879 LOG(istring("found directory match for ") + zap_item);
00880 #endif
00881 } else {
00882 #ifdef DEBUG_DIRECTORY_TREE
00883 LOG(istring("may have found file match for ") + zap_item);
00884 #endif
00885 filename to_seek(pieces[pieces.last()]);
00886 if (!last_match->_files.member(to_seek)) {
00887
00888 #ifdef DEBUG_DIRECTORY_TREE
00889 LOG(istring("couldn't find file match in common root for ") + zap_item);
00890 #endif
00891 return common::NOT_FOUND;
00892 } else {
00893 int indy = last_match->_files.locate(to_seek);
00894 #ifdef DEBUG_DIRECTORY_TREE
00895 LOG(istring("found match to remove for ") + zap_item);
00896 #endif
00897 last_match->_files.zap(indy, indy);
00898 return common::OKAY;
00899 }
00900 }
00901
00902 #ifdef DEBUG_DIRECTORY_TREE
00903 LOG(istring("going to whack node at: ") + last_match->_dirname.raw());
00904 #endif
00905
00906
00907 filename_tree *parent = (filename_tree *)last_match->parent();
00908 if (!parent || (last_match == _real_tree)) {
00909
00910 #ifdef DEBUG_DIRECTORY_TREE
00911 LOG("there's a problem whacking this node; it's the root.");
00912 #endif
00913 return common::BAD_INPUT;
00914 }
00915 #ifdef DEBUG_DIRECTORY_TREE
00916 LOG(istring("pruning tree at ") + last_match->_dirname.raw());
00917 #endif
00918 parent->prune(last_match);
00919 WHACK(last_match);
00920
00921 return common::OKAY;
00922 }
00923
00924
00925 #endif //DIRECTORY_TREE_IMPLEMENTATION_FILE
00926