diff options
| author | Eli Zaretskii | 2013-11-02 15:03:32 +0200 |
|---|---|---|
| committer | Eli Zaretskii | 2013-11-02 15:03:32 +0200 |
| commit | 1fd201bb1d720d0c5ab727a3972363778eef834f (patch) | |
| tree | 508abf22dbb91d24309869bc42a93e814f9fbcd6 /src/w32.c | |
| parent | 5c4a19a90f803ed46629c2bdc1ac3d3563caa738 (diff) | |
| download | emacs-1fd201bb1d720d0c5ab727a3972363778eef834f.tar.gz emacs-1fd201bb1d720d0c5ab727a3972363778eef834f.zip | |
Adapted dostounix_filename. w32-short/long-filename work with wide APIs.
Diffstat (limited to 'src/w32.c')
| -rw-r--r-- | src/w32.c | 202 |
1 files changed, 73 insertions, 129 deletions
| @@ -1336,7 +1336,7 @@ filename_to_ansi (const char *fn_in, char *fn_out) | |||
| 1336 | return -1; | 1336 | return -1; |
| 1337 | } | 1337 | } |
| 1338 | 1338 | ||
| 1339 | static int | 1339 | int |
| 1340 | filename_from_ansi (const char *fn_in, char *fn_out) | 1340 | filename_from_ansi (const char *fn_in, char *fn_out) |
| 1341 | { | 1341 | { |
| 1342 | wchar_t fn_utf16[MAXPATHLEN]; | 1342 | wchar_t fn_utf16[MAXPATHLEN]; |
| @@ -1799,31 +1799,20 @@ max_filename_mbslen (void) | |||
| 1799 | return cp_info.MaxCharSize; | 1799 | return cp_info.MaxCharSize; |
| 1800 | } | 1800 | } |
| 1801 | 1801 | ||
| 1802 | /* Normalize filename by converting all path separators to | 1802 | /* Normalize filename by converting in-place all of its path |
| 1803 | the specified separator. Also conditionally convert upper | 1803 | separators to the separator specified by PATH_SEP. */ |
| 1804 | case path name components to lower case. */ | ||
| 1805 | 1804 | ||
| 1806 | static void | 1805 | static void |
| 1807 | normalize_filename (register char *fp, char path_sep, int multibyte) | 1806 | normalize_filename (register char *fp, char path_sep) |
| 1808 | { | 1807 | { |
| 1809 | char sep; | 1808 | char *p2; |
| 1810 | char *elem, *p2; | ||
| 1811 | int dbcs_p = max_filename_mbslen () > 1; | ||
| 1812 | |||
| 1813 | /* Multibyte file names are in the Emacs internal representation, so | ||
| 1814 | we can traverse them by bytes with no problems. */ | ||
| 1815 | if (multibyte) | ||
| 1816 | dbcs_p = 0; | ||
| 1817 | 1809 | ||
| 1818 | /* Always lower-case drive letters a-z, even if the filesystem | 1810 | /* Always lower-case drive letters a-z, even if the filesystem |
| 1819 | preserves case in filenames. | 1811 | preserves case in filenames. |
| 1820 | This is so filenames can be compared by string comparison | 1812 | This is so filenames can be compared by string comparison |
| 1821 | functions that are case-sensitive. Even case-preserving filesystems | 1813 | functions that are case-sensitive. Even case-preserving filesystems |
| 1822 | do not distinguish case in drive letters. */ | 1814 | do not distinguish case in drive letters. */ |
| 1823 | if (dbcs_p) | 1815 | p2 = fp + 1; |
| 1824 | p2 = CharNextExA (file_name_codepage, fp, 0); | ||
| 1825 | else | ||
| 1826 | p2 = fp + 1; | ||
| 1827 | 1816 | ||
| 1828 | if (*p2 == ':' && *fp >= 'A' && *fp <= 'Z') | 1817 | if (*p2 == ':' && *fp >= 'A' && *fp <= 'Z') |
| 1829 | { | 1818 | { |
| @@ -1831,68 +1820,26 @@ normalize_filename (register char *fp, char path_sep, int multibyte) | |||
| 1831 | fp += 2; | 1820 | fp += 2; |
| 1832 | } | 1821 | } |
| 1833 | 1822 | ||
| 1834 | if (multibyte || NILP (Vw32_downcase_file_names)) | 1823 | while (*fp) |
| 1835 | { | 1824 | { |
| 1836 | while (*fp) | 1825 | if (*fp == '/' || *fp == '\\') |
| 1837 | { | 1826 | *fp = path_sep; |
| 1838 | if (*fp == '/' || *fp == '\\') | 1827 | fp++; |
| 1839 | *fp = path_sep; | ||
| 1840 | if (!dbcs_p) | ||
| 1841 | fp++; | ||
| 1842 | else | ||
| 1843 | fp = CharNextExA (file_name_codepage, fp, 0); | ||
| 1844 | } | ||
| 1845 | return; | ||
| 1846 | } | 1828 | } |
| 1847 | |||
| 1848 | sep = path_sep; /* convert to this path separator */ | ||
| 1849 | elem = fp; /* start of current path element */ | ||
| 1850 | |||
| 1851 | do { | ||
| 1852 | if (*fp >= 'a' && *fp <= 'z') | ||
| 1853 | elem = 0; /* don't convert this element */ | ||
| 1854 | |||
| 1855 | if (*fp == 0 || *fp == ':') | ||
| 1856 | { | ||
| 1857 | sep = *fp; /* restore current separator (or 0) */ | ||
| 1858 | *fp = '/'; /* after conversion of this element */ | ||
| 1859 | } | ||
| 1860 | |||
| 1861 | if (*fp == '/' || *fp == '\\') | ||
| 1862 | { | ||
| 1863 | if (elem && elem != fp) | ||
| 1864 | { | ||
| 1865 | *fp = 0; /* temporary end of string */ | ||
| 1866 | _mbslwr (elem); /* while we convert to lower case */ | ||
| 1867 | } | ||
| 1868 | *fp = sep; /* convert (or restore) path separator */ | ||
| 1869 | elem = fp + 1; /* next element starts after separator */ | ||
| 1870 | sep = path_sep; | ||
| 1871 | } | ||
| 1872 | if (*fp) | ||
| 1873 | { | ||
| 1874 | if (!dbcs_p) | ||
| 1875 | fp++; | ||
| 1876 | else | ||
| 1877 | fp = CharNextExA (file_name_codepage, fp, 0); | ||
| 1878 | } | ||
| 1879 | } while (*fp); | ||
| 1880 | } | 1829 | } |
| 1881 | 1830 | ||
| 1882 | /* Destructively turn backslashes into slashes. MULTIBYTE non-zero | 1831 | /* Destructively turn backslashes into slashes. */ |
| 1883 | means the file name is a multibyte string in Emacs's internal | ||
| 1884 | representation. */ | ||
| 1885 | void | 1832 | void |
| 1886 | dostounix_filename (register char *p, int multibyte) | 1833 | dostounix_filename (register char *p) |
| 1887 | { | 1834 | { |
| 1888 | normalize_filename (p, '/', multibyte); | 1835 | normalize_filename (p, '/'); |
| 1889 | } | 1836 | } |
| 1890 | 1837 | ||
| 1891 | /* Destructively turn slashes into backslashes. */ | 1838 | /* Destructively turn slashes into backslashes. */ |
| 1892 | void | 1839 | void |
| 1893 | unixtodos_filename (register char *p) | 1840 | unixtodos_filename (register char *p) |
| 1894 | { | 1841 | { |
| 1895 | normalize_filename (p, '\\', 0); | 1842 | normalize_filename (p, '\\'); |
| 1896 | } | 1843 | } |
| 1897 | 1844 | ||
| 1898 | /* Remove all CR's that are followed by a LF. | 1845 | /* Remove all CR's that are followed by a LF. |
| @@ -1943,17 +1890,13 @@ parse_root (char * name, char ** pPath) | |||
| 1943 | else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1])) | 1890 | else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1])) |
| 1944 | { | 1891 | { |
| 1945 | int slashes = 2; | 1892 | int slashes = 2; |
| 1946 | int dbcs_p = max_filename_mbslen () > 1; | ||
| 1947 | 1893 | ||
| 1948 | name += 2; | 1894 | name += 2; |
| 1949 | do | 1895 | do |
| 1950 | { | 1896 | { |
| 1951 | if (IS_DIRECTORY_SEP (*name) && --slashes == 0) | 1897 | if (IS_DIRECTORY_SEP (*name) && --slashes == 0) |
| 1952 | break; | 1898 | break; |
| 1953 | if (dbcs_p) | 1899 | name++; |
| 1954 | name = CharNextExA (file_name_codepage, name, 0); | ||
| 1955 | else | ||
| 1956 | name++; | ||
| 1957 | } | 1900 | } |
| 1958 | while ( *name ); | 1901 | while ( *name ); |
| 1959 | if (IS_DIRECTORY_SEP (name[0])) | 1902 | if (IS_DIRECTORY_SEP (name[0])) |
| @@ -1970,23 +1913,44 @@ parse_root (char * name, char ** pPath) | |||
| 1970 | static int | 1913 | static int |
| 1971 | get_long_basename (char * name, char * buf, int size) | 1914 | get_long_basename (char * name, char * buf, int size) |
| 1972 | { | 1915 | { |
| 1973 | WIN32_FIND_DATA find_data; | ||
| 1974 | HANDLE dir_handle; | 1916 | HANDLE dir_handle; |
| 1917 | char fname_utf8[MAX_UTF8_PATH]; | ||
| 1975 | int len = 0; | 1918 | int len = 0; |
| 1919 | int cstatus; | ||
| 1976 | 1920 | ||
| 1977 | /* must be valid filename, no wild cards or other invalid characters */ | 1921 | /* Must be valid filename, no wild cards or other invalid characters. */ |
| 1978 | if (_mbspbrk (name, "*?|<>\"")) | 1922 | if (strpbrk (name, "*?|<>\"")) |
| 1979 | return 0; | 1923 | return 0; |
| 1980 | 1924 | ||
| 1981 | dir_handle = FindFirstFile (name, &find_data); | 1925 | if (w32_unicode_filenames) |
| 1982 | if (dir_handle != INVALID_HANDLE_VALUE) | ||
| 1983 | { | 1926 | { |
| 1984 | if ((len = strlen (find_data.cFileName)) < size) | 1927 | wchar_t fname_utf16[MAX_PATH]; |
| 1985 | memcpy (buf, find_data.cFileName, len + 1); | 1928 | WIN32_FIND_DATAW find_data_wide; |
| 1986 | else | 1929 | |
| 1987 | len = 0; | 1930 | filename_to_utf16 (name, fname_utf16); |
| 1988 | FindClose (dir_handle); | 1931 | dir_handle = FindFirstFileW (fname_utf16, &find_data_wide); |
| 1932 | if (dir_handle != INVALID_HANDLE_VALUE) | ||
| 1933 | cstatus = filename_from_utf16 (find_data_wide.cFileName, fname_utf8); | ||
| 1934 | } | ||
| 1935 | else | ||
| 1936 | { | ||
| 1937 | char fname_ansi[MAX_PATH]; | ||
| 1938 | WIN32_FIND_DATAA find_data_ansi; | ||
| 1939 | |||
| 1940 | filename_to_ansi (name, fname_ansi); | ||
| 1941 | dir_handle = FindFirstFileA (fname_ansi, &find_data_ansi); | ||
| 1942 | if (dir_handle != INVALID_HANDLE_VALUE) | ||
| 1943 | cstatus = filename_from_ansi (find_data_ansi.cFileName, fname_utf8); | ||
| 1989 | } | 1944 | } |
| 1945 | |||
| 1946 | if (cstatus == 0 && (len = strlen (fname_utf8)) < size) | ||
| 1947 | memcpy (buf, fname_utf8, len + 1); | ||
| 1948 | else | ||
| 1949 | len = 0; | ||
| 1950 | |||
| 1951 | if (dir_handle != INVALID_HANDLE_VALUE) | ||
| 1952 | FindClose (dir_handle); | ||
| 1953 | |||
| 1990 | return len; | 1954 | return len; |
| 1991 | } | 1955 | } |
| 1992 | 1956 | ||
| @@ -1997,11 +1961,11 @@ w32_get_long_filename (char * name, char * buf, int size) | |||
| 1997 | char * o = buf; | 1961 | char * o = buf; |
| 1998 | char * p; | 1962 | char * p; |
| 1999 | char * q; | 1963 | char * q; |
| 2000 | char full[ MAX_PATH ]; | 1964 | char full[ MAX_UTF8_PATH ]; |
| 2001 | int len; | 1965 | int len; |
| 2002 | 1966 | ||
| 2003 | len = strlen (name); | 1967 | len = strlen (name); |
| 2004 | if (len >= MAX_PATH) | 1968 | if (len >= MAX_UTF8_PATH) |
| 2005 | return FALSE; | 1969 | return FALSE; |
| 2006 | 1970 | ||
| 2007 | /* Use local copy for destructive modification. */ | 1971 | /* Use local copy for destructive modification. */ |
| @@ -2018,7 +1982,7 @@ w32_get_long_filename (char * name, char * buf, int size) | |||
| 2018 | while (p != NULL && *p) | 1982 | while (p != NULL && *p) |
| 2019 | { | 1983 | { |
| 2020 | q = p; | 1984 | q = p; |
| 2021 | p = _mbschr (q, '\\'); | 1985 | p = strchr (q, '\\'); |
| 2022 | if (p) *p = '\0'; | 1986 | if (p) *p = '\0'; |
| 2023 | len = get_long_basename (full, o, size); | 1987 | len = get_long_basename (full, o, size); |
| 2024 | if (len > 0) | 1988 | if (len > 0) |
| @@ -2042,6 +2006,29 @@ w32_get_long_filename (char * name, char * buf, int size) | |||
| 2042 | return TRUE; | 2006 | return TRUE; |
| 2043 | } | 2007 | } |
| 2044 | 2008 | ||
| 2009 | unsigned int | ||
| 2010 | w32_get_short_filename (char * name, char * buf, int size) | ||
| 2011 | { | ||
| 2012 | if (w32_unicode_filenames) | ||
| 2013 | { | ||
| 2014 | wchar_t name_utf16[MAX_PATH], short_name[MAX_PATH]; | ||
| 2015 | unsigned int retval; | ||
| 2016 | |||
| 2017 | filename_to_utf16 (name, name_utf16); | ||
| 2018 | retval = GetShortPathNameW (name_utf16, short_name, size); | ||
| 2019 | if (retval && retval < size) | ||
| 2020 | filename_from_utf16 (short_name, buf); | ||
| 2021 | return retval; | ||
| 2022 | } | ||
| 2023 | else | ||
| 2024 | { | ||
| 2025 | char name_ansi[MAX_PATH]; | ||
| 2026 | |||
| 2027 | filename_to_ansi (name, name_ansi); | ||
| 2028 | return GetShortPathNameA (name_ansi, buf, size); | ||
| 2029 | } | ||
| 2030 | } | ||
| 2031 | |||
| 2045 | static int | 2032 | static int |
| 2046 | is_unc_volume (const char *filename) | 2033 | is_unc_volume (const char *filename) |
| 2047 | { | 2034 | { |
| @@ -2506,7 +2493,7 @@ emacs_root_dir (void) | |||
| 2506 | emacs_abort (); | 2493 | emacs_abort (); |
| 2507 | strcpy (root_dir, p); | 2494 | strcpy (root_dir, p); |
| 2508 | root_dir[parse_root (root_dir, NULL)] = '\0'; | 2495 | root_dir[parse_root (root_dir, NULL)] = '\0'; |
| 2509 | dostounix_filename (root_dir, 0); | 2496 | dostounix_filename (root_dir); |
| 2510 | return root_dir; | 2497 | return root_dir; |
| 2511 | } | 2498 | } |
| 2512 | 2499 | ||
| @@ -3937,49 +3924,6 @@ convert_from_time_t (time_t time, FILETIME * pft) | |||
| 3937 | pft->dwLowDateTime = tmp.LowPart; | 3924 | pft->dwLowDateTime = tmp.LowPart; |
| 3938 | } | 3925 | } |
| 3939 | 3926 | ||
| 3940 | #if 0 | ||
| 3941 | /* No reason to keep this; faking inode values either by hashing or even | ||
| 3942 | using the file index from GetInformationByHandle, is not perfect and | ||
| 3943 | so by default Emacs doesn't use the inode values on Windows. | ||
| 3944 | Instead, we now determine file-truename correctly (except for | ||
| 3945 | possible drive aliasing etc). */ | ||
| 3946 | |||
| 3947 | /* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */ | ||
| 3948 | static unsigned | ||
| 3949 | hashval (const unsigned char * str) | ||
| 3950 | { | ||
| 3951 | unsigned h = 0; | ||
| 3952 | while (*str) | ||
| 3953 | { | ||
| 3954 | h = (h << 4) + *str++; | ||
| 3955 | h ^= (h >> 28); | ||
| 3956 | } | ||
| 3957 | return h; | ||
| 3958 | } | ||
| 3959 | |||
| 3960 | /* Return the hash value of the canonical pathname, excluding the | ||
| 3961 | drive/UNC header, to get a hopefully unique inode number. */ | ||
| 3962 | static DWORD | ||
| 3963 | generate_inode_val (const char * name) | ||
| 3964 | { | ||
| 3965 | char fullname[ MAX_PATH ]; | ||
| 3966 | char * p; | ||
| 3967 | unsigned hash; | ||
| 3968 | |||
| 3969 | /* Get the truly canonical filename, if it exists. (Note: this | ||
| 3970 | doesn't resolve aliasing due to subst commands, or recognize hard | ||
| 3971 | links. */ | ||
| 3972 | if (!w32_get_long_filename ((char *)name, fullname, MAX_PATH)) | ||
| 3973 | emacs_abort (); | ||
| 3974 | |||
| 3975 | parse_root (fullname, &p); | ||
| 3976 | /* Normal W32 filesystems are still case insensitive. */ | ||
| 3977 | _strlwr (p); | ||
| 3978 | return hashval (p); | ||
| 3979 | } | ||
| 3980 | |||
| 3981 | #endif | ||
| 3982 | |||
| 3983 | static PSECURITY_DESCRIPTOR | 3927 | static PSECURITY_DESCRIPTOR |
| 3984 | get_file_security_desc_by_handle (HANDLE h) | 3928 | get_file_security_desc_by_handle (HANDLE h) |
| 3985 | { | 3929 | { |