|
a/src/utils/fstreewalk.cpp |
|
b/src/utils/fstreewalk.cpp |
|
... |
|
... |
30 |
#include <cstring>
|
30 |
#include <cstring>
|
31 |
#include <algorithm>
|
31 |
#include <algorithm>
|
32 |
|
32 |
|
33 |
#include <sstream>
|
33 |
#include <sstream>
|
34 |
#include <list>
|
34 |
#include <list>
|
|
|
35 |
#include <set>
|
35 |
|
36 |
|
36 |
#include "debuglog.h"
|
37 |
#include "debuglog.h"
|
37 |
#include "pathut.h"
|
38 |
#include "pathut.h"
|
38 |
#include "fstreewalk.h"
|
39 |
#include "fstreewalk.h"
|
39 |
|
40 |
|
|
... |
|
... |
41 |
using namespace std;
|
42 |
using namespace std;
|
42 |
#endif /* NO_NAMESPACES */
|
43 |
#endif /* NO_NAMESPACES */
|
43 |
|
44 |
|
44 |
const int FsTreeWalker::FtwTravMask = FtwTravNatural|
|
45 |
const int FsTreeWalker::FtwTravMask = FtwTravNatural|
|
45 |
FtwTravBreadth|FtwTravFilesThenDirs|FtwTravBreadthThenDepth;
|
46 |
FtwTravBreadth|FtwTravFilesThenDirs|FtwTravBreadthThenDepth;
|
|
|
47 |
|
|
|
48 |
class DirId {
|
|
|
49 |
public:
|
|
|
50 |
dev_t dev;
|
|
|
51 |
ino_t ino;
|
|
|
52 |
DirId(dev_t d, ino_t i) : dev(d), ino(i) {}
|
|
|
53 |
bool operator<(const DirId& r) const
|
|
|
54 |
{
|
|
|
55 |
return dev < r.dev || (dev == r.dev && ino < r.ino);
|
|
|
56 |
}
|
|
|
57 |
};
|
46 |
|
58 |
|
47 |
class FsTreeWalker::Internal {
|
59 |
class FsTreeWalker::Internal {
|
48 |
int options;
|
60 |
int options;
|
49 |
int depthswitch;
|
61 |
int depthswitch;
|
50 |
stringstream reason;
|
62 |
stringstream reason;
|
|
... |
|
... |
52 |
list<string> skippedPaths;
|
64 |
list<string> skippedPaths;
|
53 |
// When doing Breadth or FilesThenDirs traversal, we keep a list
|
65 |
// When doing Breadth or FilesThenDirs traversal, we keep a list
|
54 |
// of directory paths to be processed, and we do not recurse.
|
66 |
// of directory paths to be processed, and we do not recurse.
|
55 |
list<string> dirs;
|
67 |
list<string> dirs;
|
56 |
int errors;
|
68 |
int errors;
|
|
|
69 |
set<DirId> donedirs;
|
57 |
void logsyserr(const char *call, const string ¶m)
|
70 |
void logsyserr(const char *call, const string ¶m)
|
58 |
{
|
71 |
{
|
59 |
errors++;
|
72 |
errors++;
|
60 |
reason << call << "(" << param << ") : " << errno << " : " <<
|
73 |
reason << call << "(" << param << ") : " << errno << " : " <<
|
61 |
strerror(errno) << endl;
|
74 |
strerror(errno) << endl;
|
|
... |
|
... |
290 |
} else {
|
303 |
} else {
|
291 |
return status;
|
304 |
return status;
|
292 |
}
|
305 |
}
|
293 |
|
306 |
|
294 |
// This is a directory, read it and process entries:
|
307 |
// This is a directory, read it and process entries:
|
|
|
308 |
|
|
|
309 |
// Detect if directory already seen. This could just be several
|
|
|
310 |
// symlinks pointing to the same place (if FtwFollow is set), it
|
|
|
311 |
// could also be some other kind of cycle. In any case, there is
|
|
|
312 |
// no point in entering again.
|
|
|
313 |
// For now, we'll ignore the "other kind of cycle" part and only monitor
|
|
|
314 |
// this is FtwFollow is set
|
|
|
315 |
if (data->options & FtwFollow) {
|
|
|
316 |
DirId dirid(stp->st_dev, stp->st_ino);
|
|
|
317 |
if (data->donedirs.find(dirid) != data->donedirs.end()) {
|
|
|
318 |
LOGINFO(("Not processing [%s] (already seen as other path)\n",
|
|
|
319 |
top.c_str()));
|
|
|
320 |
return status;
|
|
|
321 |
}
|
|
|
322 |
data->donedirs.insert(dirid);
|
|
|
323 |
}
|
|
|
324 |
|
295 |
DIR *d = opendir(top.c_str());
|
325 |
DIR *d = opendir(top.c_str());
|
296 |
if (d == 0) {
|
326 |
if (d == 0) {
|
297 |
data->logsyserr("opendir", top);
|
327 |
data->logsyserr("opendir", top);
|
298 |
switch (errno) {
|
328 |
switch (errno) {
|
299 |
case EPERM:
|
329 |
case EPERM:
|
|
... |
|
... |
393 |
#define OPT_r 0x8
|
423 |
#define OPT_r 0x8
|
394 |
#define OPT_c 0x10
|
424 |
#define OPT_c 0x10
|
395 |
#define OPT_b 0x20
|
425 |
#define OPT_b 0x20
|
396 |
#define OPT_d 0x40
|
426 |
#define OPT_d 0x40
|
397 |
#define OPT_m 0x80
|
427 |
#define OPT_m 0x80
|
|
|
428 |
#define OPT_L 0x100
|
398 |
|
429 |
|
399 |
class myCB : public FsTreeWalkerCB {
|
430 |
class myCB : public FsTreeWalkerCB {
|
400 |
public:
|
431 |
public:
|
401 |
FsTreeWalker::Status processone(const string &path,
|
432 |
FsTreeWalker::Status processone(const string &path,
|
402 |
const struct stat *st,
|
433 |
const struct stat *st,
|
|
... |
|
... |
435 |
// real 14m53.245s user 0m4.244s sys 0m34.494s
|
466 |
// real 14m53.245s user 0m4.244s sys 0m34.494s
|
436 |
// time trfstreewalk -b / > /data/tmp/breadth;
|
467 |
// time trfstreewalk -b / > /data/tmp/breadth;
|
437 |
// real 17m10.585s user 0m4.532s sys 0m35.033s
|
468 |
// real 17m10.585s user 0m4.532s sys 0m35.033s
|
438 |
|
469 |
|
439 |
static char usage [] =
|
470 |
static char usage [] =
|
440 |
"trfstreewalk [-p pattern] [-P ignpath] [-r] [-c] topdir\n"
|
471 |
"trfstreewalk [-p pattern] [-P ignpath] [-r] [-c] [-L] topdir\n"
|
441 |
" -r : norecurse\n"
|
472 |
" -r : norecurse\n"
|
442 |
" -c : no path canonification\n"
|
473 |
" -c : no path canonification\n"
|
|
|
474 |
" -L : follow symbolic links\n"
|
443 |
" -b : use breadth first walk\n"
|
475 |
" -b : use breadth first walk\n"
|
444 |
" -d : use almost depth first (dir files, then subdirs)\n"
|
476 |
" -d : use almost depth first (dir files, then subdirs)\n"
|
445 |
" -m : use breadth up to 4 deep then switch to -d\n"
|
477 |
" -m : use breadth up to 4 deep then switch to -d\n"
|
446 |
;
|
478 |
;
|
447 |
static void
|
479 |
static void
|
|
... |
|
... |
466 |
while (**argv)
|
498 |
while (**argv)
|
467 |
switch (*(*argv)++) {
|
499 |
switch (*(*argv)++) {
|
468 |
case 'b': op_flags |= OPT_b; break;
|
500 |
case 'b': op_flags |= OPT_b; break;
|
469 |
case 'c': op_flags |= OPT_c; break;
|
501 |
case 'c': op_flags |= OPT_c; break;
|
470 |
case 'd': op_flags |= OPT_d; break;
|
502 |
case 'd': op_flags |= OPT_d; break;
|
|
|
503 |
case 'L': op_flags |= OPT_L; break;
|
471 |
case 'm': op_flags |= OPT_m; break;
|
504 |
case 'm': op_flags |= OPT_m; break;
|
472 |
case 'r': op_flags |= OPT_r; break;
|
505 |
case 'r': op_flags |= OPT_r; break;
|
473 |
case 'p': op_flags |= OPT_p; if (argc < 2) Usage();
|
506 |
case 'p': op_flags |= OPT_p; if (argc < 2) Usage();
|
474 |
patterns.push_back(*(++argv));
|
507 |
patterns.push_back(*(++argv));
|
475 |
argc--;
|
508 |
argc--;
|
|
... |
|
... |
490 |
int opt = 0;
|
523 |
int opt = 0;
|
491 |
if (op_flags & OPT_r)
|
524 |
if (op_flags & OPT_r)
|
492 |
opt |= FsTreeWalker::FtwNoRecurse;
|
525 |
opt |= FsTreeWalker::FtwNoRecurse;
|
493 |
if (op_flags & OPT_c)
|
526 |
if (op_flags & OPT_c)
|
494 |
opt |= FsTreeWalker::FtwNoCanon;
|
527 |
opt |= FsTreeWalker::FtwNoCanon;
|
|
|
528 |
if (op_flags & OPT_L)
|
|
|
529 |
opt |= FsTreeWalker::FtwFollow;
|
495 |
|
530 |
|
496 |
if (op_flags & OPT_b)
|
531 |
if (op_flags & OPT_b)
|
497 |
opt |= FsTreeWalker::FtwTravBreadth;
|
532 |
opt |= FsTreeWalker::FtwTravBreadth;
|
498 |
else if (op_flags & OPT_d)
|
533 |
else if (op_flags & OPT_d)
|
499 |
opt |= FsTreeWalker::FtwTravFilesThenDirs;
|
534 |
opt |= FsTreeWalker::FtwTravFilesThenDirs;
|