diff --git a/pkgs/racket-doc/scribblings/reference/filesystem.scrbl b/pkgs/racket-doc/scribblings/reference/filesystem.scrbl index 229d04a148..e9e5aaf123 100644 --- a/pkgs/racket-doc/scribblings/reference/filesystem.scrbl +++ b/pkgs/racket-doc/scribblings/reference/filesystem.scrbl @@ -472,10 +472,15 @@ successfully,the @exnraise[exn:fail:filesystem]. On Windows XP and earlier, the @exnraise[exn:fail:unsupported]. On later versions of Windows, the creation of links tends to be -disallowed by security policies. Furthermore, a relative-path link is -parsed specially; see @secref["windowspaths"] for more information. -When @racket[make-file-or-directory-link] succeeds, it creates a symbolic -link as opposed to a junction. +disallowed by security policies. Windows distinguishes between file +and directory links, and a directory link is created if @racket[to] +parses syntactically as a directory. Furthermore, a relative-path link +is parsed specially by the operating system; see +@secref["windowspaths"] for more information. When +@racket[make-file-or-directory-link] succeeds, it creates a symbolic +link as opposed to a junction or hard link. Beware that directory +links must be deleted using @racket[delete-directory] instead of +@racket[delete-file]. @history[#:changed "6.0.1.12" @elem{Added support for links on Windows.}]} diff --git a/racket/src/racket/src/file.c b/racket/src/racket/src/file.c index b277c27152..ae7493ba26 100644 --- a/racket/src/racket/src/file.c +++ b/racket/src/racket/src/file.c @@ -1919,12 +1919,11 @@ static int path_is_simple_dir_without_sep(Scheme_Object *path) static Scheme_Object *do_path_to_directory_path(char *s, intptr_t offset, intptr_t len, Scheme_Object *p, int just_check, int kind) /* Although this function accepts an offset, the Windows part assumes that - `offset' is always 0. */ + `offset' is always 0. If `just_check` is > 1, returns `p` for more + directory paths than just the ones that end in a separator. */ { char *s2; -#if DROP_REDUNDANT_SLASHES int not_a_sep = 0; -#endif if (kind == SCHEME_WINDOWS_PATH_KIND) { int slash_dir_sep = 1; @@ -1937,36 +1936,34 @@ static Scheme_Object *do_path_to_directory_path(char *s, intptr_t offset, intptr } if (check_dos_slashslash_qm(s, len, &drive_end, NULL, NULL)) { -#if DROP_REDUNDANT_SLASHES - if (drive_end < 0) { - /* It's a \\?\REL\ or \\?\RED\ path. */ - int litpos; - drive_end = get_slashslash_qm_dot_ups_end(s, len, &litpos); - /* If there's no path after the ..s, then nothing more is needed. */ - if (litpos >= len) - return p; - } else { - /* If s is just a drive, then nothing more is needed. */ - if (drive_end == len) - return p; + if (just_check > 1) { + if (drive_end < 0) { + /* It's a \\?\REL\ or \\?\RED\ path. */ + int litpos; + drive_end = get_slashslash_qm_dot_ups_end(s, len, &litpos); + /* If there's no path after the ..s, then nothing more is needed. */ + if (litpos >= len) + return p; + } else { + /* If s is just a drive, then nothing more is needed. */ + if (drive_end == len) + return p; + } } -#endif /* In \\?\, / can be part of a name, and it is never a separator. */ slash_dir_sep = 0; /* Any "." or ".." at the end is a literal path element, not an up- or same-directory indicator: */ -#if DROP_REDUNDANT_SLASHES not_a_sep = 1; -#endif } else { -#if DROP_REDUNDANT_SLASHES - /* A slash after C: is not strictly necessary: */ - if ((len == 2) - && is_drive_letter(s[offset]) - && (s[offset+1] == ':')) - return p; -#endif + if (just_check > 1) { + /* A slash after C: is not strictly necessary: */ + if ((len == 2) + && is_drive_letter(s[offset]) + && (s[offset+1] == ':')) + return p; + } } } { @@ -1979,33 +1976,33 @@ static Scheme_Object *do_path_to_directory_path(char *s, intptr_t offset, intptr return p; } -#if DROP_REDUNDANT_SLASHES - if (!not_a_sep - && (((len > 1) && (s[offset + len - 1] == '.') && IS_A_SEP(kind, s[offset + len - 2])) - || ((len == 1) && (s[offset] == '.')))) - return p; - if (!not_a_sep - && (((len > 2) - && (s[offset + len - 1] == '.') - && (s[offset + len - 2] == '.') - && IS_A_SEP(kind, s[offset + len - 3])) - || ((len == 2) && (s[offset] == '.') && (s[offset + 1] == '.')))) - return p; + if (just_check > 1) { + if (!not_a_sep + && (((len > 1) && (s[offset + len - 1] == '.') && IS_A_SEP(kind, s[offset + len - 2])) + || ((len == 1) && (s[offset] == '.')))) + return p; + if (!not_a_sep + && (((len > 2) + && (s[offset + len - 1] == '.') + && (s[offset + len - 2] == '.') + && IS_A_SEP(kind, s[offset + len - 3])) + || ((len == 2) && (s[offset] == '.') && (s[offset + 1] == '.')))) + return p; # ifdef TILDE_IS_ABSOLUTE - if (kind == SCHEME_UNIX_PATH_KIND) { - if (s[offset] == '~') { - intptr_t i; - for (i = 1; i < len; i++) { - if (IS_A_UNIX_SEP(s[offset + i])) - break; + if (kind == SCHEME_UNIX_PATH_KIND) { + if (s[offset] == '~') { + intptr_t i; + for (i = 1; i < len; i++) { + if (IS_A_UNIX_SEP(s[offset + i])) + break; + } + if (i >= len) + return p; } - if (i >= len) - return p; } - } # endif -#endif + } if (just_check) return NULL; @@ -4629,10 +4626,11 @@ static Scheme_Object *make_link(int argc, Scheme_Object *argv[]) #if defined(DOS_FILE_SYSTEM) - if (do_path_to_directory_path(src, 0, -1, argv[1], 1, SCHEME_WINDOWS_PATH_KIND)) - dest_is_dir = 1; + if (do_path_to_directory_path(SCHEME_PATH_VAL(dest), 0, SCHEME_PATH_LEN(dest), + argv[0], 2, SCHEME_WINDOWS_PATH_KIND)) + dest_is_dir = 1; else - dest_is_dir = 0; + dest_is_dir = 0; #else dest_is_dir = 0; #endif diff --git a/racket/src/rktio/rktio_fs.c b/racket/src/rktio/rktio_fs.c index 844b025988..a87995fac5 100644 --- a/racket/src/rktio/rktio_fs.c +++ b/racket/src/rktio/rktio_fs.c @@ -986,16 +986,21 @@ int rktio_make_link(rktio_t *rktio, const char *src, const char *dest, int dest_ { #if defined(RKTIO_SYSTEM_WINDOWS) init_procs(); - + +# ifndef SYMBOLIC_LINK_FLAG_DIRECTORY +# define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1 +# endif +# ifndef SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE +# define SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE 0x2 +# endif + if (CreateSymbolicLinkProc) { - int flags; + int flags = SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE; wchar_t *src_w; wchar_t *dest_w; if (dest_is_directory) - flags = 0x1; /* directory */ - else - flags = 0; /* file */ + flags |= SYMBOLIC_LINK_FLAG_DIRECTORY; /* directory */ src_w = WIDE_PATH_copy(src); if (!src_w) return 0;