17#define CDEBUG(...) Ase::debug ("crawler", __VA_ARGS__)
22ResourceCrawler::ResourceCrawler() :
23 folder (this,
"folder"),
24 entries (this,
"entries")
28FileCrawler::FileCrawler (
const String &cwd,
bool constraindir,
bool constrainfile) :
29 cwd_ (
"/"), constraindir_ (constraindir), constrainfile_ (constrainfile)
32 assign_ (encodefs (cwd),
false,
false);
37FileCrawler::list_entries ()
40 DIR *dir =
opendir (cwd_.c_str());
42 CDEBUG (
"%s: opendir('%s'): %s", __func__, cwd_,
strerror (
errno));
44 String cwdfile = cwd_ +
"/";
53 struct stat statbuf = { 0, };
54 if (0 !=
fstatat (
dirfd (dir), de->d_name, &statbuf, AT_NO_AUTOMOUNT))
56 is_dir = S_ISDIR (statbuf.st_mode);
57 is_reg = S_ISREG (statbuf.st_mode);
58 size = statbuf.st_size;
59 mtime = statbuf.st_mtim.tv_sec * 1000 + statbuf.st_mtim.tv_nsec / 1000000;
61 if (!is_reg && !is_dir)
64 .
type = is_dir ? ResourceType::FOLDER : ResourceType::FILE,
66 .uri =
encodefs (cwdfile + de->d_name) + (is_dir ?
"/" :
""),
68 r.
size = is_dir && size > 0 ? -size : size;
77FileCrawler::expand_fsdir (
const String &fsdir)
80 return Path::dir_terminate (cwd_);
83 String dir = Path::xdg_dir (fsdir);
85 return Path::dir_terminate (dir);
91FileCrawler::current_folder ()
94 .
type = ResourceType::FOLDER,
96 .uri =
encodefs (Path::dir_terminate (cwd_)),
98 struct stat statbuf = { 0, };
99 if (
lstat (cwd_.c_str(), &statbuf) == 0)
101 r.size = statbuf.st_size;
102 r.mtime = statbuf.st_mtim.tv_sec * 1000 + statbuf.st_mtim.tv_nsec / 1000000;
108FileCrawler::get_folder()
const
114FileCrawler::set_folder (
const Resource &newfolder)
116 assign_ (newfolder.
uri,
false);
120FileCrawler::get_entries()
const
126FileCrawler::set_entries (
const ResourceS &newentries)
133FileCrawler::assign_ (
const String &utf8path,
bool existingfile,
bool notify)
138 dir.
find (
"/") == dir.npos &&
144 dir = Path::xdg_dir (&dir[1]);
145 if (dir.
empty() || dir ==
"/")
149 Fs::path p = Path::expand_tilde (dir);
160 if (Path::check (p,
"d"))
161 cwd_ = Path::dir_terminate (p);
162 else if (Path::check (p,
"e")) {
165 }
else if (constraindir_) {
166 while (p.
string().size() > 1 &&
167 !Path::check (p,
"d")) {
168 filename = !existingfile || Path::check (p,
"e") ? p.
filename() :
"";
173 filename = !existingfile || Path::check (p,
"e") ? p.
filename() :
"";
177 while (cwd_.size() > 1 && cwd_.back() ==
'/')
178 cwd_.resize (cwd_.size() - 1);
183 emit_notify (
"current");
184 emit_notify (
"entries");
186 return { cwd_, filename };
191FileCrawler::canonify_fspath (
const String &fscwd,
const String &fsfragment,
bool constraindir,
bool constrainfile)
194 Fs::path p = Path::expand_tilde (fsfragment);
206 if (Path::check (p,
"d"))
207 return Path::dir_terminate (p);
208 if (Path::check (p,
"e"))
217 if (constrainfile && !Path::check (p,
"e"))
220 if (Path::check (p,
"d"))
221 return Path::dir_terminate (p);
227FileCrawler::canonify (
const String &utf8cwd,
const String &utf8fragment,
bool constraindir,
bool constrainfile)
248 FileCrawlerP cp = FileCrawler::make_shared (
"/dev",
true,
false);
251 r = c.canonify_fspath (
"",
"/dev/N°…Diŕ/N°…Fílė", 1, 1); e =
"/dev/";
TCMP (r, ==, e);
252 r = c.canonify_fspath (
".",
".", 1, 1); e =
"/dev/";
TCMP (r, ==, e);
253 r = c.canonify_fspath (
"",
"/dev/N°…Diŕ/null", 1, 1); e =
"/dev/null";
TCMP (r, ==, e);
254 r = c.canonify_fspath (
"",
"/tmp/N°…Diŕ/N°…Fílė", 1, 0); e =
"/tmp/N°…Fílė";
TCMP (r, ==, e);
255 r = c.canonify_fspath (
"",
"/tmp/N°…Diŕ//.//", 0, 0); e =
"/tmp/N°…Diŕ/";
TCMP (r, ==, e);
256 r = c.canonify_fspath (
"",
"/tmp/N°…Diŕ//..//", 0, 0); e =
"/tmp/";
TCMP (r, ==, e);
257 r = c.canonify_fspath (
"N°…Diŕ",
"N°…Fílė", 1, 1); e =
"/dev/";
TCMP (r, ==, e);
258 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...
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.