summaryrefslogtreecommitdiff
path: root/zen/long_path_prefix.h
blob: 6f6ebfdcefe6fab95203790d0818d9f86f36990f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
// **************************************************************************
// * This file is part of the FreeFileSync project. It is distributed under *
// * GNU General Public License: http://www.gnu.org/licenses/gpl-3.0        *
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved        *
// **************************************************************************

#ifndef LONGPATHPREFIX_H_INCLUDED
#define LONGPATHPREFIX_H_INCLUDED

#include "win.h"
#include "zstring.h"


namespace zen
{
//handle filepaths longer-equal 260 (== MAX_PATH) characters by applying \\?\-prefix; see: http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx#maxpath
/*
1. path must be absolute
2. if path is smaller than MAX_PATH nothing is changed! caveat: FindFirstFile() "Prepending the string "\\?\" does not allow access to the root directory."
3. path may already contain \\?\-prefix
*/
Zstring applyLongPathPrefix(const Zstring& path); //noexcept
Zstring applyLongPathPrefixCreateDir(const Zstring& path); //noexcept -> special rule for ::CreateDirectory()/::CreateDirectoryEx(): MAX_PATH - 12(=^ 8.3 filepath) is threshold

Zstring removeLongPathPrefix(const Zstring& path); //noexcept


Zstring ntPathToWin32Path(const Zstring& path); //noexcept
/*
http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx#NT_Namespaces

As used by GetModuleFileNameEx() and symlinks (FSCTL_GET_REPARSE_POINT):
    E.g.:
    \??\C:\folder -> C:\folder
    \SystemRoot   -> C:\Windows
*/
}













//################## implementation ##################

//there are two flavors of long path prefix: one for UNC paths, one for regular paths
const wchar_t LONG_PATH_PREFIX    [] = L"\\\\?\\";    //don't use Zstring as global constant: avoid static initialization order problem in global namespace!
const wchar_t LONG_PATH_PREFIX_UNC[] = L"\\\\?\\UNC"; //

template <size_t maxPath> inline
Zstring applyLongPathPrefixImpl(const Zstring& path)
{
    assert(!path.empty()); //nicely check almost all WinAPI accesses!
    assert(!zen::isWhiteSpace(path[0]));

    //http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx#naming_conventions))
    /*
      - special names like ".NUL" create all kinds of trouble (e.g. CreateDirectory() reports success, but does nothing)
        unless prefix is supplied => accept as limitation
    */
    if (path.length() >= maxPath || //maximum allowed path length without prefix is (MAX_PATH - 1)
        endsWith(path, L' ') || //by default all Win32 APIs trim trailing spaces and period, unless long path prefix is supplied!
        endsWith(path, L'.'))   //note: adding long path prefix might screw up relative paths "." and ".."!
        if (!startsWith(path, LONG_PATH_PREFIX))
        {
            if (startsWith(path, L"\\\\")) //UNC-name, e.g. \\zenju-pc\Users
                return LONG_PATH_PREFIX_UNC + afterFirst(path, L'\\', zen::IF_MISSING_RETURN_NONE); //convert to \\?\UNC\zenju-pc\Users
            else
                return LONG_PATH_PREFIX + path; //prepend \\?\ prefix
        }
    return path; //fallback
}


inline
Zstring zen::applyLongPathPrefix(const Zstring& path)
{
    return applyLongPathPrefixImpl<MAX_PATH>(path);
}


inline
Zstring zen::applyLongPathPrefixCreateDir(const Zstring& path) //noexcept
{
    //special rule for ::CreateDirectoryEx(): MAX_PATH - 12(=^ 8.3 filepath) is threshold
    return applyLongPathPrefixImpl<MAX_PATH - 12> (path);
}


inline
Zstring zen::removeLongPathPrefix(const Zstring& path) //noexcept
{
    if (zen::startsWith(path, LONG_PATH_PREFIX))
    {
        if (zen::startsWith(path, LONG_PATH_PREFIX_UNC)) //UNC-name
            return replaceCpy(path, LONG_PATH_PREFIX_UNC, Zstr("\\"), false);
        else
            return replaceCpy(path, LONG_PATH_PREFIX, Zstr(""), false);
    }
    return path; //fallback
}


inline
Zstring zen::ntPathToWin32Path(const Zstring& path) //noexcept
{
    if (startsWith(path, L"\\??\\"))
        return Zstring(path.c_str() + 4, path.length() - 4);

    if (startsWith(path, L"\\SystemRoot\\"))
    {
        DWORD bufSize = ::GetEnvironmentVariable(L"SystemRoot", nullptr, 0);
        if (bufSize > 0)
        {
            std::vector<wchar_t> buf(bufSize);
            const DWORD charsWritten = ::GetEnvironmentVariable(L"SystemRoot", //_In_opt_   LPCTSTR lpName,
                                                                &buf[0],       //_Out_opt_  LPTSTR lpBuffer,
                                                                bufSize);      //_In_       DWORD nSize
            if (0 < charsWritten && charsWritten < bufSize)
                return replaceCpy(path, L"\\SystemRoot\\", appendSeparator(Zstring(&buf[0], charsWritten)), false);
        }
    }

    return path;
}

#endif //LONGPATHPREFIX_H_INCLUDED
bgstack15