]>
Commit | Line | Data |
---|---|---|
b24c88b3 | 1 | #include <stdlib.h> |
d2e8d256 | 2 | #include <wchar.h> |
904d24fe | 3 | #include "win32.h" |
d2e8d256 | 4 | #include "ntdll.h" |
904d24fe | 5 | #include "shlobj.h" |
b24c88b3 | 6 | #include "mklink2.h" |
2f0315ad | 7 | #include "filemanip.h" |
904d24fe | 8 | |
b24c88b3 RC |
9 | #if 0 |
10 | static const char *cvsid = | |
11 | "\n%%% $Id$\n"; | |
12 | #endif | |
8507f105 | 13 | |
904d24fe DD |
14 | /* This part of the code must be in C because the C++ interface to COM |
15 | doesn't work. */ | |
16 | ||
e36b0f1e CV |
17 | /* Initialized in WinMain. This is required under Windows 7. If |
18 | CoCreateInstance gets called from here, it fails to create the | |
19 | instance with an undocumented error code 0x80110474. | |
20 | FIXME: I have no idea why this happens. */ | |
21 | IShellLink *sl; | |
22 | ||
51ebb760 | 23 | extern "C" |
904d24fe | 24 | void |
3c054baf | 25 | make_link_2 (char const *exepath, char const *args, char const *icon, char const *lname) |
904d24fe | 26 | { |
904d24fe | 27 | IPersistFile *pf; |
4875ac88 | 28 | WCHAR widepath[MAX_PATH]; |
e36b0f1e CV |
29 | if (sl) |
30 | { | |
c0e55e84 | 31 | sl->QueryInterface (IID_IPersistFile, (void **) &pf); |
904d24fe | 32 | |
c0e55e84 YS |
33 | sl->SetPath (exepath); |
34 | sl->SetArguments (args); | |
35 | sl->SetIconLocation (icon, 0); | |
904d24fe | 36 | |
e36b0f1e | 37 | MultiByteToWideChar (CP_ACP, 0, lname, -1, widepath, MAX_PATH); |
c0e55e84 | 38 | pf->Save (widepath, TRUE); |
904d24fe | 39 | |
c0e55e84 | 40 | pf->Release (); |
e36b0f1e | 41 | } |
904d24fe | 42 | } |
b24c88b3 RC |
43 | |
44 | #define SYMLINK_COOKIE "!<symlink>" | |
45 | ||
46 | /* Predicate: file is not currently in existence. | |
47 | * A file race can occur otherwise. | |
48 | */ | |
2f0315ad CV |
49 | static int |
50 | mkcygsymlink_9x (const char *from, const char *to) | |
b24c88b3 RC |
51 | { |
52 | char buf[512]; | |
53 | unsigned long w; | |
2f0315ad | 54 | |
b24c88b3 | 55 | HANDLE h = CreateFileA (from, GENERIC_WRITE, 0, 0, CREATE_NEW, |
b41c2908 | 56 | FILE_ATTRIBUTE_NORMAL, 0); |
b24c88b3 RC |
57 | if (h == INVALID_HANDLE_VALUE) |
58 | return 1; | |
59 | strcpy (buf, SYMLINK_COOKIE); | |
60 | strcat (buf, to); | |
61 | if (WriteFile (h, buf, strlen (buf) + 1, &w, NULL)) | |
62 | { | |
63 | CloseHandle (h); | |
64 | SetFileAttributesA (from, FILE_ATTRIBUTE_SYSTEM); | |
65 | return 0; | |
66 | } | |
67 | CloseHandle (h); | |
68 | DeleteFileA (from); | |
69 | return 1; | |
70 | } | |
2f0315ad CV |
71 | |
72 | static int | |
73 | mkcygsymlink_nt (const char *from, const char *to) | |
74 | { | |
770e3aed | 75 | char buf[strlen (SYMLINK_COOKIE) + 4096]; |
2f0315ad CV |
76 | unsigned long w; |
77 | const size_t len = strlen (from) + 7; | |
78 | WCHAR wfrom[len]; | |
21aa9a8b | 79 | HANDLE h; |
26922cd2 CV |
80 | SECURITY_DESCRIPTOR sd; |
81 | acl_t acl; | |
82 | SECURITY_ATTRIBUTES sa = { sizeof (SECURITY_ATTRIBUTES), | |
83 | nt_sec.GetPosixPerms (from, NULL, NULL, 0644, | |
84 | sd, acl), | |
85 | FALSE }; | |
2f0315ad CV |
86 | |
87 | mklongpath (wfrom, from, len); | |
26922cd2 | 88 | h = CreateFileW (wfrom, GENERIC_WRITE, 0, &sa, CREATE_NEW, |
21aa9a8b | 89 | FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, 0); |
2f0315ad | 90 | if (h == INVALID_HANDLE_VALUE) |
26922cd2 | 91 | return 1; |
2f0315ad | 92 | strcpy (buf, SYMLINK_COOKIE); |
770e3aed | 93 | strncat (buf, to, 4095); |
2f0315ad CV |
94 | if (WriteFile (h, buf, strlen (buf) + 1, &w, NULL)) |
95 | { | |
96 | CloseHandle (h); | |
97 | SetFileAttributesW (wfrom, FILE_ATTRIBUTE_SYSTEM); | |
98 | return 0; | |
99 | } | |
100 | CloseHandle (h); | |
101 | DeleteFileW (wfrom); | |
102 | return 1; | |
103 | } | |
104 | ||
105 | extern "C" | |
106 | int | |
107 | mkcygsymlink (const char *from, const char *to) | |
108 | { | |
109 | return IsWindowsNT () ? mkcygsymlink_nt (from, to) | |
110 | : mkcygsymlink_9x (from, to); | |
111 | } | |
d2e8d256 | 112 | |
10b2d051 | 113 | static struct { |
d2e8d256 CV |
114 | FILE_LINK_INFORMATION fli; |
115 | WCHAR namebuf[32768]; | |
116 | } sfli; | |
117 | ||
118 | extern "C" | |
119 | int | |
120 | mkcyghardlink (const char *from, const char *to) | |
121 | { | |
122 | if (!IsWindowsNT ()) | |
123 | return 1; | |
124 | ||
125 | size_t flen = strlen (from) + 7; | |
126 | size_t tlen = strlen (to) + 7; | |
127 | wchar_t wfrom[flen]; | |
128 | wchar_t wto[tlen]; | |
129 | mklongpath (wfrom, from, flen); | |
130 | wfrom[1] = '?'; | |
131 | mklongpath (wto, to, tlen); | |
132 | wto[1] = '?'; | |
133 | ||
134 | HANDLE fh; | |
135 | NTSTATUS status; | |
136 | UNICODE_STRING uto; | |
137 | OBJECT_ATTRIBUTES attr; | |
138 | IO_STATUS_BLOCK io; | |
139 | ||
140 | /* Open the existing file. */ | |
141 | RtlInitUnicodeString (&uto, wto); | |
142 | InitializeObjectAttributes (&attr, &uto, OBJ_CASE_INSENSITIVE, NULL, NULL); | |
143 | status = NtOpenFile (&fh, READ_CONTROL, &attr, &io, FILE_SHARE_VALID_FLAGS, | |
144 | FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT); | |
145 | if (!NT_SUCCESS (status)) | |
146 | return 1; | |
147 | /* Create from as link to to. */ | |
148 | flen = wcslen (wfrom) * sizeof (WCHAR); | |
149 | ULONG size = sizeof (FILE_LINK_INFORMATION) + flen; | |
150 | sfli.fli.ReplaceIfExists = TRUE; | |
151 | sfli.fli.RootDirectory = NULL; | |
152 | sfli.fli.FileNameLength = flen; | |
153 | memcpy (sfli.fli.FileName, wfrom, flen); | |
154 | status = NtSetInformationFile (fh, &io, &sfli.fli, size, FileLinkInformation); | |
155 | NtClose (fh); | |
156 | return NT_SUCCESS (status) ? 0 : 1; | |
157 | } |