/
PosixFileScanner.cpp
149 lines (131 loc) · 3.85 KB
/
PosixFileScanner.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
/*
* PosixFileScanner.cpp
*
* Copyright (C) 2009-11 by RStudio, Inc.
*
* This program is licensed to you under the terms of version 3 of the
* GNU Affero General Public License. This program is distributed WITHOUT
* ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
* AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
*
*/
#include <core/system/FileScanner.hpp>
#include <dirent.h>
#include <sys/stat.h>
#include <core/Error.hpp>
#include <core/Log.hpp>
#include <core/FilePath.hpp>
namespace core {
namespace system {
namespace {
#ifdef __APPLE__
int entryFilter(struct dirent *entry)
#else
int entryFilter(const struct dirent *entry)
#endif
{
if (::strcmp(entry->d_name, ".") == 0 || ::strcmp(entry->d_name, "..") == 0)
return 0;
else
return 1;
}
} // anonymous namespace
Error scanFiles(const tree<FileInfo>::iterator_base& fromNode,
bool recursive,
const boost::function<bool(const FileInfo&)>& filter,
const boost::function<void(const FileInfo&)>& onBeforeScanDir,
tree<FileInfo>* pTree)
{
// clear all existing
pTree->erase_children(fromNode);
// create FilePath for root
FilePath rootPath(fromNode->absolutePath());
// call onBeforeScanDir hook
if (onBeforeScanDir)
onBeforeScanDir(*fromNode);
// read directory contents
struct dirent **namelist;
int entries = ::scandir(fromNode->absolutePath().c_str(),
&namelist,
entryFilter,
::alphasort);
if (entries == -1)
{
Error error = systemError(boost::system::errc::no_such_file_or_directory,
ERROR_LOCATION);
error.addProperty("path", fromNode->absolutePath());
return error;
}
// iterate over entries
for(int i=0; i<entries; i++)
{
// get the entry (then free it) and compute the path
dirent entry = *namelist[i];
::free(namelist[i]);
std::string name(entry.d_name,
#ifdef __APPLE__
entry.d_namlen);
#else
entry.d_reclen);
#endif
std::string path = rootPath.childPath(name).absolutePath();
// get the attributes
struct stat st;
int res = ::lstat(path.c_str(), &st);
if (res == -1)
{
LOG_ERROR(systemError(errno, ERROR_LOCATION));
continue;
}
// create the FileInfo
FileInfo fileInfo;
bool isSymlink = S_ISLNK(st.st_mode);
if (S_ISDIR(st.st_mode))
{
fileInfo = FileInfo(path, true, isSymlink);
}
else
{
fileInfo = FileInfo(path,
false,
st.st_size,
#ifdef __APPLE__
st.st_mtimespec.tv_sec,
#else
st.st_mtime,
#endif
isSymlink);
}
// apply the filter (if any)
if (!filter || filter(fileInfo))
{
// add the correct type of FileEntry
if (fileInfo.isDirectory())
{
tree<FileInfo>::iterator_base child = pTree->append_child(fromNode,
fileInfo);
// recurse if requested and this isn't a link
if (recursive && !fileInfo.isSymlink())
{
Error error = scanFiles(child, true, filter, pTree);
if (error)
{
LOG_ERROR(error);
continue;
}
}
}
else
{
pTree->append_child(fromNode, fileInfo);
}
}
}
// free the namelist
::free(namelist);
// return success
return Success();
}
} // namespace system
} // namespace core