diff options
| author | Eli Zaretskii | 2013-11-16 14:31:46 +0200 |
|---|---|---|
| committer | Eli Zaretskii | 2013-11-16 14:31:46 +0200 |
| commit | 6349f70a31a56fbaf8b5dbcaaddf624d137f9d63 (patch) | |
| tree | a4d71332559cce3c08050c44715e9b3148de02b6 /src | |
| parent | e75e4a8986772112ba6e2bd80bb1a18e6124985b (diff) | |
| download | emacs-6349f70a31a56fbaf8b5dbcaaddf624d137f9d63.tar.gz emacs-6349f70a31a56fbaf8b5dbcaaddf624d137f9d63.zip | |
sys_link works, including enhanced error handling.
Diffstat (limited to 'src')
| -rw-r--r-- | src/w32.c | 60 |
1 files changed, 53 insertions, 7 deletions
| @@ -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 | ||