# # # patch "NEWS" # from [dea638b40d2472eda5749bca9a56417eab50eb17] # to [7c750cfa903ee995d14599e7678aa5061999050a] # # patch "paths.cc" # from [94cfb3385d92668683114518029f786f89dbdd7b] # to [c6db93432b452384119501c050fbc0e94f5ac91a] # # patch "paths.hh" # from [9935beaae625aabbc9db1c24abac9c36ab2210f3] # to [e5be6f2b0e2ee3a9e41f405b221d83b478c69844] # # patch "tests/rename_warns_on_subdir_move/__driver__.lua" # from [33fa14b989319f08f63dc65ae2cec1c112d2ba83] # to [54f3a635476643fd907b987f474d9e70fa93719f] # # patch "work.cc" # from [b0c1770eaede6590c430e049d18ee6f62d097956] # to [6d2883991ffdb93278fcfa329d42c9981bf13a51] # ============================================================ --- NEWS dea638b40d2472eda5749bca9a56417eab50eb17 +++ NEWS 7c750cfa903ee995d14599e7678aa5061999050a @@ -77,7 +77,7 @@ Xxx Xxx 99 99:99:99 UTC 2010 (fixes monotone bug #29843) - the 'mv' command now warns when a source is being renamed onto - itself (fixes monotone bug #29484). + itself or one of its children (fixes monotone bug #29484). - The annotate command no longer fails if it should print out empty or untrusted date cert values ============================================================ --- paths.cc 94cfb3385d92668683114518029f786f89dbdd7b +++ paths.cc c6db93432b452384119501c050fbc0e94f5ac91a @@ -621,6 +621,24 @@ file_path::dirname_basename(file_path & } } +// returns true if this path is beneath other +bool +file_path::is_beneath_of(const file_path & other) const +{ + if (other.empty()) + return true; + + file_path basedir = dirname(); + while (!basedir.empty()) + { + L(FL("base: %s, other: %s") % basedir % other); + if (basedir == other) + return true; + basedir = basedir.dirname(); + } + return false; +} + // count the number of /-separated components of the path. unsigned int file_path::depth() const ============================================================ --- paths.hh 9935beaae625aabbc9db1c24abac9c36ab2210f3 +++ paths.hh e5be6f2b0e2ee3a9e41f405b221d83b478c69844 @@ -215,6 +215,9 @@ public: // does dirname() and basename() at the same time, for efficiency void dirname_basename(file_path &, path_component &) const; + // returns true if this path is beneath other + bool is_beneath_of(const file_path & other) const; + // returns the number of /-separated components of the path. // The empty path has depth zero. unsigned int depth() const; ============================================================ --- tests/rename_warns_on_subdir_move/__driver__.lua 33fa14b989319f08f63dc65ae2cec1c112d2ba83 +++ tests/rename_warns_on_subdir_move/__driver__.lua 54f3a635476643fd907b987f474d9e70fa93719f @@ -11,5 +11,5 @@ check(qgrep("cannot move `dir' to a subd check(mtn("mv", "dir", "dir"), 0, false, true) check(qgrep("cannot move `dir' to a subdirectory of itself, `dir/dir'", "stderr")) -xfail(mtn("mv", "dir", "dir/subdir"), 0, false, true) ---check(qgrep("cannot move `dir' to a subdirectory of itself, `dir/subdir/dir'", "stderr")) +check(mtn("mv", "dir", "dir/subdir"), 0, false, true) +check(qgrep("cannot move `dir' to a subdirectory of itself, `dir/subdir/dir'", "stderr")) ============================================================ --- work.cc b0c1770eaede6590c430e049d18ee6f62d097956 +++ work.cc 6d2883991ffdb93278fcfa329d42c9981bf13a51 @@ -1962,7 +1962,7 @@ workspace::perform_rename(database & db, E(new_roster.has_node(src), origin::user, F("source file %s is not versioned") % src); - if (src == dst) + if (src == dst || dst.is_beneath_of(src)) { if (get_path_status(dst) == path::directory) W(F("cannot move `%s' to a subdirectory of itself, `%s/%s'") % src % dst % src); @@ -2010,7 +2010,7 @@ workspace::perform_rename(database & db, E(!new_roster.has_node(d), origin::user, F("destination %s already exists in the workspace manifest") % d); - if (*i == dst) + if (*i == dst || dst.is_beneath_of(*i)) { W(F("cannot move `%s' to a subdirectory of itself, `%s/%s'") % *i % dst % *i);