aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorEli Zaretskii2013-11-16 14:31:46 +0200
committerEli Zaretskii2013-11-16 14:31:46 +0200
commit6349f70a31a56fbaf8b5dbcaaddf624d137f9d63 (patch)
treea4d71332559cce3c08050c44715e9b3148de02b6 /src
parente75e4a8986772112ba6e2bd80bb1a18e6124985b (diff)
downloademacs-6349f70a31a56fbaf8b5dbcaaddf624d137f9d63.tar.gz
emacs-6349f70a31a56fbaf8b5dbcaaddf624d137f9d63.zip
sys_link works, including enhanced error handling.
Diffstat (limited to 'src')
-rw-r--r--src/w32.c60
1 files changed, 53 insertions, 7 deletions
diff --git a/src/w32.c b/src/w32.c
index f5938314d16..46f36de8b92 100644
--- a/src/w32.c
+++ b/src/w32.c
@@ -3615,7 +3615,9 @@ sys_link (const char * old, const char * new)
3615{ 3615{
3616 HANDLE fileh; 3616 HANDLE fileh;
3617 int result = -1; 3617 int result = -1;
3618 char oldname[MAX_PATH], newname[MAX_PATH]; 3618 char oldname[MAX_UTF8_PATH], newname[MAX_UTF8_PATH];
3619 wchar_t oldname_w[MAX_PATH];
3620 char oldname_a[MAX_PATH];
3619 3621
3620 if (old == NULL || new == NULL) 3622 if (old == NULL || new == NULL)
3621 { 3623 {
@@ -3626,8 +3628,18 @@ sys_link (const char * old, const char * new)
3626 strcpy (oldname, map_w32_filename (old, NULL)); 3628 strcpy (oldname, map_w32_filename (old, NULL));
3627 strcpy (newname, map_w32_filename (new, NULL)); 3629 strcpy (newname, map_w32_filename (new, NULL));
3628 3630
3629 fileh = CreateFile (oldname, 0, 0, NULL, OPEN_EXISTING, 3631 if (w32_unicode_filenames)
3630 FILE_FLAG_BACKUP_SEMANTICS, NULL); 3632 {
3633 filename_to_utf16 (oldname, oldname_w);
3634 fileh = CreateFileW (oldname_w, 0, 0, NULL, OPEN_EXISTING,
3635 FILE_FLAG_BACKUP_SEMANTICS, NULL);
3636 }
3637 else
3638 {
3639 filename_to_ansi (oldname, oldname_a);
3640 fileh = CreateFileA (oldname_a, 0, 0, NULL, OPEN_EXISTING,
3641 FILE_FLAG_BACKUP_SEMANTICS, NULL);
3642 }
3631 if (fileh != INVALID_HANDLE_VALUE) 3643 if (fileh != INVALID_HANDLE_VALUE)
3632 { 3644 {
3633 int wlen; 3645 int wlen;
@@ -3644,7 +3656,10 @@ sys_link (const char * old, const char * new)
3644 WCHAR wbuffer[MAX_PATH]; /* extra space for link name */ 3656 WCHAR wbuffer[MAX_PATH]; /* extra space for link name */
3645 } data; 3657 } data;
3646 3658
3647 wlen = MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, newname, -1, 3659 /* We used to pass MB_PRECOMPOSED as the 2nd arg here, but MSDN
3660 indicates that flag is unsupported for CP_UTF8, and OTOH says
3661 it is the default anyway. */
3662 wlen = MultiByteToWideChar (CP_UTF8, 0, newname, -1,
3648 data.wid.cStreamName, MAX_PATH); 3663 data.wid.cStreamName, MAX_PATH);
3649 if (wlen > 0) 3664 if (wlen > 0)
3650 { 3665 {
@@ -3668,9 +3683,40 @@ sys_link (const char * old, const char * new)
3668 } 3683 }
3669 else 3684 else
3670 { 3685 {
3671 /* Should try mapping GetLastError to errno; for now just 3686 DWORD err = GetLastError ();
3672 indicate a general error (eg. links not supported). */ 3687 DWORD attributes;
3673 errno = EINVAL; // perhaps EMLINK? 3688
3689 switch (err)
3690 {
3691 case ERROR_ACCESS_DENIED:
3692 /* This is what happens when OLDNAME is a directory,
3693 since Windows doesn't support hard links to
3694 directories. Posix says to set errno to EPERM in
3695 that case. */
3696 if (w32_unicode_filenames)
3697 attributes = GetFileAttributesW (oldname_w);
3698 else
3699 attributes = GetFileAttributesA (oldname_a);
3700 if (attributes != -1
3701 && (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
3702 errno = EPERM;
3703 else if (attributes == -1
3704 && is_unc_volume (oldname)
3705 && unc_volume_file_attributes (oldname) != -1)
3706 errno = EPERM;
3707 else
3708 errno = EACCES;
3709 break;
3710 case ERROR_TOO_MANY_LINKS:
3711 errno = EMLINK;
3712 break;
3713 case ERROR_NOT_SAME_DEVICE:
3714 errno = EXDEV;
3715 break;
3716 default:
3717 errno = EINVAL;
3718 break;
3719 }
3674 } 3720 }
3675 } 3721 }
3676 3722