17#define CDEBUG(...) Ase::debug ("crawler", __VA_ARGS__)
22ResourceCrawler::ResourceCrawler()
26FileCrawler::FileCrawler (
const String &cwd,
bool constraindir,
bool constrainfile) :
27 cwd_ (
"/"), constraindir_ (constraindir), constrainfile_ (constrainfile)
30 assign_ (encodefs (cwd),
false,
false);
35FileCrawler::list_entries ()
38 DIR *dir =
opendir (cwd_.c_str());
40 CDEBUG (
"%s: opendir('%s'): %s", __func__, cwd_,
strerror (
errno));
42 String cwdfile = cwd_ +
"/";
51 struct stat statbuf = { 0, };
52 if (0 !=
fstatat (
dirfd (dir), de->d_name, &statbuf, AT_NO_AUTOMOUNT))
54 is_dir = S_ISDIR (statbuf.st_mode);
55 is_reg = S_ISREG (statbuf.st_mode);
56 size = statbuf.st_size;
57 mtime = statbuf.st_mtim.tv_sec * 1000 + statbuf.st_mtim.tv_nsec / 1000000;
59 if (!is_reg && !is_dir)
62 .
type = is_dir ? ResourceType::FOLDER : ResourceType::FILE,
64 .uri =
encodefs (cwdfile + de->d_name) + (is_dir ?
"/" :
""),
66 r.
size = is_dir && size > 0 ? -size : size;
75FileCrawler::expand_fsdir (
const String &fsdir)
78 return Path::dir_terminate (cwd_);
81 String dir = Path::xdg_dir (fsdir);
83 return Path::dir_terminate (dir);
89FileCrawler::current_folder ()
92 .
type = ResourceType::FOLDER,
94 .uri =
encodefs (Path::dir_terminate (cwd_)),
96 struct stat statbuf = { 0, };
97 if (
lstat (cwd_.c_str(), &statbuf) == 0)
99 r.size = statbuf.st_size;
100 r.mtime = statbuf.st_mtim.tv_sec * 1000 + statbuf.st_mtim.tv_nsec / 1000000;
106FileCrawler::folder()
const
112FileCrawler::folder (
const Resource &newfolder)
114 assign_ (newfolder.
uri,
false);
118FileCrawler::entries()
const
124FileCrawler::entries (
const ResourceS &newentries)
131FileCrawler::assign_ (
const String &utf8path,
bool existingfile,
bool notify)
136 dir.
find (
"/") == dir.npos &&
142 dir = Path::xdg_dir (&dir[1]);
143 if (dir.
empty() || dir ==
"/")
147 Fs::path p = Path::expand_tilde (dir);
158 if (Path::check (p,
"d"))
159 cwd_ = Path::dir_terminate (p);
160 else if (Path::check (p,
"e")) {
163 }
else if (constraindir_) {
164 while (p.
string().size() > 1 &&
165 !Path::check (p,
"d")) {
166 filename = !existingfile || Path::check (p,
"e") ? p.
filename() :
"";
171 filename = !existingfile || Path::check (p,
"e") ? p.
filename() :
"";
175 while (cwd_.size() > 1 && cwd_.back() ==
'/')
176 cwd_.resize (cwd_.size() - 1);
179 emit_notify (
"folder");
180 emit_notify (
"entries");
181 emit_notify (
"current");
182 emit_notify (
"entries");
184 return { cwd_, filename };
189FileCrawler::canonify_fspath (
const String &fscwd,
const String &fsfragment,
bool constraindir,
bool constrainfile)
192 Fs::path p = Path::expand_tilde (fsfragment);
204 if (Path::check (p,
"d"))
205 return Path::dir_terminate (p);
206 if (Path::check (p,
"e"))
215 if (constrainfile && !Path::check (p,
"e"))
218 if (Path::check (p,
"d"))
219 return Path::dir_terminate (p);
225FileCrawler::canonify (
const String &utf8cwd,
const String &utf8fragment,
bool constraindir,
bool constrainfile)
246 FileCrawlerP cp = FileCrawler::make_shared (
"/dev",
true,
false);
249 r = c.canonify_fspath (
"",
"/dev/N°…Diŕ/N°…Fílė", 1, 1); e =
"/dev/";
TCMP (r, ==, e);
250 r = c.canonify_fspath (
".",
".", 1, 1); e =
"/dev/";
TCMP (r, ==, e);
251 r = c.canonify_fspath (
"",
"/dev/N°…Diŕ/null", 1, 1); e =
"/dev/null";
TCMP (r, ==, e);
252 r = c.canonify_fspath (
"",
"/tmp/N°…Diŕ/N°…Fílė", 1, 0); e =
"/tmp/N°…Fílė";
TCMP (r, ==, e);
253 r = c.canonify_fspath (
"",
"/tmp/N°…Diŕ//.//", 0, 0); e =
"/tmp/N°…Diŕ/";
TCMP (r, ==, e);
254 r = c.canonify_fspath (
"",
"/tmp/N°…Diŕ//..//", 0, 0); e =
"/tmp/";
TCMP (r, ==, e);
255 r = c.canonify_fspath (
"N°…Diŕ",
"N°…Fílė", 1, 1); e =
"/dev/";
TCMP (r, ==, e);
256 r = c.canonify_fspath (
"/N°…Diŕ",
"N°…Fílė", 1, 1); e =
"/";
TCMP (r, ==, e);
Class implementing a file system crawler.
ResourceS list_entries()
List all entries in the current folder.
Resource current_folder()
Return the current folder.
#define return_unless(cond,...)
Return silently if cond does not evaluate to true with return value ...
#define TEST_INTEGRITY(FUNC)
Register func as an integrity test.
T lexically_normal(T... args)
String cwd()
Return the current working directoy, including symlinks used in $PWD if available.
The Anklang C++ API namespace.
ResourceType type
Resource classification.
bool string_isupper(const String &str)
Check if all string characters are Unicode upper case characters.
int64_t int64
A 64-bit unsigned integer, use PRI*64 in format strings.
String string_toupper(const String &str)
Convert all string characters into Unicode upper case characters.
std::string decodefs(const std::string &utf8str)
Decode UTF-8 string back into file system path representation, extracting surrogate code points as by...
std::string anklang_runpath(RPath rpath, const String &segment)
Retrieve various resource paths at runtime.
String uri
Unique resource identifier.
std::string displayfs(const std::string &utf8str)
Convert UTF-8 encoded file system path into human readable display format, the conversion is lossy bu...
std::string String
Convenience alias for std::string.
bool string_endswith(const String &string, const String &fragment)
Returns whether string ends with fragment.
std::string encodefs(const std::string &fschars)
Encode a file system path consisting of bytes into UTF-8, using surrogate code points to store non UT...
Description of a resource, possibly nested.
T relative_path(T... args)
#define TCMP(a, cmp, b)
Compare a and b according to operator cmp, verbose on failiure.