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 <stdlib.h>
|
||||
#include <getopt.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
|
||||
using namespace std;
|
||||
static const char *thisprog;
|
||||
|
||||
static int op_flags;
|
||||
#define OPT_MOINS 0x1
|
||||
#define OPT_r 0x2
|
||||
#define OPT_s 0x4
|
||||
static char usage [] =
|
||||
"pathut\n"
|
||||
;
|
||||
static void
|
||||
Usage(void)
|
||||
static std::map<std::string, int> options {
|
||||
{"path_home", 0},
|
||||
{"path_tildexpand", 0},
|
||||
{"listdir", 0},
|
||||
};
|
||||
|
||||
static const char *thisprog;
|
||||
static 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);
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv)
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
thisprog = argv[0];
|
||||
argc--; argv++;
|
||||
thisprog = *argv;
|
||||
std::vector<struct option> long_options;
|
||||
|
||||
while (argc > 0 && **argv == '-') {
|
||||
(*argv)++;
|
||||
if (!(**argv))
|
||||
/* Cas du "adb - core" */
|
||||
Usage();
|
||||
while (**argv)
|
||||
switch (*(*argv)++) {
|
||||
default: Usage(); break;
|
||||
}
|
||||
b1: argc--; argv++;
|
||||
for (auto& entry : options) {
|
||||
struct option opt;
|
||||
opt.name = entry.first.c_str();
|
||||
opt.has_arg = 0;
|
||||
opt.flag = &entry.second;
|
||||
opt.val = 1;
|
||||
long_options.push_back(opt);
|
||||
}
|
||||
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();
|
||||
|
||||
cout << "path_home() -> [" << path_home() << "]\n";
|
||||
cout << "path_tildexpand(~) -> [" << path_tildexpand("~") << "]\n";
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -19,17 +19,10 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include "msvc_dirent.h"
|
||||
#else // !_MSC_VER
|
||||
#include <dirent.h>
|
||||
#endif // _MSC_VER
|
||||
|
||||
#include <errno.h>
|
||||
#include <fnmatch.h>
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
@ -39,7 +32,6 @@
|
||||
#include "log.h"
|
||||
#include "pathut.h"
|
||||
#include "fstreewalk.h"
|
||||
#include "transcode.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
@ -329,20 +321,6 @@ FsTreeWalker::Status FsTreeWalker::walk(const string& _top, FsTreeWalkerCB& cb)
|
||||
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.
|
||||
// This means that we always go into the top 'walk()' parameter if it is a
|
||||
// directory, even if norecurse is set. Bug or Feature ?
|
||||
@ -391,20 +369,9 @@ FsTreeWalker::Status FsTreeWalker::iwalk(const string &top,
|
||||
}
|
||||
#endif
|
||||
|
||||
SYSPATH(top, systop);
|
||||
DIRHDL *d = OPENDIR(systop);
|
||||
if (nullptr == d) {
|
||||
PathDirContents dc(top);
|
||||
if (!dc.opendir()) {
|
||||
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) {
|
||||
case EPERM:
|
||||
case EACCES:
|
||||
@ -421,25 +388,20 @@ FsTreeWalker::Status FsTreeWalker::iwalk(const string &top,
|
||||
}
|
||||
}
|
||||
|
||||
struct DIRENT *ent;
|
||||
while (errno = 0, ((ent = READDIR(d)) != 0)) {
|
||||
const struct PathDirContents::Entry *ent;
|
||||
while (errno = 0, ((ent = dc.readdir()) != nullptr)) {
|
||||
string fn;
|
||||
struct PathStat st;
|
||||
#ifdef _WIN32
|
||||
string sdname;
|
||||
if (!wchartoutf8(ent->d_name, sdname)) {
|
||||
LOGERR("wchartoutf8 failed in " << top << endl);
|
||||
const string& dname{ent->d_name};
|
||||
if (dname.empty()) {
|
||||
// ???
|
||||
continue;
|
||||
}
|
||||
const char *dname = sdname.c_str();
|
||||
#else
|
||||
const char *dname = ent->d_name;
|
||||
#endif
|
||||
// Maybe skip dotfiles
|
||||
if ((data->options & FtwSkipDotFiles) && dname[0] == '.')
|
||||
continue;
|
||||
// Skip . and ..
|
||||
if (!strcmp(dname, ".") || !strcmp(dname, ".."))
|
||||
if (dname == "." || dname == "..")
|
||||
continue;
|
||||
|
||||
// Skipped file names match ?
|
||||
@ -530,8 +492,6 @@ FsTreeWalker::Status FsTreeWalker::iwalk(const string &top,
|
||||
}
|
||||
|
||||
out:
|
||||
if (d)
|
||||
CLOSEDIR(d);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
@ -68,9 +68,15 @@
|
||||
#include <vector>
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifndef PRETEND_USE
|
||||
#define PRETEND_USE(expr) ((void)(expr))
|
||||
#endif
|
||||
// Listing directories: we include the normal dirent.h on Unix-derived
|
||||
// systems, and on MinGW, where it comes with a supplemental wide char
|
||||
// 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
|
||||
|
||||
@ -115,14 +121,17 @@
|
||||
#define LSTAT _wstati64
|
||||
#define STATBUF _stati64
|
||||
#define ACCESS _waccess
|
||||
#define OPENDIR _wopendir
|
||||
#define OPENDIR ::_wopendir
|
||||
#define DIRHDL _WDIR
|
||||
#define CLOSEDIR _wclosedir
|
||||
#define READDIR _wreaddir
|
||||
#define READDIR ::_wreaddir
|
||||
#define REWINDDIR ::_wrewinddir
|
||||
#define DIRENT _wdirent
|
||||
#define DIRHDL _WDIR
|
||||
#define MKDIR(a,b) _wmkdir(a)
|
||||
#define OPEN ::_wopen
|
||||
#define UNLINK _wunlink
|
||||
#define RMDIR _wrmdir
|
||||
#define CHDIR _wchdir
|
||||
|
||||
#define ftruncate _chsize_s
|
||||
@ -149,25 +158,22 @@
|
||||
#define LSTAT lstat
|
||||
#define STATBUF stat
|
||||
#define ACCESS access
|
||||
#define OPENDIR opendir
|
||||
#define OPENDIR ::opendir
|
||||
#define DIRHDL DIR
|
||||
#define CLOSEDIR closedir
|
||||
#define READDIR readdir
|
||||
#define READDIR ::readdir
|
||||
#define REWINDDIR ::rewinddir
|
||||
#define DIRENT dirent
|
||||
#define DIRHDL DIR
|
||||
#define MKDIR(a,b) mkdir(a,b)
|
||||
#define O_BINARY 0
|
||||
#define OPEN ::open
|
||||
#define UNLINK ::unlink
|
||||
#define RMDIR ::rmdir
|
||||
#define CHDIR ::chdir
|
||||
|
||||
#endif /* !_WIN32 */
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <msvc_dirent.h>
|
||||
#else // !_MSC_VER
|
||||
#include <dirent.h>
|
||||
#endif // _MSC_VER
|
||||
|
||||
using namespace std;
|
||||
|
||||
#ifndef PATHUT_SSIZE_T
|
||||
@ -645,28 +651,6 @@ string path_home()
|
||||
#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)
|
||||
{
|
||||
if (s.empty() || s[0] != '~') {
|
||||
@ -889,6 +873,12 @@ bool path_unlink(const std::string& path)
|
||||
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__)
|
||||
// Not sure what g++ version supports fstream assignment but 4.9
|
||||
// (jessie) certainly does not
|
||||
@ -1032,6 +1022,11 @@ bool path_readable(const string& path)
|
||||
SYSPATH(path, syspath);
|
||||
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
|
||||
* 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)
|
||||
{
|
||||
struct STATBUF st;
|
||||
int statret;
|
||||
ostringstream msg;
|
||||
DIRHDL *d = 0;
|
||||
|
||||
SYSPATH(dir, sysdir);
|
||||
|
||||
statret = LSTAT(sysdir, &st);
|
||||
if (statret == -1) {
|
||||
msg << "listdir: cant stat " << dir << " errno " << errno;
|
||||
goto out;
|
||||
}
|
||||
if (!S_ISDIR(st.st_mode)) {
|
||||
PathDirContents dc(dir);
|
||||
|
||||
if (!path_isdir(dir)) {
|
||||
msg << "listdir: " << dir << " not a directory";
|
||||
goto out;
|
||||
}
|
||||
if (ACCESS(sysdir, R_OK) < 0) {
|
||||
if (!path_access(dir, R_OK)) {
|
||||
msg << "listdir: no read access to " << dir;
|
||||
goto out;
|
||||
}
|
||||
|
||||
d = OPENDIR(sysdir);
|
||||
if (d == 0) {
|
||||
if (!dc.opendir()) {
|
||||
msg << "listdir: cant opendir " << dir << ", errno " << errno;
|
||||
goto out;
|
||||
}
|
||||
|
||||
struct DIRENT *ent;
|
||||
while ((ent = READDIR(d)) != 0) {
|
||||
#ifdef _WIN32
|
||||
string sdname;
|
||||
if (!wchartoutf8(ent->d_name, sdname)) {
|
||||
const struct PathDirContents::Entry *ent;
|
||||
while ((ent = dc.readdir()) != 0) {
|
||||
if (ent->d_name == "." || ent->d_name == "..") {
|
||||
continue;
|
||||
}
|
||||
const char *dname = sdname.c_str();
|
||||
#else
|
||||
const char *dname = ent->d_name;
|
||||
#endif
|
||||
if (!strcmp(dname, ".") || !strcmp(dname, "..")) {
|
||||
continue;
|
||||
}
|
||||
entries.insert(dname);
|
||||
entries.insert(ent->d_name);
|
||||
}
|
||||
|
||||
out:
|
||||
if (d) {
|
||||
CLOSEDIR(d);
|
||||
}
|
||||
reason = msg.str();
|
||||
if (reason.empty()) {
|
||||
return true;
|
||||
|
||||
@ -39,6 +39,21 @@ extern std::string path_basename(const std::string& s,
|
||||
extern std::string path_suffix(const std::string& s);
|
||||
/// Get the father directory
|
||||
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
|
||||
extern std::string path_home();
|
||||
/// 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***
|
||||
/// we return an empty path in this case.
|
||||
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
|
||||
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
|
||||
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
|
||||
/// 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,
|
||||
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
|
||||
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()
|
||||
#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
|
||||
extern bool listdir(const std::string& dir, std::string& reason,
|
||||
std::set<std::string>& entries);
|
||||
@ -136,10 +166,11 @@ 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_chdir(const std::string& path);
|
||||
extern std::string path_cwd();
|
||||
extern bool path_unlink(const std::string& path);
|
||||
|
||||
bool path_chdir(const std::string& path);
|
||||
std::string path_cwd();
|
||||
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
|
||||
* Windows, where it only works with MSVC at the moment if the path is
|
||||
* not ASCII, because it uses fstream(wchar_t*), which is an MSVC
|
||||
@ -151,20 +182,23 @@ extern bool path_unlink(const std::string& path);
|
||||
* @param path an utf-8 file path.
|
||||
* @param mode is an std::fstream mode (ios::in etc.) */
|
||||
extern std::fstream path_open(const std::string& path, int mode);
|
||||
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);
|
||||
extern bool path_open(
|
||||
const std::string& path, int mode, std::fstream& outstream);
|
||||
|
||||
/// 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
|
||||
extern std::string path_pathtofileurl(const std::string& path);
|
||||
|
||||
|
||||
@ -194,6 +194,28 @@ static bool path_gettempfilename(string& filename, string& reason)
|
||||
}
|
||||
#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.
|
||||
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.
|
||||
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
|
||||
extern const std::string& path_pkgdatadir();
|
||||
|
||||
|
||||
@ -41,6 +41,9 @@ void smallut_init_mt();
|
||||
#ifndef deleteZ
|
||||
#define deleteZ(X) {delete X;X = 0;}
|
||||
#endif
|
||||
#ifndef PRETEND_USE
|
||||
#define PRETEND_USE(var) ((void)(var))
|
||||
#endif
|
||||
#endif /* SMALLUT_DISABLE_MACROS */
|
||||
|
||||
// Case-insensitive compare. ASCII ONLY !
|
||||
|
||||
@ -19,140 +19,72 @@
|
||||
|
||||
#include "wipedir.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
#include "log.h"
|
||||
#include "pathut.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include "msvc_dirent.h"
|
||||
#else // !_MSC_VER
|
||||
#include <dirent.h>
|
||||
#endif // _MSC_VER
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "safefcntl.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
|
||||
|
||||
# include "safeunistd.h"
|
||||
#else // Not windows ->
|
||||
|
||||
#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
|
||||
# include <unistd.h>
|
||||
#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;
|
||||
|
||||
SYSPATH(dir, sysdir);
|
||||
statret = LSTAT(sysdir, &st);
|
||||
if (statret == -1) {
|
||||
LOGSYSERR("wipedir", "stat", dir);
|
||||
return -1;
|
||||
}
|
||||
if (!S_ISDIR(st.st_mode)) {
|
||||
LOGERR("wipedir: " << dir << " not a directory\n");
|
||||
return -1;
|
||||
if (!path_isdir(dir)) {
|
||||
LOGERR("wipedir: " << dir << " not a directory\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ACCESS(sysdir, R_OK|W_OK|X_OK) < 0) {
|
||||
LOGSYSERR("wipedir", "access", dir);
|
||||
return -1;
|
||||
if (!path_access(dir, R_OK|W_OK|X_OK)) {
|
||||
LOGSYSERR("wipedir", "access", dir);
|
||||
return -1;
|
||||
}
|
||||
|
||||
DIRHDL *d = OPENDIR(sysdir);
|
||||
if (d == 0) {
|
||||
LOGSYSERR("wipedir", "opendir", dir);
|
||||
return -1;
|
||||
PathDirContents dc(dir);
|
||||
if (!dc.opendir()) {
|
||||
LOGSYSERR("wipedir", "opendir", dir);
|
||||
return -1;
|
||||
}
|
||||
int remaining = 0;
|
||||
struct DIRENT *ent;
|
||||
while ((ent = READDIR(d)) != 0) {
|
||||
#ifdef _WIN32
|
||||
string sdname;
|
||||
if (!wchartoutf8(ent->d_name, sdname)) {
|
||||
const struct PathDirContents::Entry *ent;
|
||||
while ((ent = dc.readdir()) != 0) {
|
||||
const std::string& dname{ent->d_name};
|
||||
if (dname == "." || dname == "..")
|
||||
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);
|
||||
struct STATBUF st;
|
||||
int statret = LSTAT(sysfn, &st);
|
||||
if (statret == -1) {
|
||||
LOGSYSERR("wipedir", "stat", fn);
|
||||
goto out;
|
||||
}
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
if (recurse) {
|
||||
int rr = wipedir(fn, true, true);
|
||||
if (rr == -1)
|
||||
goto out;
|
||||
else
|
||||
remaining += rr;
|
||||
if (path_isdir(fn)) {
|
||||
if (recurse) {
|
||||
int rr = wipedir(fn, true, true);
|
||||
if (rr == -1)
|
||||
goto out;
|
||||
else
|
||||
remaining += rr;
|
||||
} else {
|
||||
remaining++;
|
||||
}
|
||||
} 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;
|
||||
if (selfalso && ret == 0) {
|
||||
if (RMDIR(sysdir) < 0) {
|
||||
LOGSYSERR("wipedir", "rmdir", dir);
|
||||
ret = -1;
|
||||
}
|
||||
if (!path_rmdir(dir)) {
|
||||
LOGSYSERR("wipedir", "rmdir", dir);
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
if (d)
|
||||
CLOSEDIR(d);
|
||||
return ret;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user