Simplify file-related operations portability by moving more code to the system-independant interface in pathut (esp.: dir reading)
This commit is contained in:
parent
3716ea3dac
commit
4b928ee57e
@ -2,48 +2,88 @@
|
|||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
static const char *thisprog;
|
|
||||||
|
|
||||||
static int op_flags;
|
static std::map<std::string, int> options {
|
||||||
#define OPT_MOINS 0x1
|
{"path_home", 0},
|
||||||
#define OPT_r 0x2
|
{"path_tildexpand", 0},
|
||||||
#define OPT_s 0x4
|
{"listdir", 0},
|
||||||
static char usage [] =
|
};
|
||||||
"pathut\n"
|
|
||||||
;
|
static const char *thisprog;
|
||||||
static void
|
static void Usage(void)
|
||||||
Usage(void)
|
|
||||||
{
|
{
|
||||||
fprintf(stderr, "%s: usage:\n%s", thisprog, usage);
|
string sopts;
|
||||||
|
for (const auto& opt: options) {
|
||||||
|
sopts += "--" + opt.first + "\n";
|
||||||
|
}
|
||||||
|
fprintf(stderr, "%s: usage: %s\n%s", thisprog, thisprog, sopts.c_str());
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, const char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
thisprog = argv[0];
|
thisprog = *argv;
|
||||||
argc--; argv++;
|
std::vector<struct option> long_options;
|
||||||
|
|
||||||
while (argc > 0 && **argv == '-') {
|
for (auto& entry : options) {
|
||||||
(*argv)++;
|
struct option opt;
|
||||||
if (!(**argv))
|
opt.name = entry.first.c_str();
|
||||||
/* Cas du "adb - core" */
|
opt.has_arg = 0;
|
||||||
Usage();
|
opt.flag = &entry.second;
|
||||||
while (**argv)
|
opt.val = 1;
|
||||||
switch (*(*argv)++) {
|
long_options.push_back(opt);
|
||||||
default: Usage(); break;
|
|
||||||
}
|
|
||||||
b1: argc--; argv++;
|
|
||||||
}
|
}
|
||||||
|
long_options.push_back({0, 0, 0, 0});
|
||||||
|
|
||||||
if (argc != 0)
|
while (getopt_long(argc, argv, "", &long_options[0], nullptr) != -1) {
|
||||||
|
}
|
||||||
|
if (options["path_home"]) {
|
||||||
|
if (optind != argc) {
|
||||||
|
cerr << "Usage: trsmallut --path_home\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
cout << "path_home() -> [" << path_home() << "]\n";
|
||||||
|
} else if (options["path_tildexpand"]) {
|
||||||
|
if (optind >= argc) {
|
||||||
|
cerr << "Usage: trsmallut --path_tildexpand <arg>\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
string s = argv[optind];
|
||||||
|
argc--;
|
||||||
|
if (optind != argc) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
cout << "path_tildexpand(" << s << ") -> [" << path_tildexpand(s) <<
|
||||||
|
"]\n";
|
||||||
|
} else if (options["listdir"]) {
|
||||||
|
if (optind >= argc) {
|
||||||
|
cerr << "Usage: trsmallut --listdir <arg>\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
std::string path = argv[optind];
|
||||||
|
argc--;
|
||||||
|
if (optind != argc) {
|
||||||
|
cerr << "Usage: trsmallut --listdir <arg>\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
std::string reason;
|
||||||
|
std::set<std::string> entries;
|
||||||
|
if (!listdir(path, reason, entries)) {
|
||||||
|
std::cerr<< "listdir(" << path << ") failed : " << reason << "\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
for (const auto& entry : entries) {
|
||||||
|
cout << entry << "\n";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
Usage();
|
Usage();
|
||||||
|
}
|
||||||
cout << "path_home() -> [" << path_home() << "]\n";
|
|
||||||
cout << "path_tildexpand(~) -> [" << path_tildexpand("~") << "]\n";
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,17 +19,10 @@
|
|||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
#include "msvc_dirent.h"
|
|
||||||
#else // !_MSC_VER
|
|
||||||
#include <dirent.h>
|
|
||||||
#endif // _MSC_VER
|
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fnmatch.h>
|
#include <fnmatch.h>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
@ -39,7 +32,6 @@
|
|||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "pathut.h"
|
#include "pathut.h"
|
||||||
#include "fstreewalk.h"
|
#include "fstreewalk.h"
|
||||||
#include "transcode.h"
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
@ -329,20 +321,6 @@ FsTreeWalker::Status FsTreeWalker::walk(const string& _top, FsTreeWalkerCB& cb)
|
|||||||
return FtwOk;
|
return FtwOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
#define DIRENT _wdirent
|
|
||||||
#define DIRHDL _WDIR
|
|
||||||
#define OPENDIR _wopendir
|
|
||||||
#define CLOSEDIR _wclosedir
|
|
||||||
#define READDIR _wreaddir
|
|
||||||
#else
|
|
||||||
#define DIRENT dirent
|
|
||||||
#define DIRHDL DIR
|
|
||||||
#define OPENDIR opendir
|
|
||||||
#define CLOSEDIR closedir
|
|
||||||
#define READDIR readdir
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Note that the 'norecurse' flag is handled as part of the directory read.
|
// Note that the 'norecurse' flag is handled as part of the directory read.
|
||||||
// This means that we always go into the top 'walk()' parameter if it is a
|
// This means that we always go into the top 'walk()' parameter if it is a
|
||||||
// directory, even if norecurse is set. Bug or Feature ?
|
// directory, even if norecurse is set. Bug or Feature ?
|
||||||
@ -391,20 +369,9 @@ FsTreeWalker::Status FsTreeWalker::iwalk(const string &top,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
SYSPATH(top, systop);
|
PathDirContents dc(top);
|
||||||
DIRHDL *d = OPENDIR(systop);
|
if (!dc.opendir()) {
|
||||||
if (nullptr == d) {
|
|
||||||
data->logsyserr("opendir", top);
|
data->logsyserr("opendir", top);
|
||||||
#ifdef _WIN32
|
|
||||||
int rc = GetLastError();
|
|
||||||
LOGERR("opendir failed: LastError " << rc << endl);
|
|
||||||
if (rc == ERROR_NETNAME_DELETED) {
|
|
||||||
// 64: share disconnected.
|
|
||||||
// Not too sure of the errno in this case.
|
|
||||||
// Make sure it's not one of the permissible ones
|
|
||||||
errno = ENODEV;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
switch (errno) {
|
switch (errno) {
|
||||||
case EPERM:
|
case EPERM:
|
||||||
case EACCES:
|
case EACCES:
|
||||||
@ -421,25 +388,20 @@ FsTreeWalker::Status FsTreeWalker::iwalk(const string &top,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct DIRENT *ent;
|
const struct PathDirContents::Entry *ent;
|
||||||
while (errno = 0, ((ent = READDIR(d)) != 0)) {
|
while (errno = 0, ((ent = dc.readdir()) != nullptr)) {
|
||||||
string fn;
|
string fn;
|
||||||
struct PathStat st;
|
struct PathStat st;
|
||||||
#ifdef _WIN32
|
const string& dname{ent->d_name};
|
||||||
string sdname;
|
if (dname.empty()) {
|
||||||
if (!wchartoutf8(ent->d_name, sdname)) {
|
// ???
|
||||||
LOGERR("wchartoutf8 failed in " << top << endl);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const char *dname = sdname.c_str();
|
|
||||||
#else
|
|
||||||
const char *dname = ent->d_name;
|
|
||||||
#endif
|
|
||||||
// Maybe skip dotfiles
|
// Maybe skip dotfiles
|
||||||
if ((data->options & FtwSkipDotFiles) && dname[0] == '.')
|
if ((data->options & FtwSkipDotFiles) && dname[0] == '.')
|
||||||
continue;
|
continue;
|
||||||
// Skip . and ..
|
// Skip . and ..
|
||||||
if (!strcmp(dname, ".") || !strcmp(dname, ".."))
|
if (dname == "." || dname == "..")
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Skipped file names match ?
|
// Skipped file names match ?
|
||||||
@ -530,8 +492,6 @@ FsTreeWalker::Status FsTreeWalker::iwalk(const string &top,
|
|||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (d)
|
|
||||||
CLOSEDIR(d);
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -68,9 +68,15 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
|
||||||
#ifndef PRETEND_USE
|
// Listing directories: we include the normal dirent.h on Unix-derived
|
||||||
#define PRETEND_USE(expr) ((void)(expr))
|
// systems, and on MinGW, where it comes with a supplemental wide char
|
||||||
#endif
|
// interface. When building with MSVC, we use our bundled msvc_dirent.h,
|
||||||
|
// which is equivalent to the one in MinGW
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#include "msvc_dirent.h"
|
||||||
|
#else // !_MSC_VER
|
||||||
|
#include <dirent.h>
|
||||||
|
#endif // _MSC_VER
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|
||||||
@ -115,14 +121,17 @@
|
|||||||
#define LSTAT _wstati64
|
#define LSTAT _wstati64
|
||||||
#define STATBUF _stati64
|
#define STATBUF _stati64
|
||||||
#define ACCESS _waccess
|
#define ACCESS _waccess
|
||||||
#define OPENDIR _wopendir
|
#define OPENDIR ::_wopendir
|
||||||
|
#define DIRHDL _WDIR
|
||||||
#define CLOSEDIR _wclosedir
|
#define CLOSEDIR _wclosedir
|
||||||
#define READDIR _wreaddir
|
#define READDIR ::_wreaddir
|
||||||
|
#define REWINDDIR ::_wrewinddir
|
||||||
#define DIRENT _wdirent
|
#define DIRENT _wdirent
|
||||||
#define DIRHDL _WDIR
|
#define DIRHDL _WDIR
|
||||||
#define MKDIR(a,b) _wmkdir(a)
|
#define MKDIR(a,b) _wmkdir(a)
|
||||||
#define OPEN ::_wopen
|
#define OPEN ::_wopen
|
||||||
#define UNLINK _wunlink
|
#define UNLINK _wunlink
|
||||||
|
#define RMDIR _wrmdir
|
||||||
#define CHDIR _wchdir
|
#define CHDIR _wchdir
|
||||||
|
|
||||||
#define ftruncate _chsize_s
|
#define ftruncate _chsize_s
|
||||||
@ -149,25 +158,22 @@
|
|||||||
#define LSTAT lstat
|
#define LSTAT lstat
|
||||||
#define STATBUF stat
|
#define STATBUF stat
|
||||||
#define ACCESS access
|
#define ACCESS access
|
||||||
#define OPENDIR opendir
|
#define OPENDIR ::opendir
|
||||||
|
#define DIRHDL DIR
|
||||||
#define CLOSEDIR closedir
|
#define CLOSEDIR closedir
|
||||||
#define READDIR readdir
|
#define READDIR ::readdir
|
||||||
|
#define REWINDDIR ::rewinddir
|
||||||
#define DIRENT dirent
|
#define DIRENT dirent
|
||||||
#define DIRHDL DIR
|
#define DIRHDL DIR
|
||||||
#define MKDIR(a,b) mkdir(a,b)
|
#define MKDIR(a,b) mkdir(a,b)
|
||||||
#define O_BINARY 0
|
#define O_BINARY 0
|
||||||
#define OPEN ::open
|
#define OPEN ::open
|
||||||
#define UNLINK ::unlink
|
#define UNLINK ::unlink
|
||||||
|
#define RMDIR ::rmdir
|
||||||
#define CHDIR ::chdir
|
#define CHDIR ::chdir
|
||||||
|
|
||||||
#endif /* !_WIN32 */
|
#endif /* !_WIN32 */
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
#include <msvc_dirent.h>
|
|
||||||
#else // !_MSC_VER
|
|
||||||
#include <dirent.h>
|
|
||||||
#endif // _MSC_VER
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
#ifndef PATHUT_SSIZE_T
|
#ifndef PATHUT_SSIZE_T
|
||||||
@ -645,28 +651,6 @@ string path_home()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// The default place to store the default config and other stuff (e.g webqueue)
|
|
||||||
string path_homedata()
|
|
||||||
{
|
|
||||||
#ifdef _WIN32
|
|
||||||
wchar_t *cp;
|
|
||||||
SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, nullptr, &cp);
|
|
||||||
string dir;
|
|
||||||
if (cp != 0) {
|
|
||||||
wchartoutf8(cp, dir);
|
|
||||||
}
|
|
||||||
if (!dir.empty()) {
|
|
||||||
dir = path_canon(dir);
|
|
||||||
} else {
|
|
||||||
dir = path_cat(path_home(), "AppData/Local/");
|
|
||||||
}
|
|
||||||
return dir;
|
|
||||||
#else
|
|
||||||
// We should use an xdg-conforming location, but, history...
|
|
||||||
return path_home();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
string path_tildexpand(const string& s)
|
string path_tildexpand(const string& s)
|
||||||
{
|
{
|
||||||
if (s.empty() || s[0] != '~') {
|
if (s.empty() || s[0] != '~') {
|
||||||
@ -889,6 +873,12 @@ bool path_unlink(const std::string& path)
|
|||||||
return UNLINK(syspath) == 0;
|
return UNLINK(syspath) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool path_rmdir(const std::string& path)
|
||||||
|
{
|
||||||
|
SYSPATH(path, syspath);
|
||||||
|
return RMDIR(syspath) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
#if !defined(__GNUC__) || __GNUC__ > 4 || defined(__clang__)
|
#if !defined(__GNUC__) || __GNUC__ > 4 || defined(__clang__)
|
||||||
// Not sure what g++ version supports fstream assignment but 4.9
|
// Not sure what g++ version supports fstream assignment but 4.9
|
||||||
// (jessie) certainly does not
|
// (jessie) certainly does not
|
||||||
@ -1032,6 +1022,11 @@ bool path_readable(const string& path)
|
|||||||
SYSPATH(path, syspath);
|
SYSPATH(path, syspath);
|
||||||
return ACCESS(syspath, R_OK) == 0;
|
return ACCESS(syspath, R_OK) == 0;
|
||||||
}
|
}
|
||||||
|
bool path_access(const std::string& path, int mode)
|
||||||
|
{
|
||||||
|
SYSPATH(path, syspath);
|
||||||
|
return ACCESS(syspath, mode) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* There is a lot of vagueness about what should be percent-encoded or
|
/* There is a lot of vagueness about what should be percent-encoded or
|
||||||
* not in a file:// url. The constraint that we have is that we may use
|
* not in a file:// url. The constraint that we have is that we may use
|
||||||
@ -1296,56 +1291,105 @@ ParsedUri::ParsedUri(std::string uri)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Directory reading interface. UTF-8 on Windows.
|
||||||
|
class PathDirContents::Internal {
|
||||||
|
public:
|
||||||
|
~Internal() {
|
||||||
|
if (dirhdl) {
|
||||||
|
CLOSEDIR(dirhdl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DIRHDL *dirhdl{nullptr};
|
||||||
|
PathDirContents::Entry entry;
|
||||||
|
std::string dirpath;
|
||||||
|
};
|
||||||
|
|
||||||
|
PathDirContents::PathDirContents(const std::string& dirpath)
|
||||||
|
{
|
||||||
|
m = new Internal;
|
||||||
|
m->dirpath = dirpath;
|
||||||
|
}
|
||||||
|
|
||||||
|
PathDirContents::~PathDirContents()
|
||||||
|
{
|
||||||
|
delete m;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PathDirContents::opendir()
|
||||||
|
{
|
||||||
|
if (m->dirhdl) {
|
||||||
|
CLOSEDIR(m->dirhdl);
|
||||||
|
m->dirhdl = nullptr;
|
||||||
|
}
|
||||||
|
SYSPATH(m->dirpath, sysdir);
|
||||||
|
m->dirhdl = OPENDIR(sysdir);
|
||||||
|
#ifdef _WIN32
|
||||||
|
int rc = GetLastError();
|
||||||
|
LOGERR("opendir failed: LastError " << rc << endl);
|
||||||
|
if (rc == ERROR_NETNAME_DELETED) {
|
||||||
|
// 64: share disconnected.
|
||||||
|
// Not too sure of the errno in this case.
|
||||||
|
// Make sure it's not one of the permissible ones
|
||||||
|
errno = ENODEV;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return ! (nullptr == m->dirhdl);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PathDirContents::rewinddir()
|
||||||
|
{
|
||||||
|
REWINDDIR(m->dirhdl);
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct PathDirContents::Entry* PathDirContents::readdir()
|
||||||
|
{
|
||||||
|
struct DIRENT *ent = READDIR(m->dirhdl);
|
||||||
|
if (nullptr == ent) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
#ifdef _WIN32
|
||||||
|
string sdname;
|
||||||
|
if (!wchartoutf8(ent->d_name, sdname)) {
|
||||||
|
LOGERR("wchartoutf8 failed for " << ent->d_name << endl);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
const char *dname = sdname.c_str();
|
||||||
|
#else
|
||||||
|
const char *dname = ent->d_name;
|
||||||
|
#endif
|
||||||
|
m->entry.d_name = dname;
|
||||||
|
return &m->entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool listdir(const string& dir, string& reason, set<string>& entries)
|
bool listdir(const string& dir, string& reason, set<string>& entries)
|
||||||
{
|
{
|
||||||
struct STATBUF st;
|
|
||||||
int statret;
|
|
||||||
ostringstream msg;
|
ostringstream msg;
|
||||||
DIRHDL *d = 0;
|
PathDirContents dc(dir);
|
||||||
|
|
||||||
SYSPATH(dir, sysdir);
|
if (!path_isdir(dir)) {
|
||||||
|
|
||||||
statret = LSTAT(sysdir, &st);
|
|
||||||
if (statret == -1) {
|
|
||||||
msg << "listdir: cant stat " << dir << " errno " << errno;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
if (!S_ISDIR(st.st_mode)) {
|
|
||||||
msg << "listdir: " << dir << " not a directory";
|
msg << "listdir: " << dir << " not a directory";
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (ACCESS(sysdir, R_OK) < 0) {
|
if (!path_access(dir, R_OK)) {
|
||||||
msg << "listdir: no read access to " << dir;
|
msg << "listdir: no read access to " << dir;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
d = OPENDIR(sysdir);
|
if (!dc.opendir()) {
|
||||||
if (d == 0) {
|
|
||||||
msg << "listdir: cant opendir " << dir << ", errno " << errno;
|
msg << "listdir: cant opendir " << dir << ", errno " << errno;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
const struct PathDirContents::Entry *ent;
|
||||||
struct DIRENT *ent;
|
while ((ent = dc.readdir()) != 0) {
|
||||||
while ((ent = READDIR(d)) != 0) {
|
if (ent->d_name == "." || ent->d_name == "..") {
|
||||||
#ifdef _WIN32
|
|
||||||
string sdname;
|
|
||||||
if (!wchartoutf8(ent->d_name, sdname)) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const char *dname = sdname.c_str();
|
entries.insert(ent->d_name);
|
||||||
#else
|
|
||||||
const char *dname = ent->d_name;
|
|
||||||
#endif
|
|
||||||
if (!strcmp(dname, ".") || !strcmp(dname, "..")) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
entries.insert(dname);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (d) {
|
|
||||||
CLOSEDIR(d);
|
|
||||||
}
|
|
||||||
reason = msg.str();
|
reason = msg.str();
|
||||||
if (reason.empty()) {
|
if (reason.empty()) {
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@ -39,6 +39,21 @@ extern std::string path_basename(const std::string& s,
|
|||||||
extern std::string path_suffix(const std::string& s);
|
extern std::string path_suffix(const std::string& s);
|
||||||
/// Get the father directory
|
/// Get the father directory
|
||||||
extern std::string path_getfather(const std::string& s);
|
extern std::string path_getfather(const std::string& s);
|
||||||
|
/// Test if path is absolute
|
||||||
|
extern bool path_isabsolute(const std::string& s);
|
||||||
|
/// Test if path is root (x:/). root is defined by root/.. == root
|
||||||
|
extern bool path_isroot(const std::string& p);
|
||||||
|
/// Test if sub is a subdirectory of top. This is a textual test,
|
||||||
|
/// links not allowed
|
||||||
|
extern bool path_isdesc(const std::string& top, const std::string& sub);
|
||||||
|
|
||||||
|
/// Clean up path by removing duplicated / and resolving ../ + make it absolute
|
||||||
|
extern std::string path_canon(const std::string& s, const std::string *cwd = 0);
|
||||||
|
|
||||||
|
/// Check that path refers to same file. Uses dev/ino on Linux,
|
||||||
|
/// textual comparison on Windows.
|
||||||
|
bool path_samefile(const std::string& p1, const std::string& p2);
|
||||||
|
|
||||||
/// Get the current user's home directory
|
/// Get the current user's home directory
|
||||||
extern std::string path_home();
|
extern std::string path_home();
|
||||||
/// Expand ~ at the beginning of std::string
|
/// Expand ~ at the beginning of std::string
|
||||||
@ -46,26 +61,6 @@ extern std::string path_tildexpand(const std::string& s);
|
|||||||
/// Use getcwd() to make absolute path if needed. Beware: ***this can fail***
|
/// Use getcwd() to make absolute path if needed. Beware: ***this can fail***
|
||||||
/// we return an empty path in this case.
|
/// we return an empty path in this case.
|
||||||
extern std::string path_absolute(const std::string& s);
|
extern std::string path_absolute(const std::string& s);
|
||||||
/// Clean up path by removing duplicated / and resolving ../ + make it absolute
|
|
||||||
extern std::string path_canon(const std::string& s, const std::string *cwd = 0);
|
|
||||||
/// Use glob(3) to return the file names matching pattern inside dir
|
|
||||||
extern std::vector<std::string> path_dirglob(const std::string& dir,
|
|
||||||
const std::string pattern);
|
|
||||||
/// Encode according to rfc 1738
|
|
||||||
extern std::string url_encode(const std::string& url,
|
|
||||||
std::string::size_type offs = 0);
|
|
||||||
extern std::string url_decode(const std::string& encoded);
|
|
||||||
//// Convert to file path if url is like file://. This modifies the
|
|
||||||
//// input (and returns a copy for convenience)
|
|
||||||
extern std::string fileurltolocalpath(std::string url);
|
|
||||||
/// Test for file:/// url
|
|
||||||
extern bool urlisfileurl(const std::string& url);
|
|
||||||
///
|
|
||||||
extern std::string url_parentfolder(const std::string& url);
|
|
||||||
|
|
||||||
/// Return the host+path part of an url. This is not a general
|
|
||||||
/// routine, it does the right thing only in the recoll context
|
|
||||||
extern std::string url_gpath(const std::string& url);
|
|
||||||
|
|
||||||
/// Stat parameter and check if it's a directory
|
/// Stat parameter and check if it's a directory
|
||||||
extern bool path_isdir(const std::string& path, bool follow = false);
|
extern bool path_isdir(const std::string& path, bool follow = false);
|
||||||
@ -75,7 +70,30 @@ extern bool path_isfile(const std::string& path, bool follow = false);
|
|||||||
/// Retrieve file size
|
/// Retrieve file size
|
||||||
extern long long path_filesize(const std::string& path);
|
extern long long path_filesize(const std::string& path);
|
||||||
|
|
||||||
bool path_samefile(const std::string& p1, const std::string& p2);
|
/// Check that path is traversable and last element exists
|
||||||
|
/// Returns true if last elt could be checked to exist. False may mean that
|
||||||
|
/// the file/dir does not exist or that an error occurred.
|
||||||
|
bool path_exists(const std::string& path);
|
||||||
|
/// Same but must be readable
|
||||||
|
bool path_readable(const std::string& path);
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
# ifndef R_OK
|
||||||
|
# define R_OK 4
|
||||||
|
# endif
|
||||||
|
# ifndef W_OK
|
||||||
|
# define W_OK 2
|
||||||
|
# endif
|
||||||
|
# ifndef X_OK
|
||||||
|
// Not useful/supported on Windows. Define as R_OK
|
||||||
|
# define X_OK R_OK
|
||||||
|
# endif
|
||||||
|
# ifndef F_OK
|
||||||
|
# define F_OK 0
|
||||||
|
# endif
|
||||||
|
#endif /* _WIN32 */
|
||||||
|
/// access() or _waccess()
|
||||||
|
bool path_access(const std::string& path, int mode);
|
||||||
|
|
||||||
/// Retrieve essential file attributes. This is used rather than a
|
/// Retrieve essential file attributes. This is used rather than a
|
||||||
/// bare stat() to ensure consistent use of the time fields (on
|
/// bare stat() to ensure consistent use of the time fields (on
|
||||||
@ -100,12 +118,6 @@ struct PathStat {
|
|||||||
extern int path_fileprops(const std::string path, struct PathStat *stp,
|
extern int path_fileprops(const std::string path, struct PathStat *stp,
|
||||||
bool follow = true);
|
bool follow = true);
|
||||||
|
|
||||||
/// Check that path is traversable and last element exists
|
|
||||||
/// Returns true if last elt could be checked to exist. False may mean that
|
|
||||||
/// the file/dir does not exist or that an error occurred.
|
|
||||||
extern bool path_exists(const std::string& path);
|
|
||||||
/// Same but must be readable
|
|
||||||
extern bool path_readable(const std::string& path);
|
|
||||||
|
|
||||||
/// Return separator for PATH environment variable
|
/// Return separator for PATH environment variable
|
||||||
extern std::string path_PATHsep();
|
extern std::string path_PATHsep();
|
||||||
@ -121,6 +133,24 @@ extern bool utf8towchar(const std::string& in, wchar_t *out, size_t obytescap);
|
|||||||
#define SYSPATH(PATH, SPATH) const char *SPATH = PATH.c_str()
|
#define SYSPATH(PATH, SPATH) const char *SPATH = PATH.c_str()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/// Directory reading interface. UTF-8 on Windows.
|
||||||
|
class PathDirContents {
|
||||||
|
public:
|
||||||
|
PathDirContents(const std::string& dirpath);
|
||||||
|
~PathDirContents();
|
||||||
|
|
||||||
|
bool opendir();
|
||||||
|
struct Entry {
|
||||||
|
std::string d_name;
|
||||||
|
};
|
||||||
|
const struct Entry* readdir();
|
||||||
|
void rewinddir();
|
||||||
|
|
||||||
|
private:
|
||||||
|
class Internal;
|
||||||
|
Internal *m{nullptr};
|
||||||
|
};
|
||||||
|
|
||||||
/// Dump directory
|
/// Dump directory
|
||||||
extern bool listdir(const std::string& dir, std::string& reason,
|
extern bool listdir(const std::string& dir, std::string& reason,
|
||||||
std::set<std::string>& entries);
|
std::set<std::string>& entries);
|
||||||
@ -136,9 +166,10 @@ bool fsocc(const std::string& path, int *pc, long long *avmbs = 0);
|
|||||||
extern bool path_makepath(const std::string& path, int mode);
|
extern bool path_makepath(const std::string& path, int mode);
|
||||||
|
|
||||||
///
|
///
|
||||||
extern bool path_chdir(const std::string& path);
|
bool path_chdir(const std::string& path);
|
||||||
extern std::string path_cwd();
|
std::string path_cwd();
|
||||||
extern bool path_unlink(const std::string& path);
|
bool path_unlink(const std::string& path);
|
||||||
|
bool path_rmdir(const std::string& path);
|
||||||
|
|
||||||
/* Open file, trying to do the right thing with non-ASCII paths on
|
/* Open file, trying to do the right thing with non-ASCII paths on
|
||||||
* Windows, where it only works with MSVC at the moment if the path is
|
* Windows, where it only works with MSVC at the moment if the path is
|
||||||
@ -151,20 +182,23 @@ extern bool path_unlink(const std::string& path);
|
|||||||
* @param path an utf-8 file path.
|
* @param path an utf-8 file path.
|
||||||
* @param mode is an std::fstream mode (ios::in etc.) */
|
* @param mode is an std::fstream mode (ios::in etc.) */
|
||||||
extern std::fstream path_open(const std::string& path, int mode);
|
extern std::fstream path_open(const std::string& path, int mode);
|
||||||
extern bool path_open(const std::string& path, int mode, std::fstream& outstream);
|
extern bool path_open(
|
||||||
|
const std::string& path, int mode, std::fstream& outstream);
|
||||||
/// Where we create the user data subdirs
|
|
||||||
extern std::string path_homedata();
|
|
||||||
/// Test if path is absolute
|
|
||||||
extern bool path_isabsolute(const std::string& s);
|
|
||||||
|
|
||||||
/// Test if path is root (x:/). root is defined by root/.. == root
|
|
||||||
extern bool path_isroot(const std::string& p);
|
|
||||||
|
|
||||||
/// Test if sub is a subdirectory of top. This is a textual test,
|
|
||||||
/// links not allowed
|
|
||||||
extern bool path_isdesc(const std::string& top, const std::string& sub);
|
|
||||||
|
|
||||||
|
/// Encode according to rfc 1738
|
||||||
|
extern std::string url_encode(const std::string& url,
|
||||||
|
std::string::size_type offs = 0);
|
||||||
|
extern std::string url_decode(const std::string& encoded);
|
||||||
|
//// Convert to file path if url is like file://. This modifies the
|
||||||
|
//// input (and returns a copy for convenience)
|
||||||
|
extern std::string fileurltolocalpath(std::string url);
|
||||||
|
/// Test for file:/// url
|
||||||
|
extern bool urlisfileurl(const std::string& url);
|
||||||
|
///
|
||||||
|
extern std::string url_parentfolder(const std::string& url);
|
||||||
|
/// Return the host+path part of an url. This is not a general
|
||||||
|
/// routine, it does the right thing only in the recoll context
|
||||||
|
extern std::string url_gpath(const std::string& url);
|
||||||
/// Turn absolute path into file:// url
|
/// Turn absolute path into file:// url
|
||||||
extern std::string path_pathtofileurl(const std::string& path);
|
extern std::string path_pathtofileurl(const std::string& path);
|
||||||
|
|
||||||
|
|||||||
@ -194,6 +194,28 @@ static bool path_gettempfilename(string& filename, string& reason)
|
|||||||
}
|
}
|
||||||
#endif // posix
|
#endif // posix
|
||||||
|
|
||||||
|
// The default place to store the default config and other stuff (e.g webqueue)
|
||||||
|
string path_homedata()
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
wchar_t *cp;
|
||||||
|
SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, nullptr, &cp);
|
||||||
|
string dir;
|
||||||
|
if (cp != 0) {
|
||||||
|
wchartoutf8(cp, dir);
|
||||||
|
}
|
||||||
|
if (!dir.empty()) {
|
||||||
|
dir = path_canon(dir);
|
||||||
|
} else {
|
||||||
|
dir = path_cat(path_home(), "AppData/Local/");
|
||||||
|
}
|
||||||
|
return dir;
|
||||||
|
#else
|
||||||
|
// We should use an xdg-conforming location, but, history...
|
||||||
|
return path_home();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
// Check if path is either non-existing or an empty directory.
|
// Check if path is either non-existing or an empty directory.
|
||||||
bool path_empty(const string& path)
|
bool path_empty(const string& path)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -33,6 +33,9 @@ extern std::string path_defaultrecollconfsubdir();
|
|||||||
// Check if path is either non-existing or an empty directory.
|
// Check if path is either non-existing or an empty directory.
|
||||||
extern bool path_empty(const std::string& path);
|
extern bool path_empty(const std::string& path);
|
||||||
|
|
||||||
|
/// Where we create the user data subdirs
|
||||||
|
extern std::string path_homedata();
|
||||||
|
|
||||||
/// e.g. /usr/share/recoll. Depends on OS and config
|
/// e.g. /usr/share/recoll. Depends on OS and config
|
||||||
extern const std::string& path_pkgdatadir();
|
extern const std::string& path_pkgdatadir();
|
||||||
|
|
||||||
|
|||||||
@ -41,6 +41,9 @@ void smallut_init_mt();
|
|||||||
#ifndef deleteZ
|
#ifndef deleteZ
|
||||||
#define deleteZ(X) {delete X;X = 0;}
|
#define deleteZ(X) {delete X;X = 0;}
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef PRETEND_USE
|
||||||
|
#define PRETEND_USE(var) ((void)(var))
|
||||||
|
#endif
|
||||||
#endif /* SMALLUT_DISABLE_MACROS */
|
#endif /* SMALLUT_DISABLE_MACROS */
|
||||||
|
|
||||||
// Case-insensitive compare. ASCII ONLY !
|
// Case-insensitive compare. ASCII ONLY !
|
||||||
|
|||||||
@ -19,140 +19,72 @@
|
|||||||
|
|
||||||
#include "wipedir.h"
|
#include "wipedir.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
#include <cstring>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "pathut.h"
|
#include "pathut.h"
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
#include "msvc_dirent.h"
|
|
||||||
#else // !_MSC_VER
|
|
||||||
#include <dirent.h>
|
|
||||||
#endif // _MSC_VER
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include "safefcntl.h"
|
# include "safeunistd.h"
|
||||||
#include "safeunistd.h"
|
|
||||||
#include "safewindows.h"
|
|
||||||
#include "safesysstat.h"
|
|
||||||
#include "transcode.h"
|
|
||||||
|
|
||||||
#define STAT _wstati64
|
|
||||||
#define LSTAT _wstati64
|
|
||||||
#define STATBUF _stati64
|
|
||||||
#define ACCESS _waccess
|
|
||||||
#define OPENDIR _wopendir
|
|
||||||
#define CLOSEDIR _wclosedir
|
|
||||||
#define READDIR _wreaddir
|
|
||||||
#define DIRENT _wdirent
|
|
||||||
#define DIRHDL _WDIR
|
|
||||||
#define UNLINK _wunlink
|
|
||||||
#define RMDIR _wrmdir
|
|
||||||
|
|
||||||
#else // Not windows ->
|
#else // Not windows ->
|
||||||
|
# include <unistd.h>
|
||||||
#include <fcntl.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
|
|
||||||
#define STAT stat
|
|
||||||
#define LSTAT lstat
|
|
||||||
#define STATBUF stat
|
|
||||||
#define ACCESS access
|
|
||||||
#define OPENDIR opendir
|
|
||||||
#define CLOSEDIR closedir
|
|
||||||
#define READDIR readdir
|
|
||||||
#define DIRENT dirent
|
|
||||||
#define DIRHDL DIR
|
|
||||||
#define UNLINK unlink
|
|
||||||
#define RMDIR rmdir
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
int wipedir(const string& dir, bool selfalso, bool recurse)
|
int wipedir(const std::string& dir, bool selfalso, bool recurse)
|
||||||
{
|
{
|
||||||
struct STATBUF st;
|
|
||||||
int statret;
|
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
|
|
||||||
SYSPATH(dir, sysdir);
|
if (!path_isdir(dir)) {
|
||||||
statret = LSTAT(sysdir, &st);
|
LOGERR("wipedir: " << dir << " not a directory\n");
|
||||||
if (statret == -1) {
|
return -1;
|
||||||
LOGSYSERR("wipedir", "stat", dir);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (!S_ISDIR(st.st_mode)) {
|
|
||||||
LOGERR("wipedir: " << dir << " not a directory\n");
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ACCESS(sysdir, R_OK|W_OK|X_OK) < 0) {
|
if (!path_access(dir, R_OK|W_OK|X_OK)) {
|
||||||
LOGSYSERR("wipedir", "access", dir);
|
LOGSYSERR("wipedir", "access", dir);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
DIRHDL *d = OPENDIR(sysdir);
|
PathDirContents dc(dir);
|
||||||
if (d == 0) {
|
if (!dc.opendir()) {
|
||||||
LOGSYSERR("wipedir", "opendir", dir);
|
LOGSYSERR("wipedir", "opendir", dir);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
int remaining = 0;
|
int remaining = 0;
|
||||||
struct DIRENT *ent;
|
const struct PathDirContents::Entry *ent;
|
||||||
while ((ent = READDIR(d)) != 0) {
|
while ((ent = dc.readdir()) != 0) {
|
||||||
#ifdef _WIN32
|
const std::string& dname{ent->d_name};
|
||||||
string sdname;
|
if (dname == "." || dname == "..")
|
||||||
if (!wchartoutf8(ent->d_name, sdname)) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
const char *dname = sdname.c_str();
|
|
||||||
#else
|
|
||||||
const char *dname = ent->d_name;
|
|
||||||
#endif
|
|
||||||
if (!strcmp(dname, ".") || !strcmp(dname, ".."))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
string fn = path_cat(dir, dname);
|
std::string fn = path_cat(dir, dname);
|
||||||
|
|
||||||
SYSPATH(fn, sysfn);
|
if (path_isdir(fn)) {
|
||||||
struct STATBUF st;
|
if (recurse) {
|
||||||
int statret = LSTAT(sysfn, &st);
|
int rr = wipedir(fn, true, true);
|
||||||
if (statret == -1) {
|
if (rr == -1)
|
||||||
LOGSYSERR("wipedir", "stat", fn);
|
goto out;
|
||||||
goto out;
|
else
|
||||||
}
|
remaining += rr;
|
||||||
if (S_ISDIR(st.st_mode)) {
|
} else {
|
||||||
if (recurse) {
|
remaining++;
|
||||||
int rr = wipedir(fn, true, true);
|
}
|
||||||
if (rr == -1)
|
|
||||||
goto out;
|
|
||||||
else
|
|
||||||
remaining += rr;
|
|
||||||
} else {
|
} else {
|
||||||
remaining++;
|
if (!path_unlink(fn)) {
|
||||||
|
LOGSYSERR("wipedir", "unlink", fn);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if (UNLINK(sysfn) < 0) {
|
|
||||||
LOGSYSERR("wipedir", "unlink", fn);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = remaining;
|
ret = remaining;
|
||||||
if (selfalso && ret == 0) {
|
if (selfalso && ret == 0) {
|
||||||
if (RMDIR(sysdir) < 0) {
|
if (!path_rmdir(dir)) {
|
||||||
LOGSYSERR("wipedir", "rmdir", dir);
|
LOGSYSERR("wipedir", "rmdir", dir);
|
||||||
ret = -1;
|
ret = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (d)
|
|
||||||
CLOSEDIR(d);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user