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