|
a/src/utils/pathut.cpp |
|
b/src/utils/pathut.cpp |
|
... |
|
... |
17 |
|
17 |
|
18 |
#ifndef TEST_PATHUT
|
18 |
#ifndef TEST_PATHUT
|
19 |
#include "autoconfig.h"
|
19 |
#include "autoconfig.h"
|
20 |
|
20 |
|
21 |
#include <stdio.h>
|
21 |
#include <stdio.h>
|
|
|
22 |
#include "safefcntl.h"
|
22 |
#include <unistd.h>
|
23 |
#include "safeunistd.h"
|
23 |
#include <fcntl.h>
|
|
|
24 |
#include <dirent.h>
|
24 |
#include "dirent.h"
|
|
|
25 |
#include "cstr.h"
|
|
|
26 |
#ifdef _WIN32
|
|
|
27 |
#include "safewindows.h"
|
|
|
28 |
#else
|
25 |
#include <sys/param.h>
|
29 |
#include <sys/param.h>
|
26 |
#include <pwd.h>
|
30 |
#include <pwd.h>
|
|
|
31 |
#include <sys/file.h>
|
|
|
32 |
#endif
|
27 |
#include <math.h>
|
33 |
#include <math.h>
|
28 |
#include <errno.h>
|
34 |
#include <errno.h>
|
29 |
#include <sys/types.h>
|
35 |
#include <sys/types.h>
|
30 |
#include <sys/file.h>
|
|
|
31 |
#include "safesysstat.h"
|
36 |
#include "safesysstat.h"
|
32 |
#include <glob.h>
|
37 |
#include "ptmutex.h"
|
33 |
|
38 |
|
34 |
// Let's include all files where statfs can be defined and hope for no
|
39 |
// Let's include all files where statfs can be defined and hope for no
|
35 |
// conflict...
|
40 |
// conflict...
|
36 |
#ifdef HAVE_SYS_MOUNT_H
|
41 |
#ifdef HAVE_SYS_MOUNT_H
|
37 |
#include <sys/mount.h>
|
42 |
#include <sys/mount.h>
|
|
... |
|
... |
50 |
#include <cstring>
|
55 |
#include <cstring>
|
51 |
#include <iostream>
|
56 |
#include <iostream>
|
52 |
#include <sstream>
|
57 |
#include <sstream>
|
53 |
#include <stack>
|
58 |
#include <stack>
|
54 |
#include <set>
|
59 |
#include <set>
|
55 |
using namespace std;
|
60 |
#include <vector>
|
56 |
|
61 |
|
57 |
#include "pathut.h"
|
62 |
#include "pathut.h"
|
58 |
#include "transcode.h"
|
63 |
#include "transcode.h"
|
59 |
#include "wipedir.h"
|
64 |
#include "wipedir.h"
|
60 |
#include "md5ut.h"
|
65 |
#include "md5ut.h"
|
61 |
|
66 |
|
|
|
67 |
using namespace std;
|
|
|
68 |
|
|
|
69 |
#ifdef _WIN32
|
|
|
70 |
/// Convert \ separators to /
|
|
|
71 |
void path_slashize(string& s)
|
|
|
72 |
{
|
|
|
73 |
for (string::size_type i = 0; i < s.size(); i++) {
|
|
|
74 |
if (s[i] == '\\')
|
|
|
75 |
s[i] = '/';
|
|
|
76 |
}
|
|
|
77 |
}
|
|
|
78 |
static bool path_strlookslikedrive(const string& s)
|
|
|
79 |
{
|
|
|
80 |
return s.size() == 2 && isalpha(s[0]) && s[1] == ':';
|
|
|
81 |
}
|
|
|
82 |
|
|
|
83 |
static bool path_hasdrive(const string& s)
|
|
|
84 |
{
|
|
|
85 |
if (s.size() >= 2 && isalpha(s[0]) && s[1] == ':')
|
|
|
86 |
return true;
|
|
|
87 |
return false;
|
|
|
88 |
}
|
|
|
89 |
static bool path_isdriveabs(const string& s)
|
|
|
90 |
{
|
|
|
91 |
if (s.size() >= 3 && isalpha(s[0]) && s[1] == ':' && s[2] == '/')
|
|
|
92 |
return true;
|
|
|
93 |
return false;
|
|
|
94 |
}
|
|
|
95 |
|
|
|
96 |
#include <Shlwapi.h>
|
|
|
97 |
#pragma comment(lib, "shlwapi.lib")
|
|
|
98 |
|
|
|
99 |
string path_tchartoutf8(TCHAR *text)
|
|
|
100 |
{
|
|
|
101 |
#ifdef UNICODE
|
|
|
102 |
// Simple C
|
|
|
103 |
// const size_t size = ( wcslen(text) + 1 ) * sizeof(wchar_t);
|
|
|
104 |
// wcstombs(&buffer[0], text, size);
|
|
|
105 |
// std::vector<char> buffer(size);
|
|
|
106 |
// Or:
|
|
|
107 |
// Windows API
|
|
|
108 |
std::vector<char> buffer;
|
|
|
109 |
int size = WideCharToMultiByte(CP_UTF8, 0, text, -1, NULL, 0, NULL, NULL);
|
|
|
110 |
if (size > 0) {
|
|
|
111 |
buffer.resize(size);
|
|
|
112 |
WideCharToMultiByte(CP_UTF8, 0, text, -1,
|
|
|
113 |
&buffer[0], int(buffer.size()), NULL, NULL);
|
|
|
114 |
} else {
|
|
|
115 |
return string();
|
|
|
116 |
}
|
|
|
117 |
return string(&buffer[0]);
|
|
|
118 |
#else
|
|
|
119 |
return text;
|
|
|
120 |
#endif
|
|
|
121 |
}
|
|
|
122 |
|
|
|
123 |
string path_thisexecpath()
|
|
|
124 |
{
|
|
|
125 |
TCHAR text[MAX_PATH];
|
|
|
126 |
DWORD length = GetModuleFileName(NULL, text, MAX_PATH);
|
|
|
127 |
#ifdef NTDDI_WIN8_future
|
|
|
128 |
PathCchRemoveFileSpec(text, MAX_PATH);
|
|
|
129 |
#else
|
|
|
130 |
PathRemoveFileSpec(text);
|
|
|
131 |
#endif
|
|
|
132 |
string path = path_tchartoutf8(text);
|
|
|
133 |
if (path.empty())
|
|
|
134 |
path = "c:/";
|
|
|
135 |
|
|
|
136 |
return path;
|
|
|
137 |
}
|
|
|
138 |
|
|
|
139 |
string path_wingettempfilename(TCHAR *pref)
|
|
|
140 |
{
|
|
|
141 |
TCHAR buf[(MAX_PATH +1)*sizeof(TCHAR)];
|
|
|
142 |
TCHAR dbuf[(MAX_PATH +1)*sizeof(TCHAR)];
|
|
|
143 |
GetTempPath(MAX_PATH+1, dbuf);
|
|
|
144 |
GetTempFileName(dbuf, pref, 0, buf);
|
|
|
145 |
// Windows will have created a temp file, we delete it.
|
|
|
146 |
string filename = path_tchartoutf8(buf);
|
|
|
147 |
unlink(filename.c_str());
|
|
|
148 |
return filename;
|
|
|
149 |
}
|
|
|
150 |
#endif
|
|
|
151 |
|
|
|
152 |
|
62 |
bool fsocc(const string &path, int *pc, long long *blocks)
|
153 |
bool fsocc(const string &path, int *pc, long long *blocks)
|
63 |
{
|
154 |
{
|
|
|
155 |
#ifdef _WIN32
|
|
|
156 |
return false;
|
|
|
157 |
#else
|
64 |
#ifdef sun
|
158 |
#ifdef sun
|
65 |
struct statvfs buf;
|
159 |
struct statvfs buf;
|
66 |
if (statvfs(path.c_str(), &buf) != 0) {
|
160 |
if (statvfs(path.c_str(), &buf) != 0) {
|
67 |
return false;
|
161 |
return false;
|
68 |
}
|
162 |
}
|
|
... |
|
... |
92 |
((long long)buf.f_bavail) * ratio :
|
186 |
((long long)buf.f_bavail) * ratio :
|
93 |
((long long)buf.f_bavail) / ratio;
|
187 |
((long long)buf.f_bavail) / ratio;
|
94 |
}
|
188 |
}
|
95 |
}
|
189 |
}
|
96 |
return true;
|
190 |
return true;
|
|
|
191 |
#endif
|
97 |
}
|
192 |
}
|
98 |
|
193 |
|
99 |
const string& tmplocation()
|
194 |
const string& tmplocation()
|
100 |
{
|
195 |
{
|
101 |
static string stmpdir;
|
196 |
static string stmpdir;
|
102 |
if (stmpdir.empty()) {
|
197 |
if (stmpdir.empty()) {
|
103 |
const char *tmpdir = getenv("RECOLL_TMPDIR");
|
198 |
const char *tmpdir = getenv("RECOLL_TMPDIR");
|
104 |
if (tmpdir == 0)
|
199 |
if (tmpdir == 0)
|
105 |
tmpdir = getenv("TMPDIR");
|
200 |
tmpdir = getenv("TMPDIR");
|
106 |
if (tmpdir == 0)
|
201 |
if (tmpdir == 0)
|
|
|
202 |
tmpdir = getenv("TMP");
|
|
|
203 |
if (tmpdir == 0)
|
|
|
204 |
tmpdir = getenv("TEMP");
|
|
|
205 |
if (tmpdir == 0) {
|
|
|
206 |
#ifdef _WIN32
|
|
|
207 |
TCHAR bufw[(MAX_PATH+1)*sizeof(TCHAR)];
|
|
|
208 |
GetTempPath(MAX_PATH+1, bufw);
|
|
|
209 |
stmpdir = path_tchartoutf8(bufw);
|
|
|
210 |
#else
|
107 |
tmpdir = "/tmp";
|
211 |
stmpdir = "/tmp";
|
|
|
212 |
#endif
|
|
|
213 |
} else {
|
108 |
stmpdir = string(tmpdir);
|
214 |
stmpdir = tmpdir;
|
109 |
}
|
215 |
}
|
|
|
216 |
stmpdir = path_canon(stmpdir);
|
|
|
217 |
}
|
|
|
218 |
|
110 |
return stmpdir;
|
219 |
return stmpdir;
|
111 |
}
|
220 |
}
|
112 |
|
221 |
|
|
|
222 |
// Location for sample config, filters, etc. (e.g. /usr/share/recoll/)
|
|
|
223 |
const string& path_sharedatadir()
|
|
|
224 |
{
|
|
|
225 |
static string datadir;
|
|
|
226 |
if (datadir.empty()) {
|
|
|
227 |
#ifdef _WIN32
|
|
|
228 |
datadir = path_cat(path_thisexecpath(), "Share");
|
|
|
229 |
#else
|
|
|
230 |
const char *cdatadir = getenv("RECOLL_DATADIR");
|
|
|
231 |
if (cdatadir == 0) {
|
|
|
232 |
// If not in environment, use the compiled-in constant.
|
|
|
233 |
datadir = RECOLL_DATADIR;
|
|
|
234 |
} else {
|
|
|
235 |
datadir = cdatadir;
|
|
|
236 |
}
|
|
|
237 |
#endif
|
|
|
238 |
}
|
|
|
239 |
return datadir;
|
|
|
240 |
}
|
|
|
241 |
|
|
|
242 |
string path_PATHsep()
|
|
|
243 |
{
|
|
|
244 |
static const string w(";");
|
|
|
245 |
static const string u(":");
|
|
|
246 |
#ifdef _WIN32
|
|
|
247 |
return w;
|
|
|
248 |
#else
|
|
|
249 |
return u;
|
|
|
250 |
#endif
|
|
|
251 |
}
|
|
|
252 |
|
113 |
bool maketmpdir(string& tdir, string& reason)
|
253 |
bool maketmpdir(string& tdir, string& reason)
|
114 |
{
|
254 |
{
|
|
|
255 |
#ifndef _WIN32
|
115 |
tdir = path_cat(tmplocation(), "rcltmpXXXXXX");
|
256 |
tdir = path_cat(tmplocation(), "rcltmpXXXXXX");
|
116 |
|
257 |
|
117 |
char *cp = strdup(tdir.c_str());
|
258 |
char *cp = strdup(tdir.c_str());
|
118 |
if (!cp) {
|
259 |
if (!cp) {
|
119 |
reason = "maketmpdir: out of memory (for file name !)\n";
|
260 |
reason = "maketmpdir: out of memory (for file name !)\n";
|
120 |
tdir.erase();
|
261 |
tdir.erase();
|
121 |
return false;
|
262 |
return false;
|
122 |
}
|
263 |
}
|
|
|
264 |
|
|
|
265 |
// There is a race condition between name computation and
|
|
|
266 |
// mkdir. try to make sure that we at least don't shoot ourselves
|
|
|
267 |
// in the foot
|
|
|
268 |
#if !defined(HAVE_MKDTEMP) || defined(_WIN32)
|
|
|
269 |
static PTMutexInit mlock;
|
|
|
270 |
PTMutexLocker lock(mlock);
|
|
|
271 |
#endif
|
123 |
|
272 |
|
124 |
if (!
|
273 |
if (!
|
125 |
#ifdef HAVE_MKDTEMP
|
274 |
#ifdef HAVE_MKDTEMP
|
126 |
mkdtemp(cp)
|
275 |
mkdtemp(cp)
|
127 |
#else
|
276 |
#else
|
|
... |
|
... |
134 |
tdir.erase();
|
283 |
tdir.erase();
|
135 |
return false;
|
284 |
return false;
|
136 |
}
|
285 |
}
|
137 |
tdir = cp;
|
286 |
tdir = cp;
|
138 |
free(cp);
|
287 |
free(cp);
|
|
|
288 |
#else // _WIN32
|
|
|
289 |
// There is a race condition between name computation and
|
|
|
290 |
// mkdir. try to make sure that we at least don't shoot ourselves
|
|
|
291 |
// in the foot
|
|
|
292 |
static PTMutexInit mlock;
|
|
|
293 |
PTMutexLocker lock(mlock);
|
|
|
294 |
tdir = path_wingettempfilename(TEXT("rcltmp"));
|
|
|
295 |
#endif
|
139 |
|
296 |
|
140 |
#ifndef HAVE_MKDTEMP
|
297 |
// At this point the directory does not exist yet except if we used
|
|
|
298 |
// mkdtemp
|
|
|
299 |
|
|
|
300 |
#if !defined(HAVE_MKDTEMP) || defined(_WIN32)
|
141 |
if (mkdir(tdir.c_str(), 0700) < 0) {
|
301 |
if (mkdir(tdir.c_str(), 0700) < 0) {
|
142 |
reason = string("maketmpdir: mkdir ") + tdir + " failed";
|
302 |
reason = string("maketmpdir: mkdir ") + tdir + " failed";
|
143 |
tdir.erase();
|
303 |
tdir.erase();
|
144 |
return false;
|
304 |
return false;
|
145 |
}
|
305 |
}
|
|
... |
|
... |
149 |
}
|
309 |
}
|
150 |
|
310 |
|
151 |
TempFileInternal::TempFileInternal(const string& suffix)
|
311 |
TempFileInternal::TempFileInternal(const string& suffix)
|
152 |
: m_noremove(false)
|
312 |
: m_noremove(false)
|
153 |
{
|
313 |
{
|
|
|
314 |
// Because we need a specific suffix, can't use mkstemp
|
|
|
315 |
// well. There is a race condition between name computation and
|
|
|
316 |
// file creation. try to make sure that we at least don't shoot
|
|
|
317 |
// our own selves in the foot. maybe we'll use mkstemps one day.
|
|
|
318 |
static PTMutexInit mlock;
|
|
|
319 |
PTMutexLocker lock(mlock);
|
|
|
320 |
|
|
|
321 |
#ifndef _WIN32
|
154 |
string filename = path_cat(tmplocation(), "rcltmpfXXXXXX");
|
322 |
string filename = path_cat(tmplocation(), "rcltmpfXXXXXX");
|
155 |
char *cp = strdup(filename.c_str());
|
323 |
char *cp = strdup(filename.c_str());
|
156 |
if (!cp) {
|
324 |
if (!cp) {
|
157 |
m_reason = "Out of memory (for file name !)\n";
|
325 |
m_reason = "Out of memory (for file name !)\n";
|
158 |
return;
|
326 |
return;
|
159 |
}
|
327 |
}
|
160 |
|
328 |
|
161 |
// Yes using mkstemp this way is awful (bot the suffix adding and
|
329 |
// Using mkstemp this way is awful (bot the suffix adding and
|
162 |
// using mkstemp() just to avoid the warnings)
|
330 |
// using mkstemp() instead of mktemp just to avoid the warnings)
|
163 |
int fd;
|
331 |
int fd;
|
164 |
if ((fd = mkstemp(cp)) < 0) {
|
332 |
if ((fd = mkstemp(cp)) < 0) {
|
165 |
free(cp);
|
333 |
free(cp);
|
166 |
m_reason = "TempFileInternal: mkstemp failed\n";
|
334 |
m_reason = "TempFileInternal: mkstemp failed\n";
|
167 |
return;
|
335 |
return;
|
168 |
}
|
336 |
}
|
169 |
close(fd);
|
337 |
close(fd);
|
170 |
unlink(cp);
|
338 |
unlink(cp);
|
171 |
|
|
|
172 |
filename = cp;
|
339 |
filename = cp;
|
173 |
free(cp);
|
340 |
free(cp);
|
|
|
341 |
#else
|
|
|
342 |
string filename = path_wingettempfilename(TEXT("recoll"));
|
|
|
343 |
#endif
|
174 |
|
344 |
|
175 |
m_filename = filename + suffix;
|
345 |
m_filename = filename + suffix;
|
176 |
if (close(open(m_filename.c_str(), O_CREAT|O_EXCL, 0600)) != 0) {
|
346 |
if (close(open(m_filename.c_str(), O_CREAT|O_EXCL, 0600)) != 0) {
|
177 |
m_reason = string("Could not open/create") + m_filename;
|
347 |
m_reason = string("Could not open/create") + m_filename;
|
178 |
m_filename.erase();
|
348 |
m_filename.erase();
|
|
... |
|
... |
212 |
return false;
|
382 |
return false;
|
213 |
}
|
383 |
}
|
214 |
return true;
|
384 |
return true;
|
215 |
}
|
385 |
}
|
216 |
|
386 |
|
217 |
void path_catslash(string &s) {
|
387 |
void path_catslash(string &s)
|
|
|
388 |
{
|
|
|
389 |
#ifdef WIN32
|
|
|
390 |
path_slashize(s);
|
|
|
391 |
#endif
|
218 |
if (s.empty() || s[s.length() - 1] != '/')
|
392 |
if (s.empty() || s[s.length() - 1] != '/')
|
219 |
s += '/';
|
393 |
s += '/';
|
220 |
}
|
394 |
}
|
221 |
|
395 |
|
222 |
string path_cat(const string &s1, const string &s2) {
|
396 |
string path_cat(const string &s1, const string &s2)
|
|
|
397 |
{
|
223 |
string res = s1;
|
398 |
string res = s1;
|
224 |
path_catslash(res);
|
399 |
path_catslash(res);
|
225 |
res += s2;
|
400 |
res += s2;
|
226 |
return res;
|
401 |
return res;
|
227 |
}
|
402 |
}
|
228 |
|
403 |
|
229 |
string path_getfather(const string &s) {
|
404 |
string path_getfather(const string &s)
|
|
|
405 |
{
|
230 |
string father = s;
|
406 |
string father = s;
|
|
|
407 |
#ifdef WIN32
|
|
|
408 |
path_slashize(father);
|
|
|
409 |
#endif
|
231 |
|
410 |
|
232 |
// ??
|
411 |
// ??
|
233 |
if (father.empty())
|
412 |
if (father.empty())
|
234 |
return "./";
|
413 |
return "./";
|
235 |
|
414 |
|
|
|
415 |
if (path_isroot(father))
|
|
|
416 |
return father;
|
|
|
417 |
|
236 |
if (father[father.length() - 1] == '/') {
|
418 |
if (father[father.length() - 1] == '/') {
|
237 |
// Input ends with /. Strip it, handle special case for root
|
419 |
// Input ends with /. Strip it, root special case was tested above
|
238 |
if (father.length() == 1)
|
|
|
239 |
return father;
|
|
|
240 |
father.erase(father.length()-1);
|
420 |
father.erase(father.length()-1);
|
241 |
}
|
421 |
}
|
242 |
|
422 |
|
243 |
string::size_type slp = father.rfind('/');
|
423 |
string::size_type slp = father.rfind('/');
|
244 |
if (slp == string::npos)
|
424 |
if (slp == string::npos)
|
|
... |
|
... |
247 |
father.erase(slp);
|
427 |
father.erase(slp);
|
248 |
path_catslash(father);
|
428 |
path_catslash(father);
|
249 |
return father;
|
429 |
return father;
|
250 |
}
|
430 |
}
|
251 |
|
431 |
|
252 |
string path_getsimple(const string &s) {
|
432 |
string path_getsimple(const string &s)
|
|
|
433 |
{
|
253 |
string simple = s;
|
434 |
string simple = s;
|
|
|
435 |
#ifdef WIN32
|
|
|
436 |
path_slashize(simple);
|
|
|
437 |
#endif
|
254 |
|
438 |
|
255 |
if (simple.empty())
|
439 |
if (simple.empty())
|
256 |
return simple;
|
440 |
return simple;
|
257 |
|
441 |
|
258 |
string::size_type slp = simple.rfind('/');
|
442 |
string::size_type slp = simple.rfind('/');
|
|
... |
|
... |
283 |
return s.substr(dotp+1);
|
467 |
return s.substr(dotp+1);
|
284 |
}
|
468 |
}
|
285 |
|
469 |
|
286 |
string path_home()
|
470 |
string path_home()
|
287 |
{
|
471 |
{
|
|
|
472 |
#ifdef _WIN32
|
|
|
473 |
string dir;
|
|
|
474 |
const char *cp = getenv("USERPROFILE");
|
|
|
475 |
if (cp != 0) {
|
|
|
476 |
dir = cp;
|
|
|
477 |
}
|
|
|
478 |
if (dir.empty()) {
|
|
|
479 |
cp = getenv("HOMEDRIVE");
|
|
|
480 |
if (cp != 0) {
|
|
|
481 |
const char *cp1 = getenv("HOMEPATH");
|
|
|
482 |
if (cp1 != 0) {
|
|
|
483 |
dir = string(cp) + string(cp1);
|
|
|
484 |
}
|
|
|
485 |
}
|
|
|
486 |
}
|
|
|
487 |
if (dir.empty()) {
|
|
|
488 |
dir = "C:\\";
|
|
|
489 |
}
|
|
|
490 |
dir = path_canon(dir);
|
|
|
491 |
path_catslash(dir);
|
|
|
492 |
return dir;
|
|
|
493 |
#else
|
288 |
uid_t uid = getuid();
|
494 |
uid_t uid = getuid();
|
289 |
|
495 |
|
290 |
struct passwd *entry = getpwuid(uid);
|
496 |
struct passwd *entry = getpwuid(uid);
|
291 |
if (entry == 0) {
|
497 |
if (entry == 0) {
|
292 |
const char *cp = getenv("HOME");
|
498 |
const char *cp = getenv("HOME");
|
|
... |
|
... |
297 |
}
|
503 |
}
|
298 |
|
504 |
|
299 |
string homedir = entry->pw_dir;
|
505 |
string homedir = entry->pw_dir;
|
300 |
path_catslash(homedir);
|
506 |
path_catslash(homedir);
|
301 |
return homedir;
|
507 |
return homedir;
|
|
|
508 |
#endif
|
|
|
509 |
}
|
|
|
510 |
|
|
|
511 |
// The default place to store the default config and other stuff (e.g webqueue)
|
|
|
512 |
string path_homedata()
|
|
|
513 |
{
|
|
|
514 |
#ifdef _WIN32
|
|
|
515 |
const char *cp = getenv("LOCALAPPDATA");
|
|
|
516 |
string dir;
|
|
|
517 |
if (cp != 0) {
|
|
|
518 |
dir = path_canon(cp);
|
|
|
519 |
}
|
|
|
520 |
if (dir.empty()) {
|
|
|
521 |
dir = path_cat(path_home(), "AppData/Local/");
|
|
|
522 |
}
|
|
|
523 |
return dir;
|
|
|
524 |
#else
|
|
|
525 |
// We should use an xdg-conforming location, but, history...
|
|
|
526 |
return path_home();
|
|
|
527 |
#endif
|
302 |
}
|
528 |
}
|
303 |
|
529 |
|
304 |
string path_tildexpand(const string &s)
|
530 |
string path_tildexpand(const string &s)
|
305 |
{
|
531 |
{
|
306 |
if (s.empty() || s[0] != '~')
|
532 |
if (s.empty() || s[0] != '~')
|
307 |
return s;
|
533 |
return s;
|
308 |
string o = s;
|
534 |
string o = s;
|
|
|
535 |
#ifdef WIN32
|
|
|
536 |
path_slashize(o);
|
|
|
537 |
#endif
|
|
|
538 |
|
309 |
if (s.length() == 1) {
|
539 |
if (s.length() == 1) {
|
310 |
o.replace(0, 1, path_home());
|
540 |
o.replace(0, 1, path_home());
|
311 |
} else if (s[1] == '/') {
|
541 |
} else if (s[1] == '/') {
|
312 |
o.replace(0, 2, path_home());
|
542 |
o.replace(0, 2, path_home());
|
313 |
} else {
|
543 |
} else {
|
314 |
string::size_type pos = s.find('/');
|
544 |
string::size_type pos = s.find('/');
|
315 |
int l = (pos == string::npos) ? s.length() - 1 : pos - 1;
|
545 |
string::size_type l = (pos == string::npos) ? s.length() - 1 : pos - 1;
|
|
|
546 |
#ifdef _WIN32
|
|
|
547 |
// Dont know what this means. Just replace with HOME
|
|
|
548 |
o.replace(0, l+1, path_home());
|
|
|
549 |
#else
|
316 |
struct passwd *entry = getpwnam(s.substr(1, l).c_str());
|
550 |
struct passwd *entry = getpwnam(s.substr(1, l).c_str());
|
317 |
if (entry)
|
551 |
if (entry)
|
318 |
o.replace(0, l+1, entry->pw_dir);
|
552 |
o.replace(0, l+1, entry->pw_dir);
|
|
|
553 |
#endif
|
319 |
}
|
554 |
}
|
320 |
return o;
|
555 |
return o;
|
321 |
}
|
556 |
}
|
322 |
|
557 |
|
|
|
558 |
bool path_isroot(const string& path)
|
|
|
559 |
{
|
|
|
560 |
if (path.size() == 1 && path[0] == '/')
|
|
|
561 |
return true;
|
|
|
562 |
#ifdef _WIN32
|
|
|
563 |
if (path.size() == 3 && isalpha(path[0]) && path[1] == ':' &&
|
|
|
564 |
(path[2] == '/' || path[2] == '\\'))
|
|
|
565 |
return true;
|
|
|
566 |
#endif
|
|
|
567 |
return false;
|
|
|
568 |
}
|
|
|
569 |
|
|
|
570 |
bool path_isabsolute(const string &path)
|
|
|
571 |
{
|
|
|
572 |
if (!path.empty() && (path[0] == '/'
|
|
|
573 |
#ifdef _WIN32
|
|
|
574 |
|| path_isdriveabs(path)
|
|
|
575 |
#endif
|
|
|
576 |
)) {
|
|
|
577 |
return true;
|
|
|
578 |
}
|
|
|
579 |
return false;
|
|
|
580 |
}
|
|
|
581 |
|
323 |
string path_absolute(const string &is)
|
582 |
string path_absolute(const string &is)
|
324 |
{
|
583 |
{
|
325 |
if (is.length() == 0)
|
584 |
if (is.length() == 0)
|
326 |
return is;
|
585 |
return is;
|
327 |
string s = is;
|
586 |
string s = is;
|
328 |
if (s[0] != '/') {
|
587 |
if (!path_isabsolute(s)) {
|
329 |
char buf[MAXPATHLEN];
|
588 |
char buf[MAXPATHLEN];
|
330 |
if (!getcwd(buf, MAXPATHLEN)) {
|
589 |
if (!getcwd(buf, MAXPATHLEN)) {
|
331 |
return string();
|
590 |
return string();
|
332 |
}
|
591 |
}
|
333 |
s = path_cat(string(buf), s);
|
592 |
s = path_cat(string(buf), s);
|
|
|
593 |
#ifdef _WIN32
|
|
|
594 |
path_slashize(s);
|
|
|
595 |
#endif
|
334 |
}
|
596 |
}
|
335 |
return s;
|
597 |
return s;
|
336 |
}
|
598 |
}
|
337 |
|
599 |
|
338 |
#include <smallut.h>
|
600 |
#include <smallut.h>
|
339 |
string path_canon(const string &is, const string* cwd)
|
601 |
string path_canon(const string &is, const string* cwd)
|
340 |
{
|
602 |
{
|
341 |
if (is.length() == 0)
|
603 |
if (is.length() == 0)
|
342 |
return is;
|
604 |
return is;
|
343 |
string s = is;
|
605 |
string s = is;
|
344 |
if (s[0] != '/') {
|
606 |
#ifdef _WIN32
|
|
|
607 |
path_slashize(s);
|
|
|
608 |
// fix possible path from file: absolute url
|
|
|
609 |
if (s.size() && s[0] == '/' && path_hasdrive(s.substr(1))) {
|
|
|
610 |
s = s.substr(1);
|
|
|
611 |
}
|
|
|
612 |
#endif
|
|
|
613 |
|
|
|
614 |
if (!path_isabsolute(s)) {
|
345 |
char buf[MAXPATHLEN];
|
615 |
char buf[MAXPATHLEN];
|
346 |
const char *cwdp = buf;
|
616 |
const char *cwdp = buf;
|
347 |
if (cwd) {
|
617 |
if (cwd) {
|
348 |
cwdp = cwd->c_str();
|
618 |
cwdp = cwd->c_str();
|
349 |
} else {
|
619 |
} else {
|
|
... |
|
... |
368 |
}
|
638 |
}
|
369 |
string ret;
|
639 |
string ret;
|
370 |
if (!cleaned.empty()) {
|
640 |
if (!cleaned.empty()) {
|
371 |
for (vector<string>::const_iterator it = cleaned.begin();
|
641 |
for (vector<string>::const_iterator it = cleaned.begin();
|
372 |
it != cleaned.end(); it++) {
|
642 |
it != cleaned.end(); it++) {
|
373 |
ret += "/";
|
643 |
ret += "/";
|
|
|
644 |
#ifdef _WIN32
|
|
|
645 |
if (it == cleaned.begin() && path_strlookslikedrive(*it)) {
|
|
|
646 |
// Get rid of just added initial "/"
|
|
|
647 |
ret.clear();
|
|
|
648 |
}
|
|
|
649 |
#endif
|
374 |
ret += *it;
|
650 |
ret += *it;
|
375 |
}
|
651 |
}
|
376 |
} else {
|
652 |
} else {
|
377 |
ret = "/";
|
653 |
ret = "/";
|
378 |
}
|
654 |
}
|
|
... |
|
... |
385 |
vector<string> elems;
|
661 |
vector<string> elems;
|
386 |
stringToTokens(path, elems, "/");
|
662 |
stringToTokens(path, elems, "/");
|
387 |
path = "/";
|
663 |
path = "/";
|
388 |
for (vector<string>::const_iterator it = elems.begin();
|
664 |
for (vector<string>::const_iterator it = elems.begin();
|
389 |
it != elems.end(); it++){
|
665 |
it != elems.end(); it++){
|
|
|
666 |
#ifdef _WIN32
|
|
|
667 |
if (it == elems.begin() && path_strlookslikedrive(*it))
|
|
|
668 |
path = "";
|
|
|
669 |
#endif
|
390 |
path += *it;
|
670 |
path += *it;
|
391 |
// Not using path_isdir() here, because this cant grok symlinks
|
671 |
// Not using path_isdir() here, because this cant grok symlinks
|
392 |
// If we hit an existing file, no worry, mkdir will just fail.
|
672 |
// If we hit an existing file, no worry, mkdir will just fail.
|
393 |
if (access(path.c_str(), 0) != 0) {
|
673 |
if (access(path.c_str(), 0) != 0) {
|
394 |
if (mkdir(path.c_str(), 0700) != 0) {
|
674 |
if (mkdir(path.c_str(), 0700) != 0) {
|
|
... |
|
... |
396 |
}
|
676 |
}
|
397 |
}
|
677 |
}
|
398 |
path += "/";
|
678 |
path += "/";
|
399 |
}
|
679 |
}
|
400 |
return true;
|
680 |
return true;
|
401 |
}
|
|
|
402 |
|
|
|
403 |
vector<string> path_dirglob(const string &dir, const string pattern)
|
|
|
404 |
{
|
|
|
405 |
vector<string> res;
|
|
|
406 |
glob_t mglob;
|
|
|
407 |
string mypat=path_cat(dir, pattern);
|
|
|
408 |
if (glob(mypat.c_str(), 0, 0, &mglob)) {
|
|
|
409 |
return res;
|
|
|
410 |
}
|
|
|
411 |
for (int i = 0; i < int(mglob.gl_pathc); i++) {
|
|
|
412 |
res.push_back(mglob.gl_pathv[i]);
|
|
|
413 |
}
|
|
|
414 |
globfree(&mglob);
|
|
|
415 |
return res;
|
|
|
416 |
}
|
681 |
}
|
417 |
|
682 |
|
418 |
bool path_isdir(const string& path)
|
683 |
bool path_isdir(const string& path)
|
419 |
{
|
684 |
{
|
420 |
struct stat st;
|
685 |
struct stat st;
|
|
... |
|
... |
551 |
}
|
816 |
}
|
552 |
return isfileurl ? string("file://") + parenturl :
|
817 |
return isfileurl ? string("file://") + parenturl :
|
553 |
string("http://") + parenturl;
|
818 |
string("http://") + parenturl;
|
554 |
}
|
819 |
}
|
555 |
|
820 |
|
|
|
821 |
|
|
|
822 |
string path_defaultrecollconfsubdir()
|
|
|
823 |
{
|
|
|
824 |
#ifdef _WIN32
|
|
|
825 |
return "Recoll";
|
|
|
826 |
#else
|
|
|
827 |
return ".recoll";
|
|
|
828 |
#endif
|
|
|
829 |
}
|
|
|
830 |
|
556 |
// Convert to file path if url is like file:
|
831 |
// Convert to file path if url is like file:
|
557 |
// Note: this only works with our internal pseudo-urls which are not
|
832 |
// Note: this only works with our internal pseudo-urls which are not
|
558 |
// encoded/escaped
|
833 |
// encoded/escaped
|
559 |
string fileurltolocalpath(string url)
|
834 |
string fileurltolocalpath(string url)
|
560 |
{
|
835 |
{
|
561 |
if (url.find("file://") == 0)
|
836 |
if (url.find("file://") == 0)
|
562 |
url = url.substr(7, string::npos);
|
837 |
url = url.substr(7, string::npos);
|
563 |
else
|
838 |
else
|
564 |
return string();
|
839 |
return string();
|
|
|
840 |
|
|
|
841 |
#ifdef _WIN32
|
|
|
842 |
// Absolute file urls are like: file:///c:/mydir/...
|
|
|
843 |
// Get rid of the initial '/'
|
|
|
844 |
if (url.size() >= 3 && url[0] == '/' && isalpha(url[1]) && url[2] == ':') {
|
|
|
845 |
url = url.substr(1);
|
|
|
846 |
}
|
|
|
847 |
#endif
|
565 |
|
848 |
|
566 |
// Removing the fragment part. This is exclusively used when
|
849 |
// Removing the fragment part. This is exclusively used when
|
567 |
// executing a viewer for the recoll manual, and we only strip the
|
850 |
// executing a viewer for the recoll manual, and we only strip the
|
568 |
// part after # if it is preceded by .html
|
851 |
// part after # if it is preceded by .html
|
569 |
string::size_type pos;
|
852 |
string::size_type pos;
|
|
... |
|
... |
572 |
} else if ((pos = url.rfind(".htm#")) != string::npos) {
|
855 |
} else if ((pos = url.rfind(".htm#")) != string::npos) {
|
573 |
url.erase(pos+4);
|
856 |
url.erase(pos+4);
|
574 |
}
|
857 |
}
|
575 |
|
858 |
|
576 |
return url;
|
859 |
return url;
|
|
|
860 |
}
|
|
|
861 |
|
|
|
862 |
string path_pathtofileurl(const string& path)
|
|
|
863 |
{
|
|
|
864 |
// We're supposed to receive a canonic absolute path, but on windows we
|
|
|
865 |
// may need to add a '/' in front of the drive spec
|
|
|
866 |
string url(cstr_fileu);
|
|
|
867 |
if (path.empty() || path[0] != '/')
|
|
|
868 |
url.push_back('/');
|
|
|
869 |
url += path;
|
|
|
870 |
return url;
|
577 |
}
|
871 |
}
|
578 |
|
872 |
|
579 |
bool urlisfileurl(const string& url)
|
873 |
bool urlisfileurl(const string& url)
|
580 |
{
|
874 |
{
|
581 |
return url.find("file://") == 0;
|
875 |
return url.find("file://") == 0;
|
|
... |
|
... |
685 |
errno = serrno;
|
979 |
errno = serrno;
|
686 |
m_reason = "fcntl lock failed";
|
980 |
m_reason = "fcntl lock failed";
|
687 |
return -1;
|
981 |
return -1;
|
688 |
}
|
982 |
}
|
689 |
#else
|
983 |
#else
|
|
|
984 |
#ifdef _WIN32
|
|
|
985 |
return 0;
|
|
|
986 |
#else
|
690 |
int operation = LOCK_EX | LOCK_NB;
|
987 |
int operation = LOCK_EX | LOCK_NB;
|
691 |
if (flock(m_fd, operation) == -1) {
|
988 |
if (flock(m_fd, operation) == -1) {
|
692 |
int serrno = errno;
|
989 |
int serrno = errno;
|
693 |
(void)::close(m_fd);
|
990 |
(void)::close(m_fd);
|
694 |
errno = serrno;
|
991 |
errno = serrno;
|
695 |
m_reason = "flock failed";
|
992 |
m_reason = "flock failed";
|
696 |
return -1;
|
993 |
return -1;
|
697 |
}
|
994 |
}
|
|
|
995 |
#endif // ! win32
|
698 |
#endif // ! sun
|
996 |
#endif // ! sun
|
699 |
|
997 |
|
700 |
if (ftruncate(m_fd, 0) != 0) {
|
998 |
if (ftruncate(m_fd, 0) != 0) {
|
701 |
/* can't happen [tm] */
|
999 |
/* can't happen [tm] */
|
702 |
int serrno = errno;
|
1000 |
int serrno = errno;
|
|
... |
|
... |
813 |
void pathut_init_mt()
|
1111 |
void pathut_init_mt()
|
814 |
{
|
1112 |
{
|
815 |
path_home();
|
1113 |
path_home();
|
816 |
tmplocation();
|
1114 |
tmplocation();
|
817 |
thumbnailsdir();
|
1115 |
thumbnailsdir();
|
|
|
1116 |
path_sharedatadir();
|
818 |
}
|
1117 |
}
|
819 |
|
1118 |
|
820 |
|
1119 |
|
821 |
#else // TEST_PATHUT
|
1120 |
#else // TEST_PATHUT
|
822 |
#include <stdlib.h>
|
1121 |
#include <stdlib.h>
|
|
... |
|
... |
931 |
sleep(10);
|
1230 |
sleep(10);
|
932 |
pidfile.close();
|
1231 |
pidfile.close();
|
933 |
pidfile.remove();
|
1232 |
pidfile.remove();
|
934 |
#endif
|
1233 |
#endif
|
935 |
|
1234 |
|
936 |
#if 1
|
1235 |
#if 0
|
937 |
if (argc > 1) {
|
1236 |
if (argc > 1) {
|
938 |
cerr << "Usage: thumbpath <filepath>" << endl;
|
1237 |
cerr << "Usage: thumbpath <filepath>" << endl;
|
939 |
exit(1);
|
1238 |
exit(1);
|
940 |
}
|
1239 |
}
|
941 |
string input;
|
1240 |
string input;
|
|
... |
|
... |
963 |
string fn = *argv++;argc--;
|
1262 |
string fn = *argv++;argc--;
|
964 |
string ext = path_suffix(fn);
|
1263 |
string ext = path_suffix(fn);
|
965 |
cout << "Suffix: [" << ext << "]" << endl;
|
1264 |
cout << "Suffix: [" << ext << "]" << endl;
|
966 |
return 0;
|
1265 |
return 0;
|
967 |
#endif
|
1266 |
#endif
|
|
|
1267 |
|
|
|
1268 |
#if 1
|
|
|
1269 |
if (argc != 1) {
|
|
|
1270 |
cerr << "Usage: trpathut url" << endl;
|
|
|
1271 |
exit(1);
|
|
|
1272 |
}
|
|
|
1273 |
string url = *argv++;argc--;
|
|
|
1274 |
|
|
|
1275 |
cout << "File: [" << fileurltolocalpath(url) << "]\n";
|
|
|
1276 |
return 0;
|
|
|
1277 |
#endif
|
|
|
1278 |
|
|
|
1279 |
|
968 |
}
|
1280 |
}
|
969 |
|
1281 |
|
970 |
#endif // TEST_PATHUT
|
1282 |
#endif // TEST_PATHUT
|
971 |
|
1283 |
|