Changeset 14588


Ignore:
Timestamp:
Oct 23, 2015, 5:29:47 AM (5 years ago)
Author:
mikedld
Message:

Support absolute paths longer than ~260 chars on Windows

Location:
trunk/libtransmission
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/libtransmission/file-win32.c

    r14586 r14588  
    142142}
    143143
     144static wchar_t *
     145path_to_native_path_ex (const char * path,
     146                        int          extra_chars_after,
     147                        int        * real_result_size)
     148{
     149  /* Extending maximum path length limit up to ~32K. See "Naming Files, Paths, and Namespaces"
     150     (https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247.aspx) for more info */
     151
     152  const wchar_t local_prefix[] = { '\\', '\\', '?', '\\' };
     153  const wchar_t unc_prefix[] = { '\\', '\\', '?', '\\', 'U', 'N', 'C', '\\' };
     154
     155  const bool is_relative = tr_sys_path_is_relative (path);
     156  const bool is_unc = is_unc_path (path);
     157
     158  /* `-2` for UNC since we overwrite existing prefix slashes */
     159  const int extra_chars_before = is_relative ? 0 : (is_unc ? ARRAYSIZE (unc_prefix) - 2
     160                                                           : ARRAYSIZE (local_prefix));
     161
     162  /* TODO (?): assert (!is_relative); */
     163
     164  wchar_t * const wide_path = tr_win32_utf8_to_native_ex (path, -1, extra_chars_before,
     165                                                          extra_chars_after, real_result_size);
     166  if (wide_path == NULL)
     167    return NULL;
     168
     169  /* Relative paths cannot be used with "\\?\" prefixes. This also means that relative paths are
     170     limited to ~260 chars... but we should rarely work with relative paths in the first place */
     171  if (!is_relative)
     172    {
     173      if (is_unc)
     174        /* UNC path: "\\server\share" -> "\\?\UNC\server\share" */
     175        memcpy (wide_path, unc_prefix, sizeof (unc_prefix));
     176      else
     177        /* Local path: "C:" -> "\\?\C:" */
     178        memcpy (wide_path, local_prefix, sizeof (local_prefix));
     179    }
     180
     181  /* Automatic '/' to '\' conversion is disabled for "\\?\"-prefixed paths */
     182  wchar_t * p = wide_path + extra_chars_before;
     183  while ((p = wcschr (p, L'/')) != NULL)
     184    *p++ = L'\\';
     185
     186  if (real_result_size != NULL)
     187    *real_result_size += extra_chars_before;
     188
     189  return wide_path;
     190}
     191
     192static wchar_t *
     193path_to_native_path (const char * path)
     194{
     195  return path_to_native_path_ex (path, 0, NULL);
     196}
     197
    144198static tr_sys_file_t
    145199open_file (const char  * path,
     
    154208  assert (path != NULL);
    155209
    156   wide_path = tr_win32_utf8_to_native (path, -1);
     210  wide_path = path_to_native_path (path);
    157211
    158212  if (wide_path != NULL)
     
    183237  (void) permissions;
    184238
    185   wide_path = tr_win32_utf8_to_native (path, -1);
     239  wide_path = path_to_native_path (path);
    186240
    187241  if ((flags & TR_SYS_DIR_CREATE_PARENTS) != 0)
    188242    {
    189       /* For some reason SHCreateDirectoryEx has issues with forward slashes */
    190       wchar_t * p = wide_path;
    191       while ((p = wcschr (p, L'/')) != NULL)
    192         *p++ = L'\\';
    193 
    194243      error_code = SHCreateDirectoryExW (NULL, wide_path, NULL);
    195244      ret = error_code == ERROR_SUCCESS;
     
    276325  assert (path != NULL);
    277326
    278   wide_path = tr_win32_utf8_to_native (path, -1);
     327  wide_path = path_to_native_path (path);
    279328
    280329  if (wide_path != NULL)
     
    320369  assert (info != NULL);
    321370
    322   wide_path = tr_win32_utf8_to_native (path, -1);
     371  wide_path = path_to_native_path (path);
    323372
    324373  if ((flags & TR_SYS_PATH_NO_FOLLOW) == 0)
     
    393442  assert (path2 != NULL);
    394443
    395   wide_path1 = tr_win32_utf8_to_native (path1, -1);
     444  wide_path1 = path_to_native_path (path1);
    396445  if (wide_path1 == NULL)
    397446    goto fail;
    398447
    399   wide_path2 = tr_win32_utf8_to_native (path2, -1);
     448  wide_path2 = path_to_native_path (path2);
    400449  if (wide_path2 == NULL)
    401450    goto fail;
     
    445494  assert (path != NULL);
    446495
    447   wide_path = tr_win32_utf8_to_native (path, -1);
     496  wide_path = path_to_native_path (path);
    448497  if (wide_path == NULL)
    449498    goto fail;
     
    566615  assert (dst_path != NULL);
    567616
    568   wide_src_path = tr_win32_utf8_to_native (src_path, -1);
    569   wide_dst_path = tr_win32_utf8_to_native (dst_path, -1);
     617  wide_src_path = path_to_native_path (src_path);
     618  wide_dst_path = path_to_native_path (dst_path);
    570619
    571620  if (wide_src_path != NULL && wide_dst_path != NULL)
     
    609658  assert (path != NULL);
    610659
    611   wide_path = tr_win32_utf8_to_native (path, -1);
     660  wide_path = path_to_native_path (path);
    612661
    613662  if (wide_path != NULL)
     
    11601209{
    11611210  tr_sys_dir_t ret;
     1211  int pattern_size;
    11621212
    11631213#ifndef __clang__
     
    11691219
    11701220  ret = tr_new (struct tr_sys_dir_win32, 1);
    1171   ret->pattern = tr_win32_utf8_to_native_ex (path, -1, 2);
     1221  ret->pattern = path_to_native_path_ex (path, 2, &pattern_size);
    11721222
    11731223  if (ret->pattern != NULL)
    11741224    {
    1175       const size_t pattern_size = wcslen (ret->pattern);
    11761225      ret->pattern[pattern_size + 0] = L'\\';
    11771226      ret->pattern[pattern_size + 1] = L'*';
    1178       ret->pattern[pattern_size + 2] = L'\0';
    11791227
    11801228      ret->find_handle = INVALID_HANDLE_VALUE;
  • trunk/libtransmission/utils.c

    r14574 r14588  
    10811081                         int          text_size)
    10821082{
    1083   return tr_win32_utf8_to_native_ex (text, text_size, 0);
     1083  return tr_win32_utf8_to_native_ex (text, text_size, 0, 0, NULL);
    10841084}
    10851085
     
    10871087tr_win32_utf8_to_native_ex (const char * text,
    10881088                            int          text_size,
    1089                             int          extra_chars)
     1089                            int          extra_chars_before,
     1090                            int          extra_chars_after,
     1091                            int        * real_result_size)
    10901092{
    10911093  wchar_t * ret = NULL;
    10921094  int size;
     1095
     1096  if (text_size == -1)
     1097    text_size = strlen (text);
    10931098
    10941099  size = MultiByteToWideChar (CP_UTF8, 0, text, text_size, NULL, 0);
     
    10961101    goto fail;
    10971102
    1098   ret = tr_new (wchar_t, size + extra_chars + 1);
    1099   size = MultiByteToWideChar (CP_UTF8, 0, text, text_size, ret, size);
     1103  ret = tr_new (wchar_t, size + extra_chars_before + extra_chars_after + 1);
     1104  size = MultiByteToWideChar (CP_UTF8, 0, text, text_size, ret + extra_chars_before, size);
    11001105  if (size == 0)
    11011106    goto fail;
    11021107
    1103   ret[size] = L'\0';
     1108  ret[size + extra_chars_before + extra_chars_after] = L'\0';
     1109
     1110  if (real_result_size != NULL)
     1111    *real_result_size = size;
    11041112
    11051113  return ret;
  • trunk/libtransmission/utils.h

    r14577 r14588  
    201201wchar_t * tr_win32_utf8_to_native_ex (const char    * text,
    202202                                      int             text_size,
    203                                       int             extra_chars);
     203                                      int             extra_chars_before,
     204                                      int             extra_chars_after,
     205                                      int           * real_result_size);
    204206char    * tr_win32_format_message    (uint32_t        code);
    205207
Note: See TracChangeset for help on using the changeset viewer.