aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorEli Zaretskii2013-11-09 14:49:02 +0200
committerEli Zaretskii2013-11-09 14:49:02 +0200
commit0b9de7cd600054dfbe6252b73995302200b8597e (patch)
tree3561fd8af235fb8b5c7a6291adceb427024bfae9 /src
parentf5441ba43c16303b129192504a0731a0ee0df47e (diff)
downloademacs-0b9de7cd600054dfbe6252b73995302200b8597e.tar.gz
emacs-0b9de7cd600054dfbe6252b73995302200b8597e.zip
Dirent functions and directory-files are converted and work.
Diffstat (limited to 'src')
-rw-r--r--src/w32.c320
1 files changed, 206 insertions, 114 deletions
diff --git a/src/w32.c b/src/w32.c
index f0812cc3420..16e381564ee 100644
--- a/src/w32.c
+++ b/src/w32.c
@@ -2934,25 +2934,28 @@ is_exec (const char * name)
2934 xstrcasecmp (p, ".cmd") == 0)); 2934 xstrcasecmp (p, ".cmd") == 0));
2935} 2935}
2936 2936
2937/* Emulate the Unix directory procedures opendir, closedir, 2937/* Emulate the Unix directory procedures opendir, closedir, and
2938 and readdir. We can't use the procedures supplied in sysdep.c, 2938 readdir. We rename them to sys_* names because some versions of
2939 so we provide them here. */ 2939 MinGW startup code call opendir and readdir to glob wildcards, and
2940 the code that calls them doesn't grok UTF-8 encoded file names we
2941 produce in dirent->d_name[]. */
2940 2942
2941struct dirent dir_static; /* simulated directory contents */ 2943struct dirent dir_static; /* simulated directory contents */
2942static HANDLE dir_find_handle = INVALID_HANDLE_VALUE; 2944static HANDLE dir_find_handle = INVALID_HANDLE_VALUE;
2943static int dir_is_fat; 2945static int dir_is_fat;
2944static char dir_pathname[MAXPATHLEN+1]; 2946static char dir_pathname[MAX_UTF8_PATH];
2945static WIN32_FIND_DATA dir_find_data; 2947static WIN32_FIND_DATAW dir_find_data_w;
2948static WIN32_FIND_DATAA dir_find_data_a;
2946 2949
2947/* Support shares on a network resource as subdirectories of a read-only 2950/* Support shares on a network resource as subdirectories of a read-only
2948 root directory. */ 2951 root directory. */
2949static HANDLE wnet_enum_handle = INVALID_HANDLE_VALUE; 2952static HANDLE wnet_enum_handle = INVALID_HANDLE_VALUE;
2950static HANDLE open_unc_volume (const char *); 2953static HANDLE open_unc_volume (const char *);
2951static char *read_unc_volume (HANDLE, char *, int); 2954static void *read_unc_volume (HANDLE, wchar_t *, char *, int);
2952static void close_unc_volume (HANDLE); 2955static void close_unc_volume (HANDLE);
2953 2956
2954DIR * 2957DIR *
2955opendir (const char *filename) 2958sys_opendir (const char *filename)
2956{ 2959{
2957 DIR *dirp; 2960 DIR *dirp;
2958 2961
@@ -2981,8 +2984,8 @@ opendir (const char *filename)
2981 dirp->dd_loc = 0; 2984 dirp->dd_loc = 0;
2982 dirp->dd_size = 0; 2985 dirp->dd_size = 0;
2983 2986
2984 strncpy (dir_pathname, map_w32_filename (filename, NULL), MAXPATHLEN); 2987 strncpy (dir_pathname, map_w32_filename (filename, NULL), MAX_UTF8_PATH - 1);
2985 dir_pathname[MAXPATHLEN] = '\0'; 2988 dir_pathname[MAX_UTF8_PATH - 1] = '\0';
2986 /* Note: We don't support symlinks to file names on FAT volumes. 2989 /* Note: We don't support symlinks to file names on FAT volumes.
2987 Doing so would mean punishing 99.99% of use cases by resolving 2990 Doing so would mean punishing 99.99% of use cases by resolving
2988 all the possible symlinks in FILENAME, recursively. */ 2991 all the possible symlinks in FILENAME, recursively. */
@@ -2992,7 +2995,7 @@ opendir (const char *filename)
2992} 2995}
2993 2996
2994void 2997void
2995closedir (DIR *dirp) 2998sys_closedir (DIR *dirp)
2996{ 2999{
2997 /* If we have a find-handle open, close it. */ 3000 /* If we have a find-handle open, close it. */
2998 if (dir_find_handle != INVALID_HANDLE_VALUE) 3001 if (dir_find_handle != INVALID_HANDLE_VALUE)
@@ -3009,52 +3012,59 @@ closedir (DIR *dirp)
3009} 3012}
3010 3013
3011struct dirent * 3014struct dirent *
3012readdir (DIR *dirp) 3015sys_readdir (DIR *dirp)
3013{ 3016{
3014 int downcase = !NILP (Vw32_downcase_file_names); 3017 int downcase = !NILP (Vw32_downcase_file_names);
3015 3018
3016 if (wnet_enum_handle != INVALID_HANDLE_VALUE) 3019 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
3017 { 3020 {
3018 if (!read_unc_volume (wnet_enum_handle, 3021 if (!read_unc_volume (wnet_enum_handle,
3019 dir_find_data.cFileName, 3022 dir_find_data_w.cFileName,
3023 dir_find_data_a.cFileName,
3020 MAX_PATH)) 3024 MAX_PATH))
3021 return NULL; 3025 return NULL;
3022 } 3026 }
3023 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */ 3027 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
3024 else if (dir_find_handle == INVALID_HANDLE_VALUE) 3028 else if (dir_find_handle == INVALID_HANDLE_VALUE)
3025 { 3029 {
3026 char filename[MAXNAMLEN + 3]; 3030 char filename[MAX_UTF8_PATH + 2];
3027 int ln; 3031 int ln;
3028 int dbcs_p = max_filename_mbslen () > 1;
3029 3032
3030 strcpy (filename, dir_pathname); 3033 strcpy (filename, dir_pathname);
3031 ln = strlen (filename) - 1; 3034 ln = strlen (filename) - 1;
3032 if (!dbcs_p) 3035 if (!IS_DIRECTORY_SEP (filename[ln]))
3036 strcat (filename, "\\");
3037 strcat (filename, "*");
3038
3039 /* Note: No need to resolve symlinks in FILENAME, because
3040 FindFirst opens the directory that is the target of a
3041 symlink. */
3042 if (w32_unicode_filenames)
3033 { 3043 {
3034 if (!IS_DIRECTORY_SEP (filename[ln])) 3044 wchar_t fnw[MAX_PATH];
3035 strcat (filename, "\\"); 3045
3046 filename_to_utf16 (filename, fnw);
3047 dir_find_handle = FindFirstFileW (fnw, &dir_find_data_w);
3036 } 3048 }
3037 else 3049 else
3038 { 3050 {
3039 char *end = filename + ln + 1; 3051 char fna[MAX_PATH];
3040 char *last_char = CharPrevExA (file_name_codepage, filename, end, 0);
3041 3052
3042 if (!IS_DIRECTORY_SEP (*last_char)) 3053 filename_to_ansi (filename, fna);
3043 strcat (filename, "\\"); 3054 dir_find_handle = FindFirstFileA (fna, &dir_find_data_a);
3044 } 3055 }
3045 strcat (filename, "*");
3046
3047 /* Note: No need to resolve symlinks in FILENAME, because
3048 FindFirst opens the directory that is the target of a
3049 symlink. */
3050 dir_find_handle = FindFirstFile (filename, &dir_find_data);
3051 3056
3052 if (dir_find_handle == INVALID_HANDLE_VALUE) 3057 if (dir_find_handle == INVALID_HANDLE_VALUE)
3053 return NULL; 3058 return NULL;
3054 } 3059 }
3060 else if (w32_unicode_filenames)
3061 {
3062 if (!FindNextFileW (dir_find_handle, &dir_find_data_w))
3063 return NULL;
3064 }
3055 else 3065 else
3056 { 3066 {
3057 if (!FindNextFile (dir_find_handle, &dir_find_data)) 3067 if (!FindNextFileA (dir_find_handle, &dir_find_data_a))
3058 return NULL; 3068 return NULL;
3059 } 3069 }
3060 3070
@@ -3062,112 +3072,153 @@ readdir (DIR *dirp)
3062 value returned by stat(). */ 3072 value returned by stat(). */
3063 dir_static.d_ino = 1; 3073 dir_static.d_ino = 1;
3064 3074
3065 strcpy (dir_static.d_name, dir_find_data.cFileName); 3075 if (w32_unicode_filenames)
3066
3067 /* If the file name in cFileName[] includes `?' characters, it means
3068 the original file name used characters that cannot be represented
3069 by the current ANSI codepage. To avoid total lossage, retrieve
3070 the short 8+3 alias of the long file name. */
3071 if (_mbspbrk (dir_static.d_name, "?"))
3072 { 3076 {
3073 strcpy (dir_static.d_name, dir_find_data.cAlternateFileName); 3077 if (downcase || dir_is_fat)
3074 downcase = 1; /* 8+3 aliases are returned in all caps */ 3078 {
3075 } 3079 wchar_t tem[MAX_PATH];
3076 dir_static.d_namlen = strlen (dir_static.d_name);
3077 dir_static.d_reclen = sizeof (struct dirent) - MAXNAMLEN + 3 +
3078 dir_static.d_namlen - dir_static.d_namlen % 4;
3079 3080
3080 /* If the file name in cFileName[] includes `?' characters, it means 3081 wcscpy (tem, dir_find_data_w.cFileName);
3081 the original file name used characters that cannot be represented 3082 CharLowerW (tem);
3082 by the current ANSI codepage. To avoid total lossage, retrieve 3083 filename_from_utf16 (tem, dir_static.d_name);
3083 the short 8+3 alias of the long file name. */ 3084 }
3084 if (_mbspbrk (dir_find_data.cFileName, "?")) 3085 else
3085 { 3086 filename_from_utf16 (dir_find_data_w.cFileName, dir_static.d_name);
3086 strcpy (dir_static.d_name, dir_find_data.cAlternateFileName);
3087 /* 8+3 aliases are returned in all caps, which could break
3088 various alists that look at filenames' extensions. */
3089 downcase = 1;
3090 } 3087 }
3091 else 3088 else
3092 strcpy (dir_static.d_name, dir_find_data.cFileName);
3093 dir_static.d_namlen = strlen (dir_static.d_name);
3094 if (dir_is_fat)
3095 _mbslwr (dir_static.d_name);
3096 else if (downcase)
3097 { 3089 {
3098 register char *p; 3090 char tem[MAX_PATH];
3099 int dbcs_p = max_filename_mbslen () > 1; 3091
3100 for (p = dir_static.d_name; *p; ) 3092 /* If the file name in cFileName[] includes `?' characters, it
3093 means the original file name used characters that cannot be
3094 represented by the current ANSI codepage. To avoid total
3095 lossage, retrieve the short 8+3 alias of the long file
3096 name. */
3097 if (_mbspbrk (dir_find_data_a.cFileName, "?"))
3101 { 3098 {
3102 if (*p >= 'a' && *p <= 'z') 3099 strcpy (tem, dir_find_data_a.cAlternateFileName);
3103 break; 3100 /* 8+3 aliases are returned in all caps, which could break
3104 if (dbcs_p) 3101 various alists that look at filenames' extensions. */
3105 p = CharNextExA (file_name_codepage, p, 0); 3102 downcase = 1;
3106 else 3103 }
3107 p++; 3104 else if (downcase || dir_is_fat)
3105 strcpy (tem, dir_find_data_a.cFileName);
3106 else
3107 filename_from_ansi (dir_find_data_a.cFileName, dir_static.d_name);
3108 if (downcase || dir_is_fat)
3109 {
3110 _mbslwr (tem);
3111 filename_from_ansi (tem, dir_static.d_name);
3108 } 3112 }
3109 if (!*p)
3110 _mbslwr (dir_static.d_name);
3111 } 3113 }
3112 3114
3115 dir_static.d_namlen = strlen (dir_static.d_name);
3116 dir_static.d_reclen = sizeof (struct dirent) - MAX_UTF8_PATH + 3 +
3117 dir_static.d_namlen - dir_static.d_namlen % 4;
3118
3113 return &dir_static; 3119 return &dir_static;
3114} 3120}
3115 3121
3116static HANDLE 3122static HANDLE
3117open_unc_volume (const char *path) 3123open_unc_volume (const char *path)
3118{ 3124{
3119 NETRESOURCE nr; 3125 const char *fn = map_w32_filename (path, NULL);
3126 DWORD result;
3120 HANDLE henum; 3127 HANDLE henum;
3121 int result;
3122 3128
3123 nr.dwScope = RESOURCE_GLOBALNET; 3129 if (w32_unicode_filenames)
3124 nr.dwType = RESOURCETYPE_DISK; 3130 {
3125 nr.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER; 3131 NETRESOURCEW nrw;
3126 nr.dwUsage = RESOURCEUSAGE_CONTAINER; 3132 wchar_t fnw[MAX_PATH];
3127 nr.lpLocalName = NULL;
3128 nr.lpRemoteName = (LPSTR)map_w32_filename (path, NULL);
3129 nr.lpComment = NULL;
3130 nr.lpProvider = NULL;
3131 3133
3132 result = WNetOpenEnum (RESOURCE_GLOBALNET, RESOURCETYPE_DISK, 3134 nrw.dwScope = RESOURCE_GLOBALNET;
3133 RESOURCEUSAGE_CONNECTABLE, &nr, &henum); 3135 nrw.dwType = RESOURCETYPE_DISK;
3136 nrw.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
3137 nrw.dwUsage = RESOURCEUSAGE_CONTAINER;
3138 nrw.lpLocalName = NULL;
3139 filename_to_utf16 (fn, fnw);
3140 nrw.lpRemoteName = fnw;
3141 nrw.lpComment = NULL;
3142 nrw.lpProvider = NULL;
3134 3143
3144 result = WNetOpenEnumW (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
3145 RESOURCEUSAGE_CONNECTABLE, &nrw, &henum);
3146 }
3147 else
3148 {
3149 NETRESOURCEA nra;
3150 char fna[MAX_PATH];
3151
3152 nra.dwScope = RESOURCE_GLOBALNET;
3153 nra.dwType = RESOURCETYPE_DISK;
3154 nra.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
3155 nra.dwUsage = RESOURCEUSAGE_CONTAINER;
3156 nra.lpLocalName = NULL;
3157 filename_to_ansi (fn, fna);
3158 nra.lpRemoteName = fna;
3159 nra.lpComment = NULL;
3160 nra.lpProvider = NULL;
3161
3162 result = WNetOpenEnumA (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
3163 RESOURCEUSAGE_CONNECTABLE, &nra, &henum);
3164 }
3135 if (result == NO_ERROR) 3165 if (result == NO_ERROR)
3136 return henum; 3166 return henum;
3137 else 3167 else
3138 return INVALID_HANDLE_VALUE; 3168 return INVALID_HANDLE_VALUE;
3139} 3169}
3140 3170
3141static char * 3171static void *
3142read_unc_volume (HANDLE henum, char *readbuf, int size) 3172read_unc_volume (HANDLE henum, wchar_t *fname_w, char *fname_a, int size)
3143{ 3173{
3144 DWORD count; 3174 DWORD count;
3145 int result; 3175 int result;
3146 DWORD bufsize = 512;
3147 char *buffer; 3176 char *buffer;
3148 char *ptr; 3177 DWORD bufsize = 512;
3149 int dbcs_p = max_filename_mbslen () > 1; 3178 void *retval;
3150 3179
3151 count = 1; 3180 count = 1;
3152 buffer = alloca (bufsize); 3181 if (w32_unicode_filenames)
3153 result = WNetEnumResource (henum, &count, buffer, &bufsize); 3182 {
3154 if (result != NO_ERROR) 3183 wchar_t *ptrw;
3155 return NULL;
3156 3184
3157 /* WNetEnumResource returns \\resource\share...skip forward to "share". */ 3185 bufsize *= 2;
3158 ptr = ((LPNETRESOURCE) buffer)->lpRemoteName; 3186 buffer = alloca (bufsize);
3159 ptr += 2; 3187 result = WNetEnumResourceW (henum, &count, buffer, &bufsize);
3160 if (!dbcs_p) 3188 if (result != NO_ERROR)
3161 while (*ptr && !IS_DIRECTORY_SEP (*ptr)) ptr++; 3189 return NULL;
3190 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
3191 ptrw = ((LPNETRESOURCEW) buffer)->lpRemoteName;
3192 ptrw += 2;
3193 while (*ptrw && *ptrw != L'/' && *ptrw != L'\\') ptrw++;
3194 ptrw++;
3195 wcsncpy (fname_w, ptrw, size);
3196 retval = fname_w;
3197 }
3162 else 3198 else
3163 { 3199 {
3164 while (*ptr && !IS_DIRECTORY_SEP (*ptr)) 3200 int dbcs_p = max_filename_mbslen () > 1;
3165 ptr = CharNextExA (file_name_codepage, ptr, 0); 3201 char *ptra;
3202
3203 buffer = alloca (bufsize);
3204 result = WNetEnumResourceA (henum, &count, buffer, &bufsize);
3205 if (result != NO_ERROR)
3206 return NULL;
3207 ptra = ((LPNETRESOURCEA) buffer)->lpRemoteName;
3208 ptra += 2;
3209 if (!dbcs_p)
3210 while (*ptra && !IS_DIRECTORY_SEP (*ptra)) ptra++;
3211 else
3212 {
3213 while (*ptra && !IS_DIRECTORY_SEP (*ptra))
3214 ptra = CharNextExA (file_name_codepage, ptra, 0);
3215 }
3216 ptra++;
3217 strncpy (fname_a, ptra, size);
3218 retval = fname_a;
3166 } 3219 }
3167 ptr++;
3168 3220
3169 strncpy (readbuf, ptr, size); 3221 return retval;
3170 return readbuf;
3171} 3222}
3172 3223
3173static void 3224static void
@@ -3198,13 +3249,12 @@ unc_volume_file_attributes (const char *path)
3198static void 3249static void
3199logon_network_drive (const char *path) 3250logon_network_drive (const char *path)
3200{ 3251{
3201 NETRESOURCE resource; 3252 char share[MAX_UTF8_PATH];
3202 char share[MAX_PATH];
3203 int n_slashes; 3253 int n_slashes;
3204 char drive[4]; 3254 char drive[4];
3205 UINT drvtype; 3255 UINT drvtype;
3206 char *p; 3256 char *p;
3207 int dbcs_p; 3257 DWORD val;
3208 3258
3209 if (IS_DIRECTORY_SEP (path[0]) && IS_DIRECTORY_SEP (path[1])) 3259 if (IS_DIRECTORY_SEP (path[0]) && IS_DIRECTORY_SEP (path[1]))
3210 drvtype = DRIVE_REMOTE; 3260 drvtype = DRIVE_REMOTE;
@@ -3224,28 +3274,70 @@ logon_network_drive (const char *path)
3224 return; 3274 return;
3225 3275
3226 n_slashes = 2; 3276 n_slashes = 2;
3227 strncpy (share, path, MAX_PATH); 3277 strncpy (share, path, MAX_UTF8_PATH);
3228 /* Truncate to just server and share name. */ 3278 /* Truncate to just server and share name. */
3229 dbcs_p = max_filename_mbslen () > 1; 3279 for (p = share + 2; *p && p < share + MAX_UTF8_PATH; p++)
3230 for (p = share + 2; *p && p < share + MAX_PATH; )
3231 { 3280 {
3232 if (IS_DIRECTORY_SEP (*p) && ++n_slashes > 3) 3281 if (IS_DIRECTORY_SEP (*p) && ++n_slashes > 3)
3233 { 3282 {
3234 *p = '\0'; 3283 *p = '\0';
3235 break; 3284 break;
3236 } 3285 }
3237 if (dbcs_p)
3238 p = CharNextExA (file_name_codepage, p, 0);
3239 else
3240 p++;
3241 } 3286 }
3242 3287
3243 resource.dwType = RESOURCETYPE_DISK; 3288 if (w32_unicode_filenames)
3244 resource.lpLocalName = NULL; 3289 {
3245 resource.lpRemoteName = share; 3290 NETRESOURCEW resourcew;
3246 resource.lpProvider = NULL; 3291 wchar_t share_w[MAX_PATH];
3292
3293 resourcew.dwScope = RESOURCE_GLOBALNET;
3294 resourcew.dwType = RESOURCETYPE_DISK;
3295 resourcew.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
3296 resourcew.dwUsage = RESOURCEUSAGE_CONTAINER;
3297 resourcew.lpLocalName = NULL;
3298 filename_to_utf16 (share, share_w);
3299 resourcew.lpRemoteName = share_w;
3300 resourcew.lpProvider = NULL;
3247 3301
3248 WNetAddConnection2 (&resource, NULL, NULL, CONNECT_INTERACTIVE); 3302 val = WNetAddConnection2W (&resourcew, NULL, NULL, CONNECT_INTERACTIVE);
3303 }
3304 else
3305 {
3306 NETRESOURCEA resourcea;
3307 char share_a[MAX_PATH];
3308
3309 resourcea.dwScope = RESOURCE_GLOBALNET;
3310 resourcea.dwType = RESOURCETYPE_DISK;
3311 resourcea.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
3312 resourcea.dwUsage = RESOURCEUSAGE_CONTAINER;
3313 resourcea.lpLocalName = NULL;
3314 filename_to_ansi (share, share_a);
3315 resourcea.lpRemoteName = share_a;
3316 resourcea.lpProvider = NULL;
3317
3318 val = WNetAddConnection2A (&resourcea, NULL, NULL, CONNECT_INTERACTIVE);
3319 }
3320
3321 switch (val)
3322 {
3323 case NO_ERROR:
3324 case ERROR_ALREADY_ASSIGNED:
3325 break;
3326 case ERROR_ACCESS_DENIED:
3327 case ERROR_LOGON_FAILURE:
3328 errno = EACCES;
3329 break;
3330 case ERROR_BUSY:
3331 errno = EAGAIN;
3332 break;
3333 case ERROR_BAD_NET_NAME:
3334 case ERROR_NO_NET_OR_BAD_PATH:
3335 case ERROR_NO_NETWORK:
3336 case ERROR_CANCELLED:
3337 default:
3338 errno = ENOENT;
3339 break;
3340 }
3249} 3341}
3250 3342
3251/* Emulate faccessat(2). */ 3343/* Emulate faccessat(2). */
@@ -4338,7 +4430,7 @@ stat_worker (const char * path, struct stat * buf, int follow_symlinks)
4338 && xstrcasecmp (name + len + 1, dir_static.d_name) == 0) 4430 && xstrcasecmp (name + len + 1, dir_static.d_name) == 0)
4339 { 4431 {
4340 /* This was the last entry returned by readdir. */ 4432 /* This was the last entry returned by readdir. */
4341 wfd = dir_find_data; 4433 wfd = dir_find_data_a; /* FIXME!!! */
4342 } 4434 }
4343 else 4435 else
4344 { 4436 {