Exemplo n.º 1
0
Zstring zen::getFormattedDirectoryPath(const Zstring& dirpassPhrase) // throw()
{
    //formatting is needed since functions expect the directory to end with '\' to be able to split the relative names.

    Zstring dirpath = dirpassPhrase;

    //remove leading/trailing whitespace before allowing misinterpretation in applyLongPathPrefix()
    trim(dirpath, true, false);
    while (endsWith(dirpath, Zstr(' '))) //don't remove all whitespace from right, e.g. 0xa0 may be used as part of dir name
        dirpath.resize(dirpath.size() - 1);

    if (dirpath.empty()) //an empty string would later be resolved as "\"; this is not desired
        return Zstring();

    dirpath = expandMacros(dirpath);
    dirpath = expandVolumeName(dirpath); //may block for slow USB sticks!
    /*
    need to resolve relative paths:
    WINDOWS:
     - \\?\-prefix which needs absolute names
     - Volume Shadow Copy: volume name needs to be part of each file path
     - file icon buffer (at least for extensions that are actually read from disk, like "exe")
     - ::SHFileOperation(): Using relative path names is not thread safe
    WINDOWS/LINUX:
     - detection of dependent directories, e.g. "\" and "C:\test"
     */
    dirpath = resolveRelativePath(dirpath);

    return appendSeparator(dirpath);
}
Exemplo n.º 2
0
void zen::recycleOrDelete(const std::vector<Zstring>& itempaths, const std::function<void (const std::wstring& displayPath)>& onRecycleItem)
{
    if (itempaths.empty()) return;
    //warning: moving long file paths to recycler does not work!
    //both ::SHFileOperation() and ::IFileOperation cannot delete a folder named "System Volume Information" with normal attributes but shamelessly report success
    //both ::SHFileOperation() and ::IFileOperation can't handle \\?\-prefix!

    /*
    Performance test: delete 1000 files
    ------------------------------------
    SHFileOperation - single file     33s
    SHFileOperation - multiple files  2,1s
    IFileOperation  - single file     33s
    IFileOperation  - multiple files  2,1s

    => SHFileOperation and IFileOperation have nearly IDENTICAL performance characteristics!

    Nevertheless, let's use IFileOperation for better error reporting (including details on locked files)!
    */
#ifdef ZEN_WIN_VISTA_AND_LATER
    vista::moveToRecycleBin(itempaths, onRecycleItem); //throw FileError

#else //regular recycle bin usage: available since XP: 1. bad error reporting 2. early failure
    Zstring itempathsDoubleNull;
    for (const Zstring& itempath : itempaths)
    {
        itempathsDoubleNull += itempath;
        itempathsDoubleNull += L'\0';
    }

    SHFILEOPSTRUCT fileOp = {};
    fileOp.hwnd   = nullptr;
    fileOp.wFunc  = FO_DELETE;
    fileOp.pFrom  = itempathsDoubleNull.c_str();
    fileOp.pTo    = nullptr;
    fileOp.fFlags = FOF_ALLOWUNDO | FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOERRORUI;
    fileOp.fAnyOperationsAborted = false;
    fileOp.hNameMappings         = nullptr;
    fileOp.lpszProgressTitle     = nullptr;

    //"You should use fully-qualified path names with this function. Using it with relative path names is not thread safe."
    if (::SHFileOperation(&fileOp) != 0 || fileOp.fAnyOperationsAborted)
    {
        std::wstring itempathFmt = fmtPath(itempaths[0]); //probably not the correct file name for file lists larger than 1!
        if (itempaths.size() > 1)
            itempathFmt += L", ..."; //give at least some hint that there are multiple files, and the error need not be related to the first one
        throw FileError(replaceCpy(_("Unable to move %x to the recycle bin."), L"%x", itempathFmt));
    }
#endif
}
Exemplo n.º 3
0
std::vector<Zstring> zen::getDirectoryAliases(const Zstring& dirpathPhrase)
{
    Zstring dirpath = dirpathPhrase;
    trim(dirpath, true, false);
    if (dirpath.empty())
        return std::vector<Zstring>();

    std::set<Zstring, LessFilename> tmp;
    getDirectoryAliasesRecursive(dirpath, tmp);

    tmp.erase(dirpath);
    tmp.erase(Zstring());

    return std::vector<Zstring>(tmp.begin(), tmp.end());
}
Exemplo n.º 4
0
bool zen::recycleOrDelete(const Zstring& itempath) //throw FileError
{
    if (!somethingExists(itempath)) //[!] do not optimize away, OS X needs this for reliable detection of "recycle bin missing"
        return false; //neither file nor any other object with that name existing: no error situation, manual deletion relies on it!

#ifdef ZEN_WIN
    recycleOrDelete({ itempath }, nullptr); //throw FileError

#elif defined ZEN_LINUX
    GFile* file = ::g_file_new_for_path(itempath.c_str()); //never fails according to docu
    ZEN_ON_SCOPE_EXIT(g_object_unref(file);)
Exemplo n.º 5
0
Zstring makeUpperCopy(const Zstring& str)
{
    const int len = static_cast<int>(str.size());

    if (len == 0) //LCMapString does not allow input sizes of 0!
        return str;

    Zstring output = str;

    //LOCALE_INVARIANT is NOT available with Windows 2000 -> ok

    //use Windows' upper case conversion: faster than ::CharUpper()
    if (::LCMapString(LOCALE_INVARIANT, //__in   LCID Locale,
                      LCMAP_UPPERCASE,  //__in   DWORD dwMapFlags,
                      str.c_str(),      //__in   LPCTSTR lpSrcStr,
                      len,              //__in   int cchSrc,
                      &*output.begin(), //__out  LPTSTR lpDestStr,
                      len) == 0)        //__in   int cchDest
        throw std::runtime_error("Error comparing strings (LCMapString). " + std::string(__FILE__) + ":" + numberTo<std::string>(__LINE__));

    return output;
}
Exemplo n.º 6
0
void OnCompletionBox::addItemHistory()
{
    const Zstring command = trimCpy(getValue());

    if (command == utfCvrtTo<Zstring>(separationLine) || //do not add sep. line
        command == utfCvrtTo<Zstring>(cmdTxtCloseProgressDlg) || //do not add special command
        command.empty())
        return;

    //do not add built-in commands to history
    for (const auto& item : defaultCommands)
        if (command == utfCvrtTo<Zstring>(item.first) ||
            equalFilePath(command, item.second))
            return;

    erase_if(history_, [&](const Zstring& item) { return equalFilePath(command, item); });

    history_.insert(history_.begin(), command);

    if (history_.size() > historyMax_)
        history_.resize(historyMax_);
}
Exemplo n.º 7
0
    //used during folder creation if parent folder is missing
    Opt<Zstring> getParentFolderPathImpl(const Zstring& itemPathImpl) const override
    {
#ifdef ZEN_WIN
        //remove trailing separator (even for C:\ root directories)
        const Zstring itemPathFmt = endsWith(itemPathImpl, FILE_NAME_SEPARATOR) ?
                                    beforeLast(itemPathImpl, FILE_NAME_SEPARATOR, IF_MISSING_RETURN_NONE) :
                                    itemPathImpl;

        const Zstring parentDir = beforeLast(itemPathFmt, FILE_NAME_SEPARATOR, IF_MISSING_RETURN_NONE);
        if (parentDir.empty())
            return NoValue();
        if (parentDir.size() == 2 && isAlpha(parentDir[0]) && parentDir[1] == L':')
            return appendSeparator(parentDir);

#elif defined ZEN_LINUX || defined ZEN_MAC
        if (itemPathImpl == "/")
            return NoValue();

        const Zstring parentDir = beforeLast(itemPathImpl, FILE_NAME_SEPARATOR, IF_MISSING_RETURN_NONE);
        if (parentDir.empty())
            return Zstring("/");
#endif
        return parentDir;
    }
Exemplo n.º 8
0
Zstring makeUpperCopy(const Zstring& str)
{
    const size_t len = str.size();

    Zstring output;
    output.resize(len);

    std::transform(str.begin(), str.end(), output.begin(), [](char c) {
        return static_cast<char>(::toupper(static_cast<unsigned char>(c)));
    }); //locale-dependent!

    //result of toupper() is an unsigned char mapped to int range, so the char representation is in the last 8 bits and we need not care about signedness!
    //this should work for UTF-8, too: all chars >= 128 are mapped upon themselves!

    return output;
}
Exemplo n.º 9
0
void zen::loginNetworkShare(const Zstring& dirpathOrig, bool allowUserInteraction) //throw() - user interaction: show OS password prompt
{
    /*
    ATTENTION: it is not safe to retrieve UNC path via ::WNetGetConnection() for every type of network share:

    network type				 |::WNetGetConnection rv   | lpRemoteName				     | existing UNC path
    -----------------------------|-------------------------|---------------------------------|----------------
    inactive local network share | ERROR_CONNECTION_UNAVAIL| \\192.168.1.27\new2			 | YES
    WebDrive					 | NO_ERROR				   | \\Webdrive-ZenJu\GNU		     | NO
    Box.net (WebDav)			 | NO_ERROR				   | \\www.box.net\DavWWWRoot\dav    | YES
    NetDrive					 | ERROR_NOT_CONNECTED     | <empty>						 | NO
    ____________________________________________________________________________________________________________

    Windows Login Prompt Naming Conventions:
    	network share:	\\<server>\<share>	e.g. \\WIN-XP\folder or \\192.168.1.50\folder
    	user account:	<Domain>\<user>		e.g. WIN-XP\Zenju    or 192.168.1.50\Zenju

    Windows Command Line:
    - list *all* active network connections, including deviceless ones which are hidden in Explorer:
    		net use
    - delete active connection:
    		net use /delete \\server\share
    ____________________________________________________________________________________________________________

    Scenario: XP-shared folder is accessed by Win 7 over LAN with access limited to a certain user

    Problems:
    I.   WNetAddConnection2() allows (at least certain) invalid credentials (e.g. username: a/password: a) and establishes an *unusable* connection
    II.  WNetAddConnection2() refuses to overwrite an existing (unusable) connection created in I), but shows prompt repeatedly
    III. WNetAddConnection2() won't bring up the prompt if *wrong* credentials had been entered just recently, even with CONNECT_INTERACTIVE specified! => 2-step proccess
    */

    auto connect = [&](NETRESOURCE& trgRes) //blocks heavily if network is not reachable!!!
    {
        //1. first try to connect without user interaction - blocks!
        DWORD rv = ::WNetAddConnection2(&trgRes, //__in  LPNETRESOURCE lpNetResource,
                                        nullptr, //__in  LPCTSTR lpPassword,
                                        nullptr, //__in  LPCTSTR lpUsername,
                                        0);      //__in  DWORD dwFlags
        //53L	ERROR_BAD_NETPATH		The network path was not found.
        //67L   ERROR_BAD_NET_NAME
        //86L	ERROR_INVALID_PASSWORD
        //1219L	ERROR_SESSION_CREDENTIAL_CONFLICT	Multiple connections to a server or shared resource by the same user, using more than one user name, are not allowed. Disconnect all previous connections to the server or shared resource and try again.
        //1326L	ERROR_LOGON_FAILURE	Logon failure: unknown user name or bad password.
        //1236L ERROR_CONNECTION_ABORTED
        if (somethingExists(trgRes.lpRemoteName)) //blocks!
            return; //success: connection usable! -> don't care about "rv"

        if (rv == ERROR_BAD_NETPATH || //like ERROR_PATH_NOT_FOUND
                rv == ERROR_BAD_NET_NAME|| //like ERROR_FILE_NOT_FOUND
                rv == ERROR_CONNECTION_ABORTED) //failed to connect to a network that existed not too long ago; will later return ERROR_BAD_NETPATH
            return; //no need to show a prompt for an unreachable network device

        //2. if first attempt failed, we need to *force* prompt by using CONNECT_PROMPT
        if (allowUserInteraction)
        {
            //avoid problem II.)
            DWORD rv2= ::WNetCancelConnection2(trgRes.lpRemoteName, //_In_  LPCTSTR lpName,
                                               0,					  //_In_  DWORD dwFlags,
                                               true);				  //_In_  BOOL fForce
            //2250L ERROR_NOT_CONNECTED

            //enforce login prompt
            DWORD rv3 = ::WNetAddConnection2(&trgRes, // __in  LPNETRESOURCE lpNetResource,
                                             nullptr, // __in  LPCTSTR lpPassword,
                                             nullptr, // __in  LPCTSTR lpUsername,
                                             CONNECT_INTERACTIVE | CONNECT_PROMPT); //__in  DWORD dwFlags
            (void)rv2;
            (void)rv3;
        }
    };


    Zstring dirpath = removeLongPathPrefix(dirpathOrig);
    trim(dirpath, true, false);

    //1. locally mapped network share
    if (dirpath.size() >= 2 && iswalpha(dirpath[0]) && dirpath[1] == L':')
    {
        Zstring driveLetter(dirpath.c_str(), 2); //e.g.: "Q:"
        {
            DWORD bufferSize = 10000;
            std::vector<wchar_t> remoteNameBuffer(bufferSize);

            //map local -> remote

            //note: following function call does NOT block!
            DWORD rv = ::WNetGetConnection(driveLetter.c_str(),  //__in     LPCTSTR lpLocalName in the form "<driveletter>:"
                                           &remoteNameBuffer[0], //__out    LPTSTR lpRemoteName,
                                           &bufferSize);         //__inout  LPDWORD lpnLength
            if (rv == ERROR_CONNECTION_UNAVAIL) //remoteNameBuffer will be filled nevertheless!
            {
                //ERROR_CONNECTION_UNAVAIL: network mapping is existing, but not connected

                Zstring networkShare = &remoteNameBuffer[0];
                if (!networkShare.empty())
                {
                    NETRESOURCE trgRes = {};
                    trgRes.dwType = RESOURCETYPE_DISK;
                    trgRes.lpLocalName  = const_cast<LPWSTR>(driveLetter.c_str());  //lpNetResource is marked "__in", seems WNetAddConnection2 is not const correct!
                    trgRes.lpRemoteName = const_cast<LPWSTR>(networkShare.c_str()); //

                    connect(trgRes); //blocks!
                }
            }
        }
    }
    //2. deviceless network connection
    else if (startsWith(dirpath, L"\\\\")) //UNC path
    {
        const Zstring networkShare = [&]() -> Zstring //extract prefix "\\server\share"
        {
            size_t pos = dirpath.find('\\', 2);
            if (pos == Zstring::npos)
                return Zstring();
            pos = dirpath.find('\\', pos + 1);
            return pos == Zstring::npos ? dirpath : Zstring(dirpath.c_str(), pos);
        }();

        if (!networkShare.empty())
        {
            //::WNetGetResourceInformation seems to fail with ERROR_BAD_NET_NAME even for existing unconnected network shares!
            // => unconditionally try to connect to network share, seems we cannot reliably detect connection status otherwise

            NETRESOURCE trgRes  = {};
            trgRes.dwType       = RESOURCETYPE_DISK;
            trgRes.lpRemoteName = const_cast<LPWSTR>(networkShare.c_str()); //trgRes is "__in"

            connect(trgRes); //blocks!
        }
    }
}
Exemplo n.º 10
0
void getDirectoryAliasesRecursive(const Zstring& dirpath, std::set<Zstring, LessFilename>& output)
{
#ifdef ZEN_WIN
    //1. replace volume path by volume name: c:\dirpath -> [SYSTEM]\dirpath
    if (dirpath.size() >= 3 &&
            std::iswalpha(dirpath[0]) &&
            dirpath[1] == L':' &&
            dirpath[2] == L'\\')
    {
        Zstring volname = getVolumeName(Zstring(dirpath.c_str(), 3)); //should not block
        if (!volname.empty())
            output.insert(L"[" + volname + L"]" + Zstring(dirpath.c_str() + 2));
    }

    //2. replace volume name by volume path: [SYSTEM]\dirpath -> c:\dirpath
    {
        Zstring testVolname = expandVolumeName(dirpath); //should not block
        if (testVolname != dirpath)
            if (output.insert(testVolname).second)
                getDirectoryAliasesRecursive(testVolname, output); //recurse!
    }
#endif

    //3. environment variables: C:\Users\<user> -> %USERPROFILE%
    {
        std::map<Zstring, Zstring> envToDir;

        //get list of useful variables
        auto addEnvVar = [&](const Zstring& envName)
        {
            if (Opt<Zstring> value = getEnvironmentVar(envName))
                envToDir.emplace(envName, *value);
        };
#ifdef ZEN_WIN
        addEnvVar(L"AllUsersProfile");  // C:\ProgramData
        addEnvVar(L"AppData");          // C:\Users\<user>\AppData\Roaming
        addEnvVar(L"LocalAppData");     // C:\Users\<user>\AppData\Local
        addEnvVar(L"ProgramData");      // C:\ProgramData
        addEnvVar(L"ProgramFiles");     // C:\Program Files
        addEnvVar(L"ProgramFiles(x86)");// C:\Program Files (x86)
        addEnvVar(L"CommonProgramFiles");      // C:\Program Files\Common Files
        addEnvVar(L"CommonProgramFiles(x86)"); // C:\Program Files (x86)\Common Files
        addEnvVar(L"Public");           // C:\Users\Public
        addEnvVar(L"UserProfile");      // C:\Users\<user>
        addEnvVar(L"WinDir");           // C:\Windows
        addEnvVar(L"Temp");             // C:\Windows\Temp

        //add CSIDL values: http://msdn.microsoft.com/en-us/library/bb762494(v=vs.85).aspx
        const auto& csidlMap = CsidlConstants::get();
        envToDir.insert(csidlMap.begin(), csidlMap.end());

#elif defined ZEN_LINUX || defined ZEN_MAC
        addEnvVar("HOME"); //Linux: /home/<user>  Mac: /Users/<user>
#endif
        //substitute paths by symbolic names
        auto pathStartsWith = [](const Zstring& path, const Zstring& prefix) -> bool
        {
#if defined ZEN_WIN || defined ZEN_MAC
            return startsWith(makeUpperCopy(path), makeUpperCopy(prefix));
#elif defined ZEN_LINUX
            return startsWith(path, prefix);
#endif
        };
        for (const auto& entry : envToDir)
            if (pathStartsWith(dirpath, entry.second))
                output.insert(MACRO_SEP + entry.first + MACRO_SEP + (dirpath.c_str() + entry.second.size()));
    }

    //4. replace (all) macros: %USERPROFILE% -> C:\Users\<user>
    {
        Zstring testMacros = expandMacros(dirpath);
        if (testMacros != dirpath)
            if (output.insert(testMacros).second)
                getDirectoryAliasesRecursive(testMacros, output); //recurse!
    }
}
Exemplo n.º 11
0
MainDialog::MainDialog(wxDialog* dlg, const Zstring& cfgFileName)
    : MainDlgGenerated(dlg)
{
#ifdef ZEN_WIN
    new MouseMoveWindow(*this); //ownership passed to "this"
    wxWindowUpdateLocker dummy(this); //leads to GUI corruption problems on Linux/OS X!
#endif

    SetIcon(getRtsIcon()); //set application icon

    setRelativeFontSize(*m_buttonStart, 1.5);

    m_bpButtonRemoveTopFolder->Hide();
    m_panelMainFolder->Layout();

    m_bpButtonAddFolder      ->SetBitmapLabel(getResourceImage(L"item_add"));
    m_bpButtonRemoveTopFolder->SetBitmapLabel(getResourceImage(L"item_remove"));
    setBitmapTextLabel(*m_buttonStart, getResourceImage(L"startRts").ConvertToImage(), m_buttonStart->GetLabel(), 5, 8);

    //register key event
    Connect(wxEVT_CHAR_HOOK, wxKeyEventHandler(MainDialog::OnKeyPressed), nullptr, this);

    //prepare drag & drop
    dirpathFirst = std::make_unique<FolderSelector2>(*m_panelMainFolder, *m_buttonSelectFolderMain, *m_txtCtrlDirectoryMain, m_staticTextFinalPath);

    //--------------------------- load config values ------------------------------------
    xmlAccess::XmlRealConfig newConfig;

    const Zstring currentConfigFile = cfgFileName.empty() ? lastConfigFileName() : cfgFileName;
    bool loadCfgSuccess = false;
    if (!cfgFileName.empty() || fileExists(lastConfigFileName()))
        try
        {
            std::wstring warningMsg;
            xmlAccess::readRealOrBatchConfig(currentConfigFile, newConfig, warningMsg); //throw FileError

            if (!warningMsg.empty())
                showNotificationDialog(this, DialogInfoType::WARNING, PopupDialogCfg().setDetailInstructions(warningMsg));

            loadCfgSuccess = warningMsg.empty();
        }
        catch (const FileError& e)
        {
            showNotificationDialog(this, DialogInfoType::ERROR2, PopupDialogCfg().setDetailInstructions(e.toString()));
        }

    const bool startWatchingImmediately = loadCfgSuccess && !cfgFileName.empty();

    setConfiguration(newConfig);
    setLastUsedConfig(currentConfigFile);
    //-----------------------------------------------------------------------------------------

    if (startWatchingImmediately) //start watch mode directly
    {
        wxCommandEvent dummy2(wxEVT_COMMAND_BUTTON_CLICKED);
        this->OnStart(dummy2);
        //don't Show()!
    }
    else
    {
        m_buttonStart->SetFocus(); //don't "steal" focus if program is running from sys-tray"
        Show();
#ifdef ZEN_MAC
        ProcessSerialNumber psn = { 0, kCurrentProcess };
        ::TransformProcessType(&psn, kProcessTransformToForegroundApplication); //show dock icon, even if we're not an application bundle
        ::SetFrontProcess(&psn);
        //if the executable is not yet in a bundle or if it is called through a launcher, we need to set focus manually:
#endif
    }

    //drag and drop .ffs_real and .ffs_batch on main dialog
    setupFileDrop(*m_panelMain);
    m_panelMain->Connect(EVENT_DROP_FILE, FileDropEventHandler(MainDialog::onFilesDropped), nullptr, this);
}
Exemplo n.º 12
0
bool tryLock(const Zstring& lockfilepath) //throw FileError
{
#ifdef ZEN_WIN
#ifdef TODO_MinFFS_ActivatePriviledge
    try { activatePrivilege(SE_BACKUP_NAME); }
    catch (const FileError&) {}
    try { activatePrivilege(SE_RESTORE_NAME); }
    catch (const FileError&) {}
#endif//TODO_MinFFS_ActivatePriviledge

    const HANDLE fileHandle = ::CreateFile(applyLongPathPrefix(lockfilepath).c_str(),              //_In_      LPCTSTR lpFileName,
                                           //use both when writing over network, see comment in file_io.cpp
                                           GENERIC_READ | GENERIC_WRITE,                           //_In_      DWORD dwDesiredAccess,
                                           FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, //_In_      DWORD dwShareMode,
                                           nullptr,               //_In_opt_  LPSECURITY_ATTRIBUTES lpSecurityAttributes,
                                           CREATE_NEW,            //_In_      DWORD dwCreationDisposition,
                                           FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, //_In_      DWORD dwFlagsAndAttributes,
                                           nullptr);              //_In_opt_  HANDLE hTemplateFile
    if (fileHandle == INVALID_HANDLE_VALUE)
    {
        const DWORD ec = ::GetLastError(); //copy before directly/indirectly making other system calls!
        if (ec == ERROR_FILE_EXISTS || //confirmed to be used
            ec == ERROR_ALREADY_EXISTS) //comment on msdn claims, this one is used on Windows Mobile 6
            return false;

        throw FileError(replaceCpy(_("Cannot write file %x."), L"%x", fmtPath(lockfilepath)), formatSystemError(L"CreateFile", ec));
    }
    ScopeGuard guardLockFile = zen::makeGuard([&] { removeFile(lockfilepath); });
    FileOutput fileOut(fileHandle, lockfilepath); //pass handle ownership

    //be careful to avoid CreateFile() + CREATE_ALWAYS on a hidden file -> see file_io.cpp
    //=> we don't need it that badly //::SetFileAttributes(applyLongPathPrefix(lockfilepath).c_str(), FILE_ATTRIBUTE_HIDDEN); //(try to) hide it

#elif defined ZEN_LINUX || defined ZEN_MAC
    const mode_t oldMask = ::umask(0); //important: we want the lock file to have exactly the permissions specified
    ZEN_ON_SCOPE_EXIT(::umask(oldMask));

    //O_EXCL contains a race condition on NFS file systems: http://linux.die.net/man/2/open
    const int fileHandle = ::open(lockfilepath.c_str(), O_CREAT | O_EXCL | O_WRONLY,
                                  S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
    if (fileHandle == -1)
    {
        if (errno == EEXIST)
            return false;
        else
            THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot write file %x."), L"%x", fmtPath(lockfilepath)), L"open");
    }
    ScopeGuard guardLockFile = zen::makeGuard([&] { removeFile(lockfilepath); });
    FileOutput fileOut(fileHandle, lockfilepath); //pass handle ownership
#endif

    //write housekeeping info: user, process info, lock GUID
    ByteArray binStream = [&]
    {
        MemStreamOut streamOut;
        LockInformation(FromCurrentProcess()).toStream(streamOut);
        return streamOut.ref();
    }();

    if (!binStream.empty())
        fileOut.write(&*binStream.begin(), binStream.size()); //throw FileError

    guardLockFile.dismiss(); //lockfile created successfully
    return true;
}
Exemplo n.º 13
0
void zen::recycleOrDelete(const std::vector<Zstring>& itempaths, const std::function<void (const Zstring& currentItem)>& notifyDeletionStatus)
{
    if (itempaths.empty())
        return;
    //::SetFileAttributes(applyLongPathPrefix(itempath).c_str(), FILE_ATTRIBUTE_NORMAL);
    //warning: moving long file paths to recycler does not work!
    //both ::SHFileOperation() and ::IFileOperation() cannot delete a folder named "System Volume Information" with normal attributes but shamelessly report success
    //both ::SHFileOperation() and ::IFileOperation() can't handle \\?\-prefix!

    if (vistaOrLater()) //new recycle bin usage: available since Vista
    {
#define DEF_DLL_FUN(name) const DllFun<fileop::FunType_##name> name(fileop::getDllName(), fileop::funName_##name);
        DEF_DLL_FUN(moveToRecycleBin);
        DEF_DLL_FUN(getLastErrorMessage);

        if (!moveToRecycleBin || !getLastErrorMessage)
            throw FileError(replaceCpy(_("Unable to move %x to the recycle bin."), L"%x", fmtFileName(itempaths[0])),
                            replaceCpy(_("Cannot load file %x."), L"%x", fmtFileName(fileop::getDllName())));
	
        std::vector<const wchar_t*> cNames;
        for (auto it = itempaths.begin(); it != itempaths.end(); ++it) //CAUTION: do not create temporary strings here!!
            cNames.push_back(it->c_str());

        CallbackData cbd(notifyDeletionStatus);
        if (!moveToRecycleBin(&cNames[0], cNames.size(), onRecyclerCallback, &cbd))
        {
            if (cbd.exception)
                std::rethrow_exception(cbd.exception);

            std::wstring itempathFmt = fmtFileName(itempaths[0]); //probably not the correct file name for file lists larger than 1!
            if (itempaths.size() > 1)
                itempathFmt += L", ..."; //give at least some hint that there are multiple files, and the error need not be related to the first one

            throw FileError(replaceCpy(_("Unable to move %x to the recycle bin."), L"%x", itempathFmt), getLastErrorMessage()); //already includes details about locking errors!
        }
    }
    else //regular recycle bin usage: available since XP
    {
        Zstring itempathsDoubleNull;
        for (const Zstring& itempath : itempaths)
        {
            itempathsDoubleNull += itempath;
            itempathsDoubleNull += L'\0';
        }

        SHFILEOPSTRUCT fileOp = {};
        fileOp.hwnd   = nullptr;
        fileOp.wFunc  = FO_DELETE;
        fileOp.pFrom  = itempathsDoubleNull.c_str();
        fileOp.pTo    = nullptr;
        fileOp.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMATION | FOF_SILENT | FOF_NOERRORUI;
        fileOp.fAnyOperationsAborted = false;
        fileOp.hNameMappings         = nullptr;
        fileOp.lpszProgressTitle     = nullptr;

        //"You should use fully-qualified path names with this function. Using it with relative path names is not thread safe."
        if (::SHFileOperation(&fileOp) != 0 || fileOp.fAnyOperationsAborted)
        {
            throw FileError(replaceCpy(_("Unable to move %x to the recycle bin."), L"%x", fmtFileName(itempaths[0]))); //probably not the correct file name for file list larger than 1!
        }
    }
}
Exemplo n.º 14
0
void DirectoryName<NameControl>::onSelectDir(wxCommandEvent& event)
{
    wxString defaultdirpath; //default selection for dir picker
    {
        const Zstring dirFmt = getFormattedDirectoryPath(toZ(getPath()));
        if (!dirFmt.empty())
        {
            //convert to Zstring first: we don't want to pass wxString by value and risk MT issues!
            auto ft = async([=] { return zen::dirExists(dirFmt); });

            if (ft.timed_wait(boost::posix_time::milliseconds(200)) && ft.get()) //potentially slow network access: wait 200ms at most
                defaultdirpath = utfCvrtTo<wxString>(dirFmt);
        }
    }

    //wxDirDialog internally uses lame-looking SHBrowseForFolder(); we better use IFileDialog() instead! (remembers size and position!)
    std::unique_ptr<wxString> newFolder;
#ifdef ZEN_WIN
    if (vistaOrLater())
    {
#define DEF_DLL_FUN(name) const DllFun<ifile::FunType_##name> name(ifile::getDllName(), ifile::funName_##name);
        DEF_DLL_FUN(showFolderPicker);
        DEF_DLL_FUN(freeString);
#undef DEF_DLL_FUN

        if (showFolderPicker && freeString)
        {
            wchar_t* selectedFolder = nullptr;
            wchar_t* errorMsg       = nullptr;
            bool cancelled = false;
            ZEN_ON_SCOPE_EXIT(freeString(selectedFolder));
            ZEN_ON_SCOPE_EXIT(freeString(errorMsg));

            const ifile::GuidProxy guid = { '\x0', '\x4a', '\xf9', '\x31', '\xb4', '\x92', '\x40', '\xa0',
                                            '\x8d', '\xc2', '\xc', '\xa5', '\xef', '\x59', '\x6e', '\x3b'
                                          }; //some random GUID => have Windows save IFileDialog state separately from other file/dir pickers!

            showFolderPicker(static_cast<HWND>(selectButton_.GetHWND()), //in;  ==HWND
                             defaultdirpath.empty() ? static_cast<const wchar_t*>(nullptr) : defaultdirpath.c_str(), //in, optional!
                             &guid,
                             selectedFolder, //out: call freeString() after use!
                             cancelled,      //out
                             errorMsg);      //out, optional: call freeString() after use!
            if (errorMsg)
            {
                showNotificationDialog(&dropWindow_, DialogInfoType::ERROR2, PopupDialogCfg().setDetailInstructions(errorMsg));
                return;
            }
            if (cancelled || !selectedFolder)
                return;
            newFolder = make_unique<wxString>(selectedFolder);
        }
    }
#endif
    if (!newFolder.get())
    {
        wxDirDialog dirPicker(&selectButton_, _("Select a folder"), defaultdirpath); //put modal wxWidgets dialogs on stack: creating on freestore leads to memleak!
        if (dirPicker.ShowModal() != wxID_OK)
            return;
        newFolder = make_unique<wxString>(dirPicker.GetPath());
    }

    setDirectoryName(*newFolder, &dirpath_, dirpath_, staticText_);

    //notify action invoked by user
    wxCommandEvent dummy(EVENT_ON_DIR_SELECTED);
    ProcessEvent(dummy);
}
Exemplo n.º 15
0
std::wstring xmlAccess::extractJobName(const Zstring& configFilename)
{
    const Zstring shortName = afterLast(configFilename, FILE_NAME_SEPARATOR); //returns the whole string if separator not found
    const Zstring jobName = beforeLast(shortName, Zstr('.')); //returns empty string if seperator not found
    return utfCvrtTo<std::wstring>(jobName.empty() ? shortName : jobName);
}