common/src/fixpath.c

changeset 494
e64f2cb57d05
child 564
befbad2e4d87
equal deleted inserted replaced
488:8a3fe0ae06a8 494:e64f2cb57d05
1 /*
2 * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 #include <Windows.h>
27 #include <io.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <malloc.h>
31
32 /*
33 * Test if pos points to /cygdrive/_/ where _ can
34 * be any character.
35 */
36 int is_cygdrive_here(int pos, char *in, int len)
37 {
38 // Length of /cygdrive/c/ is 12
39 if (pos+12 > len) return 0;
40 if (in[pos+11]=='/' &&
41 in[pos+9]=='/' &&
42 in[pos+8]=='e' &&
43 in[pos+7]=='v' &&
44 in[pos+6]=='i' &&
45 in[pos+5]=='r' &&
46 in[pos+4]=='d' &&
47 in[pos+3]=='g' &&
48 in[pos+2]=='y' &&
49 in[pos+1]=='c' &&
50 in[pos+0]=='/') {
51 return 1;
52 }
53 return 0;
54 }
55
56 /*
57 * Replace /cygdrive/_/ with _:/
58 * Works in place since drive letter is always
59 * shorter than /cygdrive/
60 */
61 char *replace_cygdrive_cygwin(char *in)
62 {
63 int len = strlen(in);
64 char *out = malloc(len+1);
65 int i,j;
66
67 if (len < 12) {
68 strcpy(out, in);
69 return out;
70 }
71 for (i = 0, j = 0; i<len;) {
72 if (is_cygdrive_here(i, in, len)) {
73 out[j++] = in[i+10];
74 out[j++] = ':';
75 i+=11;
76 } else {
77 out[j] = in[i];
78 i++;
79 j++;
80 }
81 }
82 out[j] = 0;
83 return out;
84 }
85
86 void append(char **b, size_t *bl, size_t *u, char *add, size_t addlen)
87 {
88 while ( (addlen+*u+1) > *bl) {
89 *bl *= 2;
90 *b = realloc(*b, *bl);
91 }
92 memcpy(*b+*u, add, addlen);
93 *u += addlen;
94 }
95
96 /*
97 * Creates a new string from in where the first occurance of sub is
98 * replaced by rep.
99 */
100 char *replace_substring(char *in, char *sub, char *rep)
101 {
102 int in_len = strlen(in);
103 int sub_len = strlen(sub);
104 int rep_len = strlen(rep);
105 char *out = malloc(in_len - sub_len + rep_len + 1);
106 char *p;
107
108 if (!(p = strstr(in, sub))) {
109 // If sub isn't a substring of in, just return in.
110 return in;
111 }
112
113 // Copy characters from beginning of in to start of sub.
114 strncpy(out, in, p - in);
115 out[p - in] = '\0';
116
117 sprintf(out + (p - in), "%s%s", rep, p + sub_len);
118
119 return out;
120 }
121
122 char* msys_path_list; // @-separated list of paths prefix to look for
123 char* msys_path_list_end; // Points to last \0 in msys_path_list.
124
125 void setup_msys_path_list(char* argument)
126 {
127 char* p;
128 char* drive_letter_pos;
129
130 msys_path_list = strdup(&argument[2]);
131 msys_path_list_end = &msys_path_list[strlen(msys_path_list)];
132
133 // Convert all at-sign (@) in path list to \0.
134 // @ was chosen as separator to minimize risk of other tools messing around with it
135 p = msys_path_list;
136 do {
137 if (p[1] == ':') {
138 // msys has mangled our path list, restore it from c:/... to /c/...
139 drive_letter_pos = p+1;
140 *drive_letter_pos = *p;
141 *p = '/';
142 }
143
144 // Look for an @ in the list
145 p = strchr(p, '@');
146 if (p != NULL) {
147 *p = '\0';
148 p++;
149 }
150 } while (p != NULL);
151 }
152
153 char *replace_cygdrive_msys(char *in)
154 {
155 char* str;
156 char* prefix;
157 char* p;
158
159 str = strdup(in);
160
161 // For each prefix in the path list, search for it and replace /c/... with c:/...
162 for (prefix = msys_path_list; prefix < msys_path_list_end && prefix != NULL; prefix += strlen(prefix)+1) {
163 p=str;
164 while ((p = strstr(p, prefix))) {
165 char* drive_letter = p+1;
166 *p = *drive_letter;
167 *drive_letter = ':';
168 p++;
169 }
170 }
171
172 return str;
173 }
174
175 char*(*replace_cygdrive)(char *in) = NULL;
176
177 char *files_to_delete[1024];
178 int num_files_to_delete = 0;
179
180 char *fix_at_file(char *in)
181 {
182 char *tmpdir;
183 char name[2048];
184 char *atname;
185 char *buffer;
186 size_t buflen=65536;
187 size_t used=0;
188 size_t len;
189 int rc;
190 FILE *atout;
191 FILE *atin;
192 char block[2048];
193 size_t blocklen;
194 char *fixed;
195
196 atin = fopen(in+1, "r");
197 if (atin == NULL) {
198 fprintf(stderr, "Could not read at file %s\n", in+1);
199 exit(-1);
200 }
201
202 tmpdir = getenv("TMP");
203 if (tmpdir == NULL) {
204 tmpdir = "c:/cygwin/tmp";
205 }
206 _snprintf(name, sizeof(name), "%s\\atfile_XXXXXX", tmpdir);
207
208 rc = _mktemp_s(name, strlen(name)+1);
209 if (rc) {
210 fprintf(stderr, "Could not create temporary file name for at file!\n");
211 exit(-1);
212 }
213
214 atout = fopen(name, "w");
215 if (atout == NULL) {
216 fprintf(stderr, "Could not open temporary file for writing! %s\n", name);
217 exit(-1);
218 }
219
220 buffer = malloc(buflen);
221 while((blocklen = fread(block,1,sizeof(block),atin)) > 0) {
222 append(&buffer, &buflen, &used, block, blocklen);
223 }
224 buffer[used] = 0;
225 if (getenv("DEBUG_FIXPATH") != NULL) {
226 fprintf(stderr, "fixpath input from @-file %s: %s\n", &in[1], buffer);
227 }
228 fixed = replace_cygdrive(buffer);
229 if (getenv("DEBUG_FIXPATH") != NULL) {
230 fprintf(stderr, "fixpath converted to @-file %s is: %s\n", name, fixed);
231 }
232 fwrite(fixed, strlen(fixed), 1, atout);
233 fclose(atin);
234 fclose(atout);
235 free(fixed);
236 free(buffer);
237 files_to_delete[num_files_to_delete] = malloc(strlen(name)+1);
238 strcpy(files_to_delete[num_files_to_delete], name);
239 num_files_to_delete++;
240 atname = malloc(strlen(name)+2);
241 atname[0] = '@';
242 strcpy(atname+1, name);
243 return atname;
244 }
245
246 int main(int argc, char **argv)
247 {
248 STARTUPINFO si;
249 PROCESS_INFORMATION pi;
250 unsigned short rc;
251
252 char *new_at_file;
253 char *old_at_file;
254 char *line;
255 int i;
256 DWORD exitCode;
257
258 if (argc<3 || argv[1][0] != '-' || (argv[1][1] != 'c' && argv[1][1] != 'm')) {
259 fprintf(stderr, "Usage: fixpath -c|m<path@path@...> /cygdrive/c/WINDOWS/notepad.exe /cygdrive/c/x/test.txt");
260 exit(0);
261 }
262
263 if (getenv("DEBUG_FIXPATH") != NULL) {
264 fprintf(stderr, "fixpath input line >%s<\n", strstr(GetCommandLine(), argv[1]));
265 }
266
267 if (argv[1][1] == 'c' && argv[1][2] == '\0') {
268 if (getenv("DEBUG_FIXPATH") != NULL) {
269 fprintf(stderr, "using cygwin mode\n");
270 }
271 replace_cygdrive = replace_cygdrive_cygwin;
272 } else if (argv[1][1] == 'm') {
273 if (getenv("DEBUG_FIXPATH") != NULL) {
274 fprintf(stderr, "using msys mode, with path list: %s\n", &argv[1][2]);
275 }
276 setup_msys_path_list(argv[1]);
277 replace_cygdrive = replace_cygdrive_msys;
278 } else {
279 fprintf(stderr, "Unknown mode: %s\n", argv[1]);
280 exit(-1);
281 }
282 line = replace_cygdrive(strstr(GetCommandLine(), argv[2]));
283
284 for (i=1; i<argc; ++i) {
285 if (argv[i][0] == '@') {
286 // Found at-file! Fix it!
287 old_at_file = replace_cygdrive(argv[i]);
288 new_at_file = fix_at_file(old_at_file);
289 line = replace_substring(line, old_at_file, new_at_file);
290 }
291 }
292
293 if (getenv("DEBUG_FIXPATH") != NULL) {
294 fprintf(stderr, "fixpath converted line >%s<\n", line);
295 }
296
297 ZeroMemory(&si,sizeof(si));
298 si.cb=sizeof(si);
299 ZeroMemory(&pi,sizeof(pi));
300
301 rc = CreateProcess(NULL,
302 line,
303 0,
304 0,
305 TRUE,
306 0,
307 0,
308 0,
309 &si,
310 &pi);
311 if(!rc)
312 {
313 //Could not start process;
314 fprintf(stderr, "Could not start process!\n");
315 exit(-1);
316 }
317
318 WaitForSingleObject(pi.hProcess,INFINITE);
319 GetExitCodeProcess(pi.hProcess,&exitCode);
320
321 if (getenv("DEBUG_FIXPATH") != NULL) {
322 for (i=0; i<num_files_to_delete; ++i) {
323 fprintf(stderr, "Not deleting temporary fixpath file %s\n",
324 files_to_delete[i]);
325 }
326 }
327 else {
328 for (i=0; i<num_files_to_delete; ++i) {
329 remove(files_to_delete[i]);
330 }
331 }
332
333 exit(exitCode);
334 }

mercurial