@@ -109,23 +109,51 @@ static __tb_inline__ tb_wchar_t const* tb_path_absolute_w(tb_char_t const* path,
109109 tb_size_t size = tb_strlen (path );
110110 if (size >= MAX_PATH )
111111 {
112- tb_char_t * e = data + size - 1 ;
113- if (e + 5 < data + sizeof (data ))
112+ /* choose the long-path prefix and the number of leading chars to drop
113+ *
114+ * - already "\\?\" prefixed => keep as-is
115+ * - UNC path "\\server\share\.." => "\\?\UNC\server\share\.."
116+ * - drive/other absolute path => "\\?\.."
117+ *
118+ * @see https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation
119+ */
120+ tb_char_t const * prefix = tb_null ;
121+ tb_size_t plen = 0 ;
122+ tb_size_t skip = 0 ;
123+ if (data [0 ] == '\\' && data [1 ] == '\\' && data [2 ] == '?' && data [3 ] == '\\' )
124+ ; // already a long-path form, do nothing
125+ else if (data [0 ] == '\\' && data [1 ] == '\\' )
114126 {
115- e [5 ] = '\0' ;
116- while (e >= data )
127+ // UNC path: replace the leading "\\" with "\\?\UNC\"
128+ prefix = "\\\\?\\UNC\\" ;
129+ plen = 8 ;
130+ skip = 2 ;
131+ }
132+ else
133+ {
134+ prefix = "\\\\?\\" ;
135+ plen = 4 ;
136+ }
137+
138+ if (prefix )
139+ {
140+ tb_size_t new_size = plen + size - skip ;
141+ if (new_size < sizeof (data ))
117142 {
118- e [4 ] = * e ;
119- e -- ;
143+ /* shift the kept content (with the null terminator) right, then prepend the prefix
144+ *
145+ * copy from high to low to avoid overlap corruption, e.g. for a drive path:
146+ * "C:\..\0" => "\\?\C:\..\0"
147+ */
148+ tb_char_t * d = data + new_size ;
149+ tb_char_t const * s = data + size ;
150+ while (s >= data + skip ) * d -- = * s -- ;
151+ tb_memcpy (data , prefix , plen );
152+ path = data ;
153+ size = new_size ;
120154 }
121- data [0 ] = '\\' ;
122- data [1 ] = '\\' ;
123- data [2 ] = '?' ;
124- data [3 ] = '\\' ;
125- path = data ;
126- size += 4 ; // add "\\?\" prefix length
155+ else return tb_null ;
127156 }
128- else return tb_null ;
129157 }
130158
131159 // use tb_atow_n with known length to avoid tb_atow's internal strlen
0 commit comments