Windows: build with UNICODE, get rid of all TCHAR/TEXT(), use explicit

xxA() interfaces and wchar_t in some places. Add a static cleanup retry
method to TempFile, called after clearing the MimeHandler cache (killing
the subprocesses which might hold an open file).
This commit is contained in:
Jean-Francois Dockes 2019-07-21 16:23:16 +02:00
parent af664e7768
commit 049ba1e7e4
11 changed files with 280 additions and 247 deletions

View File

@ -205,16 +205,16 @@ LRESULT CALLBACK MainWndProc(HWND hwnd , UINT msg , WPARAM wParam,
bool CreateInvisibleWindow() bool CreateInvisibleWindow()
{ {
HWND hwnd; HWND hwnd;
WNDCLASS wc = {0}; WNDCLASS wc = {0,0,0,0,0,0,0,0,0,0};
wc.lpfnWndProc = (WNDPROC)MainWndProc; wc.lpfnWndProc = (WNDPROC)MainWndProc;
wc.hInstance = GetModuleHandle(NULL); wc.hInstance = GetModuleHandle(NULL);
wc.hIcon = LoadIcon(GetModuleHandle(NULL), "TestWClass"); wc.hIcon = LoadIcon(GetModuleHandle(NULL), L"TestWClass");
wc.lpszClassName = "TestWClass"; wc.lpszClassName = L"TestWClass";
RegisterClass(&wc); RegisterClass(&wc);
hwnd = hwnd =
CreateWindowEx(0, "TestWClass", "TestWClass", WS_OVERLAPPEDWINDOW, CreateWindowEx(0, L"TestWClass", L"TestWClass", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, (HWND) NULL, (HMENU) NULL, CW_USEDEFAULT, (HWND) NULL, (HMENU) NULL,
GetModuleHandle(NULL), (LPVOID) NULL); GetModuleHandle(NULL), (LPVOID) NULL);
@ -248,8 +248,8 @@ void initAsyncSigs(void (*sigcleanup)(int))
} }
} }
} }
HANDLE hInvisiblethread =
CreateThread(NULL, 0, RunInvisibleWindowThread, NULL, 0, &tid); CreateThread(NULL, 0, RunInvisibleWindowThread, NULL, 0, &tid);
SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, TRUE); SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, TRUE);
eWorkFinished = CreateEvent(NULL, TRUE, FALSE, NULL); eWorkFinished = CreateEvent(NULL, TRUE, FALSE, NULL);
if (eWorkFinished == INVALID_HANDLE_VALUE) { if (eWorkFinished == INVALID_HANDLE_VALUE) {

View File

@ -43,6 +43,7 @@ using namespace std;
#include "mh_null.h" #include "mh_null.h"
#include "mh_xslt.h" #include "mh_xslt.h"
#include "rcldoc.h" #include "rcldoc.h"
#include "rclutil.h"
// Performance help: we use a pool of already known and created // Performance help: we use a pool of already known and created
// handlers. There can be several instances for a given mime type // handlers. There can be several instances for a given mime type
@ -67,17 +68,17 @@ static RecollFilter *getMimeHandlerFromCache(const string& key)
multimap<string, RecollFilter *>::iterator it = o_handlers.find(key); multimap<string, RecollFilter *>::iterator it = o_handlers.find(key);
if (it != o_handlers.end()) { if (it != o_handlers.end()) {
RecollFilter *h = it->second; RecollFilter *h = it->second;
hlruit_tp it1 = find(o_hlru.begin(), o_hlru.end(), it); hlruit_tp it1 = find(o_hlru.begin(), o_hlru.end(), it);
if (it1 != o_hlru.end()) { if (it1 != o_hlru.end()) {
o_hlru.erase(it1); o_hlru.erase(it1);
} else { } else {
LOGERR("getMimeHandlerFromCache: lru position not found\n"); LOGERR("getMimeHandlerFromCache: lru position not found\n");
} }
o_handlers.erase(it); o_handlers.erase(it);
LOGDEB("getMimeHandlerFromCache: " << xdigest << " found size " << LOGDEB("getMimeHandlerFromCache: " << xdigest << " found size " <<
o_handlers.size() << "\n"); o_handlers.size() << "\n");
return h; return h;
} }
LOGDEB("getMimeHandlerFromCache: " << xdigest << " not found\n"); LOGDEB("getMimeHandlerFromCache: " << xdigest << " not found\n");
return 0; return 0;
@ -89,8 +90,8 @@ void returnMimeHandler(RecollFilter *handler)
typedef multimap<string, RecollFilter*>::value_type value_type; typedef multimap<string, RecollFilter*>::value_type value_type;
if (handler == 0) { if (handler == 0) {
LOGERR("returnMimeHandler: bad parameter\n"); LOGERR("returnMimeHandler: bad parameter\n");
return; return;
} }
handler->clear(); handler->clear();
@ -107,20 +108,20 @@ void returnMimeHandler(RecollFilter *handler)
// are processing the same mime type at the same time. // are processing the same mime type at the same time.
multimap<string, RecollFilter *>::iterator it; multimap<string, RecollFilter *>::iterator it;
if (o_handlers.size() >= max_handlers_cache_size) { if (o_handlers.size() >= max_handlers_cache_size) {
static int once = 1; static int once = 1;
if (once) { if (once) {
once = 0; once = 0;
for (it = o_handlers.begin(); it != o_handlers.end(); it++) { for (it = o_handlers.begin(); it != o_handlers.end(); it++) {
LOGDEB1("Cache full. key: " << it->first << "\n"); LOGDEB1("Cache full. key: " << it->first << "\n");
} }
LOGDEB1("Cache LRU size: " << o_hlru.size() << "\n"); LOGDEB1("Cache LRU size: " << o_hlru.size() << "\n");
} }
if (o_hlru.size() > 0) { if (o_hlru.size() > 0) {
it = o_hlru.back(); it = o_hlru.back();
o_hlru.pop_back(); o_hlru.pop_back();
delete it->second; delete it->second;
o_handlers.erase(it); o_handlers.erase(it);
} }
} }
it = o_handlers.insert(value_type(handler->get_id(), handler)); it = o_handlers.insert(value_type(handler->get_id(), handler));
o_hlru.push_front(it); o_hlru.push_front(it);
@ -132,15 +133,16 @@ void clearMimeHandlerCache()
multimap<string, RecollFilter *>::iterator it; multimap<string, RecollFilter *>::iterator it;
std::unique_lock<std::mutex> locker(o_handlers_mutex); std::unique_lock<std::mutex> locker(o_handlers_mutex);
for (it = o_handlers.begin(); it != o_handlers.end(); it++) { for (it = o_handlers.begin(); it != o_handlers.end(); it++) {
delete it->second; delete it->second;
} }
o_handlers.clear(); o_handlers.clear();
TempFile::tryRemoveAgain();
} }
/** For mime types set as "internal" in mimeconf: /** For mime types set as "internal" in mimeconf:
* create appropriate handler object. */ * create appropriate handler object. */
static RecollFilter *mhFactory(RclConfig *config, const string &mimeOrParams, static RecollFilter *mhFactory(RclConfig *config, const string &mimeOrParams,
bool nobuild, string& id) bool nobuild, string& id)
{ {
LOGDEB1("mhFactory(" << mimeOrParams << ")\n"); LOGDEB1("mhFactory(" << mimeOrParams << ")\n");
vector<string> lparams; vector<string> lparams;
@ -152,50 +154,50 @@ static RecollFilter *mhFactory(RclConfig *config, const string &mimeOrParams,
string lmime(lparams[0]); string lmime(lparams[0]);
stringtolower(lmime); stringtolower(lmime);
if (cstr_textplain == lmime) { if (cstr_textplain == lmime) {
LOGDEB2("mhFactory(" << mime << "): returning MimeHandlerText\n"); LOGDEB2("mhFactory(" << mime << "): returning MimeHandlerText\n");
MD5String("MimeHandlerText", id); MD5String("MimeHandlerText", id);
return nobuild ? 0 : new MimeHandlerText(config, id); return nobuild ? 0 : new MimeHandlerText(config, id);
} else if (cstr_texthtml == lmime) { } else if (cstr_texthtml == lmime) {
LOGDEB2("mhFactory(" << mime << "): returning MimeHandlerHtml\n"); LOGDEB2("mhFactory(" << mime << "): returning MimeHandlerHtml\n");
MD5String("MimeHandlerHtml", id); MD5String("MimeHandlerHtml", id);
return nobuild ? 0 : new MimeHandlerHtml(config, id); return nobuild ? 0 : new MimeHandlerHtml(config, id);
} else if ("text/x-mail" == lmime) { } else if ("text/x-mail" == lmime) {
LOGDEB2("mhFactory(" << mime << "): returning MimeHandlerMbox\n"); LOGDEB2("mhFactory(" << mime << "): returning MimeHandlerMbox\n");
MD5String("MimeHandlerMbox", id); MD5String("MimeHandlerMbox", id);
return nobuild ? 0 : new MimeHandlerMbox(config, id); return nobuild ? 0 : new MimeHandlerMbox(config, id);
} else if ("message/rfc822" == lmime) { } else if ("message/rfc822" == lmime) {
LOGDEB2("mhFactory(" << mime << "): returning MimeHandlerMail\n"); LOGDEB2("mhFactory(" << mime << "): returning MimeHandlerMail\n");
MD5String("MimeHandlerMail", id); MD5String("MimeHandlerMail", id);
return nobuild ? 0 : new MimeHandlerMail(config, id); return nobuild ? 0 : new MimeHandlerMail(config, id);
} else if ("inode/symlink" == lmime) { } else if ("inode/symlink" == lmime) {
LOGDEB2("mhFactory(" << mime << "): returning MimeHandlerSymlink\n"); LOGDEB2("mhFactory(" << mime << "): returning MimeHandlerSymlink\n");
MD5String("MimeHandlerSymlink", id); MD5String("MimeHandlerSymlink", id);
return nobuild ? 0 : new MimeHandlerSymlink(config, id); return nobuild ? 0 : new MimeHandlerSymlink(config, id);
} else if ("application/x-zerosize" == lmime) { } else if ("application/x-zerosize" == lmime) {
LOGDEB("mhFactory(" << lmime << "): returning MimeHandlerNull\n"); LOGDEB("mhFactory(" << lmime << "): returning MimeHandlerNull\n");
MD5String("MimeHandlerNull", id); MD5String("MimeHandlerNull", id);
return nobuild ? 0 : new MimeHandlerNull(config, id); return nobuild ? 0 : new MimeHandlerNull(config, id);
} else if (lmime.find("text/") == 0) { } else if (lmime.find("text/") == 0) {
// Try to handle unknown text/xx as text/plain. This // Try to handle unknown text/xx as text/plain. This
// only happen if the text/xx was defined as "internal" in // only happen if the text/xx was defined as "internal" in
// mimeconf, not at random. For programs, for example this // mimeconf, not at random. For programs, for example this
// allows indexing and previewing as text/plain (no filter // allows indexing and previewing as text/plain (no filter
// exec) but still opening with a specific editor. // exec) but still opening with a specific editor.
LOGDEB2("mhFactory(" << mime << "): returning MimeHandlerText(x)\n"); LOGDEB2("mhFactory(" << mime << "): returning MimeHandlerText(x)\n");
MD5String("MimeHandlerText", id); MD5String("MimeHandlerText", id);
return nobuild ? 0 : new MimeHandlerText(config, id); return nobuild ? 0 : new MimeHandlerText(config, id);
} else if ("xsltproc" == lmime) { } else if ("xsltproc" == lmime) {
// XML Types processed with one or several xslt style sheets. // XML Types processed with one or several xslt style sheets.
MD5String(mimeOrParams, id); MD5String(mimeOrParams, id);
return nobuild ? 0 : new MimeHandlerXslt(config, id, lparams); return nobuild ? 0 : new MimeHandlerXslt(config, id, lparams);
} else { } else {
// We should not get there. It means that "internal" was set // We should not get there. It means that "internal" was set
// as a handler in mimeconf for a mime type we actually can't // as a handler in mimeconf for a mime type we actually can't
// handle. // handle.
LOGERR("mhFactory: mime type [" << lmime << LOGERR("mhFactory: mime type [" << lmime <<
"] set as internal but unknown\n"); "] set as internal but unknown\n");
MD5String("MimeHandlerUnknown", id); MD5String("MimeHandlerUnknown", id);
return nobuild ? 0 : new MimeHandlerUnknown(config, id); return nobuild ? 0 : new MimeHandlerUnknown(config, id);
} }
} }
@ -216,7 +218,7 @@ MimeHandlerExec *mhExecFactory(RclConfig *cfg, const string& mtype, string& hs,
string cmdstr; string cmdstr;
if (!cfg->valueSplitAttributes(hs, cmdstr, attrs)) { if (!cfg->valueSplitAttributes(hs, cmdstr, attrs)) {
LOGERR("mhExecFactory: bad config line for [" << LOGERR("mhExecFactory: bad config line for [" <<
mtype << "]: [" << hs << "]\n"); mtype << "]: [" << hs << "]\n");
return 0; return 0;
} }
@ -225,12 +227,12 @@ MimeHandlerExec *mhExecFactory(RclConfig *cfg, const string& mtype, string& hs,
vector<string> cmdtoks; vector<string> cmdtoks;
stringToStrings(cmdstr, cmdtoks); stringToStrings(cmdstr, cmdtoks);
if (cmdtoks.empty()) { if (cmdtoks.empty()) {
LOGERR("mhExecFactory: bad config line for [" << mtype << LOGERR("mhExecFactory: bad config line for [" << mtype <<
"]: [" << hs << "]\n"); "]: [" << hs << "]\n");
return 0; return 0;
} }
MimeHandlerExec *h = multiple ? MimeHandlerExec *h = multiple ?
new MimeHandlerExecMultiple(cfg, id) : new MimeHandlerExecMultiple(cfg, id) :
new MimeHandlerExec(cfg, id); new MimeHandlerExec(cfg, id);
vector<string>::iterator it = cmdtoks.begin(); vector<string>::iterator it = cmdtoks.begin();
@ -262,7 +264,7 @@ MimeHandlerExec *mhExecFactory(RclConfig *cfg, const string& mtype, string& hs,
#if 0 #if 0
string scmd; string scmd;
for (it = h->params.begin(); it != h->params.end(); it++) { for (it = h->params.begin(); it != h->params.end(); it++) {
scmd += string("[") + *it + "] "; scmd += string("[") + *it + "] ";
} }
LOGDEB("mhExecFactory:mt [" << mtype << "] cfgmt [" << LOGDEB("mhExecFactory:mt [" << mtype << "] cfgmt [" <<
h->cfgFilterOutputMtype << "] cfgcs [" << h->cfgFilterOutputMtype << "] cfgcs [" <<
@ -291,83 +293,83 @@ RecollFilter *getMimeHandler(const string &mtype, RclConfig *cfg,
string id; string id;
if (!hs.empty()) { if (!hs.empty()) {
// Got a handler definition line // Got a handler definition line
// Break definition into type (internal/exec/execm) // Break definition into type (internal/exec/execm)
// and name/command string // and name/command string
string::size_type b1 = hs.find_first_of(" \t"); string::size_type b1 = hs.find_first_of(" \t");
string handlertype = hs.substr(0, b1); string handlertype = hs.substr(0, b1);
string cmdstr; string cmdstr;
if (b1 != string::npos) { if (b1 != string::npos) {
cmdstr = hs.substr(b1); cmdstr = hs.substr(b1);
trimstring(cmdstr); trimstring(cmdstr);
} }
bool internal = !stringlowercmp("internal", handlertype); bool internal = !stringlowercmp("internal", handlertype);
if (internal) { if (internal) {
// For internal types let the factory compute the cache id // For internal types let the factory compute the cache id
mhFactory(cfg, cmdstr.empty() ? mtype : cmdstr, true, id); mhFactory(cfg, cmdstr.empty() ? mtype : cmdstr, true, id);
} else { } else {
// exec/execm: use the md5 of the def line // exec/execm: use the md5 of the def line
MD5String(hs, id); MD5String(hs, id);
} }
// Do we already have a handler object in the cache ? // Do we already have a handler object in the cache ?
h = getMimeHandlerFromCache(id); h = getMimeHandlerFromCache(id);
if (h != 0) if (h != 0)
goto out; goto out;
LOGDEB2("getMimeHandler: " << mtype << " not in cache\n"); LOGDEB2("getMimeHandler: " << mtype << " not in cache\n");
if (internal) { if (internal) {
// If there is a parameter after "internal" it's the mime // If there is a parameter after "internal" it's the mime
// type to use, or the further qualifier (e.g. style sheet // type to use, or the further qualifier (e.g. style sheet
// name for xslt types). This is so that we can have bogus // name for xslt types). This is so that we can have bogus
// mime types like text/x-purple-html-log (for ie: // mime types like text/x-purple-html-log (for ie:
// specific icon) and still use the html filter on // specific icon) and still use the html filter on
// them. This is partly redundant with the // them. This is partly redundant with the
// localfields/rclaptg, but better? (and the latter will // localfields/rclaptg, but better? (and the latter will
// probably go away at some point in the future?). // probably go away at some point in the future?).
LOGDEB2("handlertype internal, cmdstr [" << cmdstr << "]\n"); LOGDEB2("handlertype internal, cmdstr [" << cmdstr << "]\n");
h = mhFactory(cfg, cmdstr.empty() ? mtype : cmdstr, false, id); h = mhFactory(cfg, cmdstr.empty() ? mtype : cmdstr, false, id);
goto out; goto out;
} else if (!stringlowercmp("dll", handlertype)) { } else if (!stringlowercmp("dll", handlertype)) {
} else { } else {
if (cmdstr.empty()) { if (cmdstr.empty()) {
LOGERR("getMimeHandler: bad line for " << mtype << ": " << LOGERR("getMimeHandler: bad line for " << mtype << ": " <<
hs << "\n"); hs << "\n");
goto out; goto out;
} }
if (!stringlowercmp("exec", handlertype)) { if (!stringlowercmp("exec", handlertype)) {
h = mhExecFactory(cfg, mtype, cmdstr, false, id); h = mhExecFactory(cfg, mtype, cmdstr, false, id);
goto out; goto out;
} else if (!stringlowercmp("execm", handlertype)) { } else if (!stringlowercmp("execm", handlertype)) {
h = mhExecFactory(cfg, mtype, cmdstr, true, id); h = mhExecFactory(cfg, mtype, cmdstr, true, id);
goto out; goto out;
} else { } else {
LOGERR("getMimeHandler: bad line for " << mtype << ": " << LOGERR("getMimeHandler: bad line for " << mtype << ": " <<
hs << "\n"); hs << "\n");
goto out; goto out;
} }
} }
} else { } else {
// No identified mime type, or no handler associated. // No identified mime type, or no handler associated.
// Unhandled files are either ignored or their name and // Unhandled files are either ignored or their name and
// generic metadata is indexed, depending on configuration // generic metadata is indexed, depending on configuration
bool indexunknown = false; bool indexunknown = false;
cfg->getConfParam("indexallfilenames", &indexunknown); cfg->getConfParam("indexallfilenames", &indexunknown);
if (indexunknown) { if (indexunknown) {
MD5String("MimeHandlerUnknown", id); MD5String("MimeHandlerUnknown", id);
if ((h = getMimeHandlerFromCache(id)) == 0) if ((h = getMimeHandlerFromCache(id)) == 0)
h = new MimeHandlerUnknown(cfg, id); h = new MimeHandlerUnknown(cfg, id);
} }
goto out; goto out;
} }
out: out:
if (h) { if (h) {
h->set_property(RecollFilter::DEFAULT_CHARSET, cfg->getDefCharset()); h->set_property(RecollFilter::DEFAULT_CHARSET, cfg->getDefCharset());
// In multithread context, and in case this handler is out // In multithread context, and in case this handler is out
// from the cache, it may have a config pointer belonging to // from the cache, it may have a config pointer belonging to
// another thread. Fix it. // another thread. Fix it.
h->setConfig(cfg); h->setConfig(cfg);
} }
return h; return h;
} }
@ -376,10 +378,10 @@ out:
bool canIntern(const std::string mtype, RclConfig *cfg) bool canIntern(const std::string mtype, RclConfig *cfg)
{ {
if (mtype.empty()) if (mtype.empty())
return false; return false;
string hs = cfg->getMimeHandlerDef(mtype); string hs = cfg->getMimeHandlerDef(mtype);
if (hs.empty()) if (hs.empty())
return false; return false;
return true; return true;
} }
/// Same, getting MIME from doc /// Same, getting MIME from doc

View File

@ -0,0 +1,51 @@
#include "rclutil.h"
void path_to_thumb(const string& _input)
{
string input(_input);
// Make absolute path if needed
if (input[0] != '/') {
input = path_absolute(input);
}
input = string("file://") + path_canon(input);
string path;
//path = url_encode(input, 7);
thumbPathForUrl(input, 7, path);
cout << path << endl;
}
const char *thisprog;
int main(int argc, const char **argv)
{
thisprog = *argv++;
argc--;
string s;
vector<string>::const_iterator it;
#if 0
if (argc > 1) {
cerr << "Usage: thumbpath <filepath>" << endl;
exit(1);
}
string input;
if (argc == 1) {
input = *argv++;
if (input.empty()) {
cerr << "Usage: thumbpath <filepath>" << endl;
exit(1);
}
path_to_thumb(input);
} else {
while (getline(cin, input)) {
path_to_thumb(input);
}
}
exit(0);
#endif
}

View File

@ -274,8 +274,8 @@ bool fsocc(const string& path, int *pc, long long *avmbs)
#ifdef _WIN32 #ifdef _WIN32
ULARGE_INTEGER freebytesavail; ULARGE_INTEGER freebytesavail;
ULARGE_INTEGER totalbytes; ULARGE_INTEGER totalbytes;
if (!GetDiskFreeSpaceEx(path.c_str(), &freebytesavail, if (!GetDiskFreeSpaceExA(path.c_str(), &freebytesavail,
&totalbytes, NULL)) { &totalbytes, NULL)) {
return false; return false;
} }
if (pc) { if (pc) {

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2016 J.F.Dockes /* Copyright (C) 2016-2019 J.F.Dockes
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or * the Free Software Foundation; either version 2 of the License, or
@ -14,7 +14,7 @@
* Free Software Foundation, Inc., * Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#ifndef TEST_RCLUTIL
#include "autoconfig.h" #include "autoconfig.h"
#include <stdio.h> #include <stdio.h>
@ -39,6 +39,7 @@
#include <mutex> #include <mutex>
#include <map> #include <map>
#include <unordered_map> #include <unordered_map>
#include <list>
#include "rclutil.h" #include "rclutil.h"
#include "pathut.h" #include "pathut.h"
@ -50,7 +51,6 @@
using namespace std; using namespace std;
template <class T> void map_ss_cp_noshr(T s, T *d) template <class T> void map_ss_cp_noshr(T s, T *d)
{ {
for (const auto& ent : s) { for (const auto& ent : s) {
@ -83,54 +83,48 @@ static bool path_isdriveabs(const string& s)
#include <Shlwapi.h> #include <Shlwapi.h>
#pragma comment(lib, "shlwapi.lib") #pragma comment(lib, "shlwapi.lib")
string path_tchartoutf8(TCHAR *text)
{
#ifdef UNICODE
// Simple C
// const size_t size = ( wcslen(text) + 1 ) * sizeof(wchar_t);
// wcstombs(&buffer[0], text, size);
// std::vector<char> buffer(size);
// Or:
// Windows API
std::vector<char> buffer;
int size = WideCharToMultiByte(CP_UTF8, 0, text, -1, NULL, 0, NULL, NULL);
if (size > 0) {
buffer.resize(size);
WideCharToMultiByte(CP_UTF8, 0, text, -1,
&buffer[0], int(buffer.size()), NULL, NULL);
} else {
return string();
}
return string(&buffer[0]);
#else
return text;
#endif
}
string path_thisexecpath() string path_thisexecpath()
{ {
TCHAR text[MAX_PATH]; wchar_t text[MAX_PATH];
GetModuleFileName(NULL, text, MAX_PATH); GetModuleFileNameW(NULL, text, MAX_PATH);
#ifdef NTDDI_WIN8_future #ifdef NTDDI_WIN8_future
PathCchRemoveFileSpec(text, MAX_PATH); PathCchRemoveFileSpec(text, MAX_PATH);
#else #else
PathRemoveFileSpec(text); PathRemoveFileSpecW(text);
#endif #endif
string path = path_tchartoutf8(text); string path;
wchartoutf8(text, path);
if (path.empty()) { if (path.empty()) {
path = "c:/"; path = "c:/";
} }
return path; return path;
} }
string path_wingettempfilename(TCHAR *pref) string path_wingettempfilename(wchar_t *pref)
{ {
TCHAR buf[(MAX_PATH + 1)*sizeof(TCHAR)]; // Use a subdirectory named "rcltmp" inside the windows temp
TCHAR dbuf[(MAX_PATH + 1)*sizeof(TCHAR)]; // location.
GetTempPath(MAX_PATH + 1, dbuf); wchar_t dbuf[MAX_PATH + 1];
GetTempFileName(dbuf, pref, 0, buf); GetTempPathW(MAX_PATH + 1, dbuf);
string tdir;
wchartoutf8(dbuf, tdir);
tdir = path_cat(tdir, "rcltmp");;
if (!path_exists(tdir)) {
if (path_makepath(tdir, 0700)) {
LOGSYSERR("path_wingettempfilename", "path_makepath", tdir);
}
}
utf8towchar(tdir, dbuf, MAX_PATH);
wchar_t buf[MAX_PATH + 1];
GetTempFileNameW(dbuf, pref, 0, buf);
// Windows will have created a temp file, we delete it. // Windows will have created a temp file, we delete it.
string filename = path_tchartoutf8(buf); if (!DeleteFileW(buf)) {
unlink(filename.c_str()); LOGSYSERR("path_wingettempfilename", "DeleteFileW", filename);
} else {
LOGDEB1("path_wingettempfilename: DeleteFile " << filename << " Ok\n");
}
string filename;
wchartoutf8(buf, filename);
path_slashize(filename); path_slashize(filename);
return filename; return filename;
} }
@ -235,9 +229,9 @@ const string& tmplocation()
} }
if (tmpdir == 0) { if (tmpdir == 0) {
#ifdef _WIN32 #ifdef _WIN32
TCHAR bufw[(MAX_PATH + 1)*sizeof(TCHAR)]; wchar_t bufw[MAX_PATH + 1];
GetTempPath(MAX_PATH + 1, bufw); GetTempPathW(MAX_PATH + 1, bufw);
stmpdir = path_tchartoutf8(bufw); wchartoutf8(bufw, stmpdir);
#else #else
stmpdir = "/tmp"; stmpdir = "/tmp";
#endif #endif
@ -267,19 +261,19 @@ bool maketmpdir(string& tdir, string& reason)
// in the foot // in the foot
#if !defined(HAVE_MKDTEMP) || defined(_WIN32) #if !defined(HAVE_MKDTEMP) || defined(_WIN32)
static std::mutex mmutex; static std::mutex mmutex;
std::unique_lock lock(mmutex); std::unique_lock<std::mutex> lock(mmutex);
#endif #endif
if (! if (!
#ifdef HAVE_MKDTEMP #ifdef HAVE_MKDTEMP
mkdtemp(cp) mkdtemp(cp)
#else #else
mktemp(cp) mktemp(cp)
#endif // HAVE_MKDTEMP #endif // HAVE_MKDTEMP
) { ) {
free(cp); free(cp);
reason = "maketmpdir: mktemp failed for [" + tdir + "] : " + reason = "maketmpdir: mktemp failed for [" + tdir + "] : " +
strerror(errno); strerror(errno);
tdir.erase(); tdir.erase();
return false; return false;
} }
@ -291,7 +285,8 @@ bool maketmpdir(string& tdir, string& reason)
// in the foot // in the foot
static std::mutex mmutex; static std::mutex mmutex;
std::unique_lock<std::mutex> lock(mmutex); std::unique_lock<std::mutex> lock(mmutex);
tdir = path_wingettempfilename(TEXT("rcltmp")); static wchar_t tmpbasename[]{L"rcltmp"};
tdir = path_wingettempfilename(tmpbasename);
#endif #endif
// At this point the directory does not exist yet except if we used // At this point the directory does not exist yet except if we used
@ -382,10 +377,12 @@ TempFile::Internal::Internal(const string& suffix)
filename = cp; filename = cp;
free(cp); free(cp);
#else #else
string filename = path_wingettempfilename(TEXT("recoll")); static wchar_t tmpbasename[]{L"rcl"};
string filename = path_wingettempfilename(tmpbasename);
#endif #endif
m_filename = filename + suffix; m_filename = filename + suffix;
LOGDEB1("TempFile: filename: " << m_filename << endl);
int fd1 = open(m_filename.c_str(), O_CREAT | O_EXCL, 0600); int fd1 = open(m_filename.c_str(), O_CREAT | O_EXCL, 0600);
if (fd1 < 0) { if (fd1 < 0) {
m_reason = string("Open/create error. errno : ") + m_reason = string("Open/create error. errno : ") +
@ -396,13 +393,51 @@ TempFile::Internal::Internal(const string& suffix)
} }
} }
#ifdef _WIN32
static list<string> remainingTempFileNames;
static std::mutex remTmpFNMutex;
#endif
TempFile::Internal::~Internal() TempFile::Internal::~Internal()
{ {
if (!m_filename.empty() && !m_noremove) { if (!m_filename.empty() && !m_noremove) {
unlink(m_filename.c_str()); LOGDEB1("TempFile:~: unlinking " << m_filename << endl);
if (unlink(m_filename.c_str()) != 0) {
LOGSYSERR("TempFile:~", "unlink", m_filename);
#ifdef _WIN32
{
std::unique_lock<std::mutex> lock(remTmpFNMutex);
remainingTempFileNames.push_back(m_filename);
}
#endif
} else {
LOGDEB1("TempFile:~: unlink " << m_filename << " Ok\n");
}
} }
} }
// On Windows we sometimes fail to remove temporary files because
// they are open. It's difficult to make sure this does not
// happen, so we add a cleaning pass after clearing the input
// handlers cache (which should kill subprocesses etc.)
void TempFile::tryRemoveAgain()
{
#ifdef _WIN32
LOGDEB1("TempFile::tryRemoveAgain. List size: " <<
remainingTempFileNames.size() << endl);
std::unique_lock<std::mutex> lock(remTmpFNMutex);
std::list<string>::iterator pos = remainingTempFileNames.begin();
while (pos != remainingTempFileNames.end()) {
if (unlink(pos->c_str()) != 0) {
LOGSYSERR("TempFile::tryRemoveAgain", "unlink", *pos);
pos++;
} else {
pos = remainingTempFileNames.erase(pos);
}
}
#endif
}
TempDir::TempDir() TempDir::TempDir()
{ {
if (!maketmpdir(m_dirname, m_reason)) { if (!maketmpdir(m_dirname, m_reason)) {
@ -448,6 +483,7 @@ static const string& xdgcachedir()
} }
return xdgcache; return xdgcache;
} }
static const string& thumbnailsdir() static const string& thumbnailsdir()
{ {
static string thumbnailsd; static string thumbnailsd;
@ -506,56 +542,3 @@ void rclutil_init_mt()
tmplocation(); tmplocation();
thumbnailsdir(); thumbnailsdir();
} }
#else // TEST_RCLUTIL
void path_to_thumb(const string& _input)
{
string input(_input);
// Make absolute path if needed
if (input[0] != '/') {
input = path_absolute(input);
}
input = string("file://") + path_canon(input);
string path;
//path = url_encode(input, 7);
thumbPathForUrl(input, 7, path);
cout << path << endl;
}
const char *thisprog;
int main(int argc, const char **argv)
{
thisprog = *argv++;
argc--;
string s;
vector<string>::const_iterator it;
#if 0
if (argc > 1) {
cerr << "Usage: thumbpath <filepath>" << endl;
exit(1);
}
string input;
if (argc == 1) {
input = *argv++;
if (input.empty()) {
cerr << "Usage: thumbpath <filepath>" << endl;
exit(1);
}
path_to_thumb(input);
} else {
while (getline(cin, input)) {
path_to_thumb(input);
}
}
exit(0);
#endif
}
#endif // TEST_RCLUTIL

View File

@ -58,6 +58,11 @@ public:
const std::string& getreason() const; const std::string& getreason() const;
void setnoremove(bool onoff); void setnoremove(bool onoff);
bool ok() const; bool ok() const;
// Attempt to delete all files which could not be deleted on the
// first try (typically on Windows: because they are open by some
// process). Called after clearing the mimeHandler cache. Does
// nothing if not _WIN32
static void tryRemoveAgain();
class Internal; class Internal;
private: private:
std::shared_ptr<Internal> m; std::shared_ptr<Internal> m;

View File

@ -108,6 +108,13 @@ static string argvToCmdLine(const string& cmd, const vector<string>& args)
return cmdline; return cmdline;
} }
// Because we build with UNICODE defined, GetEnvironmentStrings is
// defined as GetEnvironmentStringsW. Because of a Windows problem teh
// GetEnvironmentStrings function is really a GetEnvironmentStringsA,
// which is what we want.
// See: https://devblogs.microsoft.com/oldnewthing/20130117-00/?p=5533
#undef GetEnvironmentStrings
// Merge the father environment with the variable specified in m_env // Merge the father environment with the variable specified in m_env
static char *mergeEnvironment(const std::unordered_map<string, string>& addenv) static char *mergeEnvironment(const std::unordered_map<string, string>& addenv)
{ {
@ -131,7 +138,7 @@ static char *mergeEnvironment(const std::unordered_map<string, string>& addenv)
} }
} }
FreeEnvironmentStrings(envir); FreeEnvironmentStringsA(envir);
// Merge our values // Merge our values
for (auto it = addenv.begin(); it != addenv.end(); it++) { for (auto it = addenv.begin(); it != addenv.end(); it++) {
@ -614,7 +621,7 @@ bool ExecCmd::Internal::preparePipes(bool has_input,HANDLE *hChildInput,
// attribute, and the options are important. // attribute, and the options are important.
// use CreateFile to open a new handle to the existing pipe... // use CreateFile to open a new handle to the existing pipe...
sa.bInheritHandle = TRUE; sa.bInheritHandle = TRUE;
hOutputWrite = CreateFile( hOutputWrite = CreateFileA(
pipeName.c_str(), pipeName.c_str(),
FILE_WRITE_DATA | SYNCHRONIZE, FILE_WRITE_DATA | SYNCHRONIZE,
0, &sa, OPEN_EXISTING, // very important flag! 0, &sa, OPEN_EXISTING, // very important flag!
@ -659,7 +666,7 @@ bool ExecCmd::Internal::preparePipes(bool has_input,HANDLE *hChildInput,
} }
sa.bInheritHandle = TRUE; sa.bInheritHandle = TRUE;
hInputRead = CreateFile( hInputRead = CreateFileA(
pipeName.c_str(), pipeName.c_str(),
FILE_READ_DATA | SYNCHRONIZE, FILE_READ_DATA | SYNCHRONIZE,
0, &sa, OPEN_EXISTING, // very important flag! 0, &sa, OPEN_EXISTING, // very important flag!
@ -782,13 +789,7 @@ int ExecCmd::startExec(const string &cmd, const vector<string>& args,
char *envir = mergeEnvironment(m->m_env); char *envir = mergeEnvironment(m->m_env);
// Create the child process. // Create the child process.
// Need a writable buffer for the command line, for some reason.
LOGDEB("ExecCmd:startExec: cmdline [" << cmdline << "]\n"); LOGDEB("ExecCmd:startExec: cmdline [" << cmdline << "]\n");
#if 0
LPSTR buf = (LPSTR)malloc(cmdline.size() + 1);
memcpy(buf, cmdline.c_str(), cmdline.size());
buf[cmdline.size()] = 0;
#endif
SYSPATH(cmdline, wcmdline); SYSPATH(cmdline, wcmdline);
bSuccess = CreateProcessW(NULL, bSuccess = CreateProcessW(NULL,
wcmdline, // command line wcmdline, // command line
@ -805,7 +806,6 @@ int ExecCmd::startExec(const string &cmd, const vector<string>& args,
} }
free(envir); free(envir);
// free(buf);
// Close child-side handles else we'll never see eofs // Close child-side handles else we'll never see eofs
if (!CloseHandle(hOutputWrite)) if (!CloseHandle(hOutputWrite))
printError("CloseHandle"); printError("CloseHandle");

View File

@ -10,9 +10,7 @@ TARGET = librecoll
TEMPLATE = lib TEMPLATE = lib
DEFINES += LIBRECOLL_LIBRARY BUILDING_RECOLL DEFINES += LIBRECOLL_LIBRARY BUILDING_RECOLL
DEFINES -= UNICODE DEFINES += UNICODE
DEFINES -= _UNICODE
DEFINES += _MBCS
DEFINES += PSAPI_VERSION=1 DEFINES += PSAPI_VERSION=1
DEFINES += READFILE_ENABLE_MINIZ DEFINES += READFILE_ENABLE_MINIZ
DEFINES += READFILE_ENABLE_MD5 DEFINES += READFILE_ENABLE_MD5

View File

@ -5,9 +5,7 @@ TARGET = rclstartw
TEMPLATE = app TEMPLATE = app
DEFINES += BUILDING_RECOLL DEFINES += BUILDING_RECOLL
DEFINES -= UNICODE DEFINES += UNICODE
DEFINES -= _UNICODE
DEFINES += _MBCS
DEFINES += PSAPI_VERSION=1 DEFINES += PSAPI_VERSION=1

View File

@ -7,9 +7,7 @@ CONFIG -= app_bundle
TEMPLATE = app TEMPLATE = app
DEFINES += BUILDING_RECOLL DEFINES += BUILDING_RECOLL
DEFINES -= UNICODE DEFINES += UNICODE
DEFINES -= _UNICODE
DEFINES += _MBCS
DEFINES += PSAPI_VERSION=1 DEFINES += PSAPI_VERSION=1
DEFINES += RCL_MONITOR DEFINES += RCL_MONITOR

View File

@ -7,9 +7,7 @@ CONFIG -= app_bundle
TEMPLATE = app TEMPLATE = app
DEFINES += BUILDING_RECOLL DEFINES += BUILDING_RECOLL
DEFINES -= UNICODE DEFINES += UNICODE
DEFINES -= _UNICODE
DEFINES += _MBCS
DEFINES += PSAPI_VERSION=1 DEFINES += PSAPI_VERSION=1