fixpath.c revision 492:e64f2cb57d05
155714Skris/* 255714Skris * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. 355714Skris * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 455714Skris * 555714Skris * This code is free software; you can redistribute it and/or modify it 655714Skris * under the terms of the GNU General Public License version 2 only, as 755714Skris * published by the Free Software Foundation. Oracle designates this 8296341Sdelphij * particular file as subject to the "Classpath" exception as provided 955714Skris * by Oracle in the LICENSE file that accompanied this code. 1055714Skris * 1155714Skris * This code is distributed in the hope that it will be useful, but WITHOUT 1255714Skris * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1355714Skris * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1455714Skris * version 2 for more details (a copy is included in the LICENSE file that 15296341Sdelphij * accompanied this code). 1655714Skris * 1755714Skris * You should have received a copy of the GNU General Public License version 1855714Skris * 2 along with this work; if not, write to the Free Software Foundation, 1955714Skris * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 2055714Skris * 2155714Skris * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22296341Sdelphij * or visit www.oracle.com if you need additional information or have any 2355714Skris * questions. 2455714Skris */ 2555714Skris 2655714Skris#include <Windows.h> 2755714Skris#include <io.h> 2855714Skris#include <stdio.h> 2955714Skris#include <string.h> 3055714Skris#include <malloc.h> 3155714Skris 3255714Skris/* 3355714Skris * Test if pos points to /cygdrive/_/ where _ can 3455714Skris * be any character. 3555714Skris */ 3655714Skrisint is_cygdrive_here(int pos, char *in, int len) 37296341Sdelphij{ 3855714Skris // Length of /cygdrive/c/ is 12 3955714Skris if (pos+12 > len) return 0; 40296341Sdelphij if (in[pos+11]=='/' && 4155714Skris in[pos+9]=='/' && 4255714Skris in[pos+8]=='e' && 4355714Skris in[pos+7]=='v' && 4455714Skris in[pos+6]=='i' && 4555714Skris in[pos+5]=='r' && 4655714Skris in[pos+4]=='d' && 4755714Skris in[pos+3]=='g' && 4855714Skris in[pos+2]=='y' && 4955714Skris in[pos+1]=='c' && 5055714Skris in[pos+0]=='/') { 5155714Skris return 1; 52296341Sdelphij } 5355714Skris return 0; 5455714Skris} 5555714Skris 5655714Skris/* 5755714Skris * Replace /cygdrive/_/ with _:/ 5855714Skris * Works in place since drive letter is always 5955714Skris * shorter than /cygdrive/ 6055714Skris */ 6155714Skrischar *replace_cygdrive_cygwin(char *in) 6255714Skris{ 6355714Skris int len = strlen(in); 6455714Skris char *out = malloc(len+1); 65109998Smarkm int i,j; 66296341Sdelphij 67296341Sdelphij if (len < 12) { 6855714Skris strcpy(out, in); 69296341Sdelphij return out; 70296341Sdelphij } 71238405Sjkim for (i = 0, j = 0; i<len;) { 72296341Sdelphij if (is_cygdrive_here(i, in, len)) { 73194206Ssimon out[j++] = in[i+10]; 74296341Sdelphij out[j++] = ':'; 75296341Sdelphij i+=11; 76296341Sdelphij } else { 77296341Sdelphij out[j] = in[i]; 78296341Sdelphij i++; 79296341Sdelphij j++; 80296341Sdelphij } 81296341Sdelphij } 82296341Sdelphij out[j] = 0; 8355714Skris return out; 84109998Smarkm} 85296341Sdelphij 86296341Sdelphijvoid append(char **b, size_t *bl, size_t *u, char *add, size_t addlen) 87296341Sdelphij{ 88296341Sdelphij while ( (addlen+*u+1) > *bl) { 8955714Skris *bl *= 2; 90296341Sdelphij *b = realloc(*b, *bl); 91296341Sdelphij } 92296341Sdelphij memcpy(*b+*u, add, addlen); 93296341Sdelphij *u += addlen; 94296341Sdelphij} 95296341Sdelphij 96296341Sdelphij/* 97296341Sdelphij * Creates a new string from in where the first occurance of sub is 98296341Sdelphij * replaced by rep. 9955714Skris */ 100296341Sdelphijchar *replace_substring(char *in, char *sub, char *rep) 101296341Sdelphij{ 102296341Sdelphij int in_len = strlen(in); 103296341Sdelphij int sub_len = strlen(sub); 104296341Sdelphij int rep_len = strlen(rep); 105296341Sdelphij char *out = malloc(in_len - sub_len + rep_len + 1); 106296341Sdelphij char *p; 107296341Sdelphij 108296341Sdelphij if (!(p = strstr(in, sub))) { 109296341Sdelphij // If sub isn't a substring of in, just return in. 110296341Sdelphij return in; 11155714Skris } 11255714Skris 113296341Sdelphij // Copy characters from beginning of in to start of sub. 114296341Sdelphij strncpy(out, in, p - in); 11555714Skris out[p - in] = '\0'; 116296341Sdelphij 117296341Sdelphij sprintf(out + (p - in), "%s%s", rep, p + sub_len); 118296341Sdelphij 11955714Skris return out; 12055714Skris} 121296341Sdelphij 122296341Sdelphijchar* msys_path_list; // @-separated list of paths prefix to look for 12355714Skrischar* msys_path_list_end; // Points to last \0 in msys_path_list. 124296341Sdelphij 125296341Sdelphijvoid setup_msys_path_list(char* argument) 126296341Sdelphij{ 12755714Skris char* p; 12855714Skris char* drive_letter_pos; 129296341Sdelphij 130296341Sdelphij msys_path_list = strdup(&argument[2]); 131296341Sdelphij msys_path_list_end = &msys_path_list[strlen(msys_path_list)]; 132296341Sdelphij 133296341Sdelphij // Convert all at-sign (@) in path list to \0. 134296341Sdelphij // @ was chosen as separator to minimize risk of other tools messing around with it 135296341Sdelphij p = msys_path_list; 136296341Sdelphij do { 137296341Sdelphij if (p[1] == ':') { 13859191Skris // msys has mangled our path list, restore it from c:/... to /c/... 139296341Sdelphij drive_letter_pos = p+1; 140296341Sdelphij *drive_letter_pos = *p; 141296341Sdelphij *p = '/'; 142296341Sdelphij } 143296341Sdelphij 144296341Sdelphij // Look for an @ in the list 145296341Sdelphij p = strchr(p, '@'); 146238405Sjkim if (p != NULL) { 147296341Sdelphij *p = '\0'; 148296341Sdelphij p++; 149296341Sdelphij } 150296341Sdelphij } while (p != NULL); 151296341Sdelphij} 152238405Sjkim 153238405Sjkimchar *replace_cygdrive_msys(char *in) 154296341Sdelphij{ 155296341Sdelphij char* str; 156296341Sdelphij char* prefix; 157296341Sdelphij char* p; 158296341Sdelphij 159296341Sdelphij str = strdup(in); 160296341Sdelphij 161238405Sjkim // For each prefix in the path list, search for it and replace /c/... with c:/... 162296341Sdelphij for (prefix = msys_path_list; prefix < msys_path_list_end && prefix != NULL; prefix += strlen(prefix)+1) { 163296341Sdelphij p=str; 164296341Sdelphij while ((p = strstr(p, prefix))) { 165296341Sdelphij char* drive_letter = p+1; 166296341Sdelphij *p = *drive_letter; 167296341Sdelphij *drive_letter = ':'; 168296341Sdelphij p++; 169296341Sdelphij } 170296341Sdelphij } 171238405Sjkim 172296341Sdelphij return str; 173296341Sdelphij} 174296341Sdelphij 175296341Sdelphijchar*(*replace_cygdrive)(char *in) = NULL; 176296341Sdelphij 177296341Sdelphijchar *files_to_delete[1024]; 178296341Sdelphijint num_files_to_delete = 0; 179296341Sdelphij 180296341Sdelphijchar *fix_at_file(char *in) 181238405Sjkim{ 182296341Sdelphij char *tmpdir; 183296341Sdelphij char name[2048]; 184296341Sdelphij char *atname; 185296341Sdelphij char *buffer; 186296341Sdelphij size_t buflen=65536; 187238405Sjkim size_t used=0; 188238405Sjkim size_t len; 189296341Sdelphij int rc; 190296341Sdelphij FILE *atout; 191296341Sdelphij FILE *atin; 192296341Sdelphij char block[2048]; 193296341Sdelphij size_t blocklen; 194296341Sdelphij char *fixed; 195296341Sdelphij 196238405Sjkim atin = fopen(in+1, "r"); 197296341Sdelphij if (atin == NULL) { 198296341Sdelphij fprintf(stderr, "Could not read at file %s\n", in+1); 199296341Sdelphij exit(-1); 200296341Sdelphij } 201296341Sdelphij 202296341Sdelphij tmpdir = getenv("TMP"); 203296341Sdelphij if (tmpdir == NULL) { 204296341Sdelphij tmpdir = "c:/cygwin/tmp"; 205296341Sdelphij } 206238405Sjkim _snprintf(name, sizeof(name), "%s\\atfile_XXXXXX", tmpdir); 207296341Sdelphij 208296341Sdelphij rc = _mktemp_s(name, strlen(name)+1); 209296341Sdelphij if (rc) { 210296341Sdelphij fprintf(stderr, "Could not create temporary file name for at file!\n"); 211296341Sdelphij exit(-1); 212296341Sdelphij } 213296341Sdelphij 214296341Sdelphij atout = fopen(name, "w"); 215296341Sdelphij 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 246int 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} 335