The R Project SVN R

Rev

Rev 76170 | Rev 77458 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 76170 Rev 77324
Line 29... Line 29...
29
 
29
 
30
#include "win-nls.h"
30
#include "win-nls.h"
31
 
31
 
32
 
32
 
33
#include <stdio.h>
33
#include <stdio.h>
-
 
34
#include <string.h>
34
#include <time.h>
35
#include <time.h>
35
#include "Defn.h"
36
#include "Defn.h"
36
#include <Internal.h>
37
#include <Internal.h>
37
#include "Fileio.h"
38
#include "Fileio.h"
38
#include <direct.h>
39
#include <direct.h>
39
#include "graphapp/ga.h"
40
#include "graphapp/ga.h"
-
 
41
#include "rlocale.h"
40
/* Mingw-w64 defines this to be 0x0502 */
42
/* Mingw-w64 defines this to be 0x0502 */
41
#ifndef _WIN32_WINNT
43
#ifndef _WIN32_WINNT
42
# define _WIN32_WINNT 0x0502 /* for GetLongPathName, KEY_WOW64_64KEY */
44
# define _WIN32_WINNT 0x0502 /* for GetLongPathName, KEY_WOW64_64KEY */
43
#endif
45
#endif
44
#include <windows.h>
46
#include <windows.h>
Line 432... Line 434...
432
    p = buf+strlen(buf) -1;
434
    p = buf+strlen(buf) -1;
433
    if(*p == '.') *p = '\0';
435
    if(*p == '.') *p = '\0';
434
    return buf;
436
    return buf;
435
}
437
}
436
 
438
 
-
 
439
#if _WIN32_WINNT < 0x0600
-
 
440
/* available from Windows Vista */
-
 
441
typedef DWORD (WINAPI *LPFN_GFPNBH) (HANDLE, LPSTR, DWORD, DWORD);
-
 
442
typedef DWORD (WINAPI *LPFN_GFPNBHW) (HANDLE, LPWSTR, DWORD, DWORD);
-
 
443
/*
-
 
444
DWORD GetFinalPathNameByHandle(
-
 
445
    HANDLE hFile,
-
 
446
    LPSTR lpszFilePath,
-
 
447
    DWORD cchFilePath,
-
 
448
    DWORD dwFlags);
-
 
449
 
-
 
450
DWORD GetFinalPathNameByHandleW(
-
 
451
    HANDLE hFile,
-
 
452
    LPWSTR lpszFilePath,
-
 
453
    DWORD  cchFilePath,
-
 
454
    DWORD  dwFlags
-
 
455
);
-
 
456
*/
-
 
457
#endif
-
 
458
 
-
 
459
/*
-
 
460
   Returns TRUE on success. On failure, "res" may be modified but not useful.
-
 
461
*/
-
 
462
static Rboolean getFinalPathName(const char *orig, char *res)
-
 
463
{
-
 
464
    HANDLE h;
-
 
465
    int ret;
-
 
466
    static LPFN_GFPNBH gfpnbh = NULL;
-
 
467
    static Rboolean initialized = FALSE;
-
 
468
 
-
 
469
    if (!initialized) {
-
 
470
	initialized = TRUE;
-
 
471
	gfpnbh = (LPFN_GFPNBH) GetProcAddress(
-
 
472
	    GetModuleHandle(TEXT("kernel32")),
-
 
473
	    "GetFinalPathNameByHandleA");
-
 
474
    }
-
 
475
    if (gfpnbh == NULL)
-
 
476
	return FALSE;
-
 
477
 
-
 
478
    h = CreateFile(orig, 0,
-
 
479
                   FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
-
 
480
		   NULL, OPEN_EXISTING,
-
 
481
                   /* FILE_FLAG_BACKUP_SEMANTICS needed to open a directory */
-
 
482
		   FILE_ATTRIBUTE_HIDDEN | FILE_FLAG_BACKUP_SEMANTICS, NULL);
-
 
483
    if (h == INVALID_HANDLE_VALUE) 
-
 
484
	return FALSE;
-
 
485
 
-
 
486
    ret = gfpnbh(h, res, MAX_PATH, VOLUME_NAME_DOS);
-
 
487
    CloseHandle(h);
-
 
488
 
-
 
489
    if (!ret || ret > MAX_PATH)
-
 
490
	return FALSE;
-
 
491
    
-
 
492
    /* get rid of the \\?\ prefix */
-
 
493
    int len = strlen(res);
-
 
494
    int strip = 0;
-
 
495
    if (len < 4 || strncmp("\\\\?\\", res, 4))
-
 
496
	/* res should start with \\?\ */
-
 
497
	return FALSE;
-
 
498
    
-
 
499
    if (len > 8 && !strncmp("UNC\\", res+4, 4))
-
 
500
	/* UNC path \\?\UNC */
-
 
501
	strip = 7;	
-
 
502
    else if (len >= 6 && isalpha(res[4]) && res[5] == ':' && res[6] == '\\')
-
 
503
	/* \\?\D: */
-
 
504
	strip = 4;
-
 
505
    else
-
 
506
	return FALSE;
-
 
507
    memmove(res, res+strip, len-strip+1);
-
 
508
 
-
 
509
    /* sanity check if the file exists using the normalized path, a normalized
-
 
510
       path to an existing file should still be working */
-
 
511
    h = CreateFile(orig, 0,
-
 
512
                   FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
-
 
513
		   NULL, OPEN_EXISTING,
-
 
514
                   /* FILE_FLAG_BACKUP_SEMANTICS needed to open a directory */
-
 
515
		   FILE_ATTRIBUTE_HIDDEN | FILE_FLAG_BACKUP_SEMANTICS, NULL);
-
 
516
    if (h == INVALID_HANDLE_VALUE)
-
 
517
	return FALSE;
-
 
518
    CloseHandle(h);
-
 
519
 
-
 
520
    return TRUE;	
-
 
521
}
-
 
522
 
-
 
523
/*
-
 
524
   Returns TRUE on success. On failure, "res" may be modified but not useful.
-
 
525
*/
-
 
526
static Rboolean getFinalPathNameW(const wchar_t *orig, wchar_t *res)
-
 
527
{
-
 
528
    HANDLE h;
-
 
529
    int ret;
-
 
530
    static LPFN_GFPNBHW gfpnbhw = NULL;
-
 
531
    static Rboolean initialized = FALSE;
-
 
532
 
-
 
533
    if (!initialized) {
-
 
534
	initialized = TRUE;
-
 
535
	gfpnbhw = (LPFN_GFPNBHW) GetProcAddress(
-
 
536
	    GetModuleHandle(TEXT("kernel32")),
-
 
537
	    "GetFinalPathNameByHandleW");
-
 
538
    }
-
 
539
    if (gfpnbhw == NULL)
-
 
540
	return FALSE;
-
 
541
 
-
 
542
    h = CreateFileW(orig, 0,
-
 
543
                   FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
-
 
544
		   NULL, OPEN_EXISTING,
-
 
545
                   /* FILE_FLAG_BACKUP_SEMANTICS needed to open a directory */
-
 
546
		   FILE_ATTRIBUTE_HIDDEN | FILE_FLAG_BACKUP_SEMANTICS, NULL);
-
 
547
    if (h == INVALID_HANDLE_VALUE) 
-
 
548
	return FALSE;
-
 
549
 
-
 
550
    ret = gfpnbhw(h, res, 32767, VOLUME_NAME_DOS);
-
 
551
    CloseHandle(h);
-
 
552
 
-
 
553
    if (!ret || ret > 32768)
-
 
554
	return FALSE;
-
 
555
    
-
 
556
    /* get rid of the \\?\ prefix */
-
 
557
    size_t len = wcslen(res);
-
 
558
    int strip = 0;
-
 
559
    if (len < 4 || wcsncmp(L"\\\\?\\", res, 4))
-
 
560
	/* res should start with \\?\ */
-
 
561
	return FALSE;
-
 
562
    
-
 
563
    if (len > 8 && !wcsncmp(L"UNC\\", res+4, 4))
-
 
564
	/* UNC path \\?\UNC */
-
 
565
	strip = 7;	
-
 
566
    else if (len >= 6 && Ri18n_iswctype(res[4], Ri18n_wctype("alpha"))
-
 
567
	     && res[5] == L':' && res[6] == L'\\')
-
 
568
	/* \\?\D: */
-
 
569
	strip = 4;
-
 
570
    else
-
 
571
	return FALSE;
-
 
572
    wmemmove(res, res+strip, len-strip+1);
-
 
573
 
-
 
574
    /* sanity check if the file exists using the normalized path, a normalized
-
 
575
       path to an existing file should still be working */
-
 
576
    h = CreateFileW(orig, 0,
-
 
577
                   FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
-
 
578
		   NULL, OPEN_EXISTING,
-
 
579
                   /* FILE_FLAG_BACKUP_SEMANTICS needed to open a directory */
-
 
580
		   FILE_ATTRIBUTE_HIDDEN | FILE_FLAG_BACKUP_SEMANTICS, NULL);
-
 
581
    if (h == INVALID_HANDLE_VALUE)
-
 
582
	return FALSE;
-
 
583
    CloseHandle(h);
-
 
584
 
-
 
585
    return TRUE;	
-
 
586
}
-
 
587
 
-
 
588
 
437
 
589
 
438
void R_UTF8fixslash(char *s); /* from main/util.c */
590
void R_UTF8fixslash(char *s); /* from main/util.c */
439
SEXP do_normalizepath(SEXP call, SEXP op, SEXP args, SEXP rho)
591
SEXP do_normalizepath(SEXP call, SEXP op, SEXP args, SEXP rho)
440
{
592
{
441
    SEXP ans, paths = CAR(args), el, slash;
593
    SEXP ans, paths = CAR(args), el, slash;
Line 458... Line 610...
458
    
610
    
459
    mustWork = asLogical(CADDR(args));
611
    mustWork = asLogical(CADDR(args));
460
 
612
 
461
    PROTECT(ans = allocVector(STRSXP, n));
613
    PROTECT(ans = allocVector(STRSXP, n));
462
    for (i = 0; i < n; i++) {
614
    for (i = 0; i < n; i++) {
463
    	int warn = 0;
-
 
464
    	SEXP result;
615
    	SEXP result;
-
 
616
	Rboolean ok = FALSE;
465
	el = STRING_ELT(paths, i);
617
	el = STRING_ELT(paths, i);
466
	result = el;
618
	result = el;
467
	if (el == NA_STRING) {
619
	if (el == NA_STRING) {
468
	    result = NA_STRING;
620
	    result = NA_STRING;
469
	    if(mustWork == 1)
621
	    if(mustWork == 1)
470
		errorcall(call, "path[%d]=NA", i+1);
622
		errorcall(call, "path[%d]=NA", i+1);
471
	    else if(mustWork == NA_LOGICAL)
623
	    else if(mustWork == NA_LOGICAL)
472
		warningcall(call, "path[%d]=NA", i+1);
624
		warningcall(call, "path[%d]=NA", i+1);
473
	} else if(getCharCE(el) == CE_UTF8) {
625
	} else if(getCharCE(el) == CE_UTF8) {
474
	    if ((res = GetFullPathNameW(filenameToWchar(el, FALSE), 32768, 
-
 
475
					wtmp, &wtmp2)) && res <= 32768) {
-
 
476
		if ((res = GetLongPathNameW(wtmp, wlongpath, 32768))
-
 
477
		    && res <= 32768) {
626
	    wchar_t *norm = NULL;
478
	    	    wcstoutf8(longpath, wlongpath, sizeof(longpath));
-
 
479
		    if(fslash) R_UTF8fixslash(longpath);
-
 
480
	    	    result = mkCharCE(longpath, CE_UTF8);
627
	    const wchar_t* wel = filenameToWchar(el, FALSE);
481
		} else if(mustWork == 1) {
-
 
482
		    errorcall(call, "path[%d]=\"%s\": %s", i+1, 
-
 
483
			      translateChar(el), 
-
 
484
			      formatError(GetLastError()));	
-
 
485
	    	} else {
628
 
486
	    	    wcstoutf8(tmp, wtmp, sizeof(tmp));
-
 
487
		    if(fslash) R_UTF8fixslash(tmp);
629
	    if (getFinalPathNameW(wel, wtmp)) {
488
	    	    result = mkCharCE(tmp, CE_UTF8);
-
 
489
	    	    warn = 1;
630
		norm = wtmp;
490
	    	}
631
		ok = TRUE;
491
	    } else if(mustWork == 1) {
-
 
492
		errorcall(call, "path[%d]=\"%s\": %s", i+1, 
-
 
493
			  translateChar(el), 
-
 
494
			  formatError(GetLastError()));	
-
 
495
	    } else {
632
	    } else {
-
 
633
		/* silently fall back to GetFullPathNameW/GetLongPathNameW */
-
 
634
		res = GetFullPathNameW(wel, 32768, wtmp, &wtmp2);
496
		if (fslash) {
635
		if (res && res <= 32768) {
-
 
636
		    norm = wtmp;
497
		    strcpy(tmp, translateCharUTF8(el));
637
		    res = GetLongPathNameW(wtmp, wlongpath, 32768);
498
		    R_UTF8fixslash(tmp);
638
		    if (res && res <= 32768) {
-
 
639
			norm = wlongpath;
-
 
640
			ok = TRUE;
-
 
641
		    }
-
 
642
		}
-
 
643
	    }
-
 
644
	    if (!ok) {
-
 
645
		if (mustWork == 1) {
-
 
646
		    errorcall(call, "path[%d]=\"%ls\": %s", i+1, 
499
	    	    result = mkCharCE(tmp, CE_UTF8);
647
			      wel, formatError(GetLastError()));
-
 
648
		} else if (mustWork == NA_LOGICAL) {
-
 
649
		    warningcall(call, "path[%d]=\"%ls\": %s", i+1, 
-
 
650
				wel, formatError(GetLastError()));
500
		}
651
		}
501
	    	warn = 1;
-
 
502
	    }
652
	    }
-
 
653
 
503
	    if (warn && (mustWork == NA_LOGICAL))
654
	    char *normutf8 = tmp;
-
 
655
	    if (norm)
-
 
656
		wcstoutf8(tmp, norm, sizeof(tmp));
-
 
657
	    else if (fslash)
-
 
658
		strcpy(tmp, translateCharUTF8(el));
-
 
659
	    else
504
	    	warningcall(call, "path[%d]=\"%ls\": %s", i+1, 
660
		normutf8 = (char *)translateCharUTF8(el);
-
 
661
 
505
			    filenameToWchar(el,FALSE), 
662
	    if (fslash) R_UTF8fixslash(normutf8);
506
			    formatError(GetLastError()));
663
	    result = mkCharCE(normutf8, CE_UTF8);
507
	} else {
664
	} else {
508
	    if ((res = GetFullPathName(translateChar(el), MAX_PATH, tmp, &tmp2)) 
-
 
509
		&& res <= MAX_PATH) {
-
 
510
	    	if ((res = GetLongPathName(tmp, longpath, MAX_PATH))
-
 
511
		    && res <= MAX_PATH) {
665
	    char *norm = NULL;
512
		    if(fslash) R_fixslash(longpath);
-
 
513
	    	    result = mkChar(longpath);
-
 
514
		} else if(mustWork == 1) {
-
 
515
		    errorcall(call, "path[%d]=\"%s\": %s", i+1, 
-
 
516
			      translateChar(el), 
666
	    const char *tel = translateChar(el);
517
			      formatError(GetLastError()));	
-
 
518
	    	} else {
-
 
519
		    if(fslash) R_fixslash(tmp);
-
 
520
	    	    result = mkChar(tmp);
667
	    if (getFinalPathName(tel, tmp)) {
521
	    	    warn = 1;
668
		norm = tmp;
522
	    	}
669
		ok = TRUE;
523
	    } else if(mustWork == 1) {
-
 
524
		errorcall(call, "path[%d]=\"%s\": %s", i+1, 
-
 
525
			  translateChar(el), 
-
 
526
			  formatError(GetLastError()));	
-
 
527
	    } else {
670
	    } else {
-
 
671
		/* silently fall back to GetFullPathName/GetLongPathName */
-
 
672
		res = GetFullPathName(tel, MAX_PATH, tmp, &tmp2);
-
 
673
		if (res && res <= MAX_PATH) {
-
 
674
		    norm = tmp;
-
 
675
		    res = GetLongPathName(tmp, longpath, MAX_PATH);
-
 
676
		    if (res && res <= MAX_PATH) {
-
 
677
			norm = longpath;
-
 
678
			ok = TRUE;
-
 
679
		    }
-
 
680
		}
-
 
681
	    }
-
 
682
	    if (!ok) {
-
 
683
		if (mustWork == 1) {
-
 
684
		    errorcall(call, "path[%d]=\"%s\": %s", i+1, 
-
 
685
			      tel, formatError(GetLastError()));
-
 
686
		} else if (mustWork == NA_LOGICAL) {
-
 
687
		    warningcall(call, "path[%d]=\"%s\": %s", i+1, 
-
 
688
				tel, formatError(GetLastError()));
-
 
689
		}
-
 
690
		if (!norm) {
528
		if (fslash) {
691
		    if (fslash) {
529
		    strcpy(tmp, translateChar(el));
692
			strcpy(tmp, tel);
-
 
693
			norm = tmp;
530
		    R_fixslash(tmp);
694
		    } else
531
		    result = mkChar(tmp);
695
			norm = (char *)tel;
532
		}
696
		}
533
	    	warn = 1;
-
 
534
	    }
697
	    }
535
	    if (warn && (mustWork == NA_LOGICAL))
698
	    if (fslash) R_fixslash(norm);
536
		warningcall(call, "path[%d]=\"%s\": %s", i+1, 
-
 
537
			    translateChar(el), 
699
	    result = mkChar(norm);
538
			    formatError(GetLastError()));	
-
 
539
	}
700
	}
540
	SET_STRING_ELT(ans, i, result);
701
	SET_STRING_ELT(ans, i, result);
541
    }
702
    }
542
    UNPROTECT(1);
703
    UNPROTECT(1);
543
    return ans;
704
    return ans;