From: marcus AT shannon DOT sysc DOT pdx DOT edu (Marcus G. Daniels) Subject: Re: ln and links 25 Jan 1997 18:47:00 -0800 Approved: cygnus DOT gnu-win32 AT cygnus DOT com Distribution: cygnus Message-ID: References: <01BC0B0E DOT 9ACE4BB0 AT sos> Original-To: Sergey Okhapkin Original-Cc: "'GNU-Win32'" , "'Ron Forrester'" In-Reply-To: Sergey Okhapkin's message of Sat, 25 Jan 1997 21:41:50 +0300 X-Mailer: Gnus v5.3/Emacs 19.34 Original-Sender: owner-gnu-win32 AT cygnus DOT com >>>>> "SO" == Sergey Okhapkin writes: RF> Using b17.1 on Windows NT 4.0 SP2, with a FAT drive, if I am in RF> /usr/rjf and there is a directory /pub, and I issue the command: RF> ln -s /pub SO> B17 does not support symlinks to directories. But you might find this patch useful... diff --ignore-all-space -c -r winsup/fhandler.cc /src/winsup/fhandler.cc *** winsup/fhandler.cc Tue Dec 10 14:18:50 1996 --- /src/winsup/fhandler.cc Thu Jan 9 06:27:19 1997 *************** *** 298,304 **** syml_p = 0; } ! path_conv win32_path (real_path); if (win32_path.error) { set_errno (win32_path.error); --- 298,304 ---- syml_p = 0; } ! path_conv win32_path (real_path, 0); if (win32_path.error) { set_errno (win32_path.error); diff --ignore-all-space -c -r winsup/path.cc /src/winsup/path.cc *** winsup/path.cc Tue Dec 3 19:23:01 1996 --- /src/winsup/path.cc Fri Jan 10 00:26:02 1997 *************** *** 136,141 **** --- 136,192 ---- return 0; } + + static const char * + skip_n_slashes (const char *path, int ind) + { + int i; + const char *ptr = path; + for (i = 0 ; i < ind && ptr != NULL; i++) + { + ptr = strchr (ptr+1, '/'); + if (ptr) + if (ptr[1] == '/') + ptr++; + } + return ptr; + } + + static int symlink_check_worker (const char *path, char *buf, int buflen, int *syml, int *exec, int follow_mode); + + static void + symlink_expand (const char *path, char *buf) + { + + char in[MAX_PATH]; + char tmp[MAX_PATH]; + char *next; + int si, tmplen; + int exec, syml; + + strcpy (in, path); + for (si=1; next = (char *)skip_n_slashes (in, si); si++) + { + *next = '\0'; + tmplen = symlink_check_worker (in, buf, MAX_PATH - 1, &syml, &exec, -1); + *next = '/'; + if (tmplen > 0) + { + strcpy (tmp, next); + buf[tmplen]='\0'; + if (buf[0] == '/' || si == 1) + strcpy (in, buf); + else + { + const char *prev = skip_n_slashes (in, si - 1); + strcpy ((char *)prev + 1, (const char *)buf); + } + strcat (in, tmp); + } + } + strcpy (buf, in); + } + /* Convert an arbitrary path SRC to a pure WIN32 path, suitable for passing to Win32 API routines. *************** *** 145,157 **** If an error occurs, `error' is set to the errno value. Otherwise it is set to 0. */ ! path_conv::path_conv (const char *src) { mixed_p = 0; silent_p = 0; binary_p = 0; error = 0; if (! s->mount.posix_path_p ()) { if (strlen (src) >= MAX_PATH) --- 196,226 ---- If an error occurs, `error' is set to the errno value. Otherwise it is set to 0. */ ! path_conv::path_conv (const char *in_src, int follow_mode) { + const char *src; + char src_[MAX_PATH]; + mixed_p = 0; silent_p = 0; binary_p = 0; error = 0; + if (follow_mode > 0) + { + int exec; + symlink_follow (in_src, src_, &exec); + src = src_; + } + else if (follow_mode == 0) + { + symlink_expand (in_src, src_); + src = src_; + } + else + src = in_src; + + if (! s->mount.posix_path_p ()) { if (strlen (src) >= MAX_PATH) *************** *** 1021,1032 **** If an error occurs -1 is returned and errno is set. */ ! int ! symlink_check (const char *path, char *buf, int buflen, int *syml, int *exec) { int res = -1; ! path_conv pathbuf (path); if (pathbuf.error) { set_errno (pathbuf.error); --- 1090,1101 ---- If an error occurs -1 is returned and errno is set. */ ! static int ! symlink_check_worker (const char *path, char *buf, int buflen, int *syml, int *exec, int follow_mode) { int res = -1; ! path_conv pathbuf (path, follow_mode); if (pathbuf.error) { set_errno (pathbuf.error); *************** *** 1110,1115 **** --- 1179,1191 ---- return res; } + int + symlink_check (const char *path, char *buf, int buflen, int *syml, int *exec) + { + return symlink_check_worker (path, buf, buflen, syml, exec, 0); + } + + /* Traverse PATH to its ultimate destination and store that in REALPATH. PATH needn't be a symlink (in which case it is copied to REALPATH). REALPATH is assumed to be large enough (i.e. MAX_PATH bytes). *************** *** 1125,1135 **** up later but the priority now is on simplicity and correctness. */ int ! symlink_follow (const char *path, char *realpath, int *exec) { char buf[MAX_PATH]; int len; if (strlen (path) >= MAX_PATH) { set_errno (ENAMETOOLONG); --- 1201,1213 ---- up later but the priority now is on simplicity and correctness. */ int ! symlink_follow (const char *in_path, char *realpath, int *exec) { char buf[MAX_PATH]; + char path[MAX_PATH]; int len; + symlink_expand (in_path, path); if (strlen (path) >= MAX_PATH) { set_errno (ENAMETOOLONG); *************** *** 1147,1152 **** --- 1225,1232 ---- /* If that wasn't a symlink, we're done. */ if (len == -1 || ! syml_p) { + symlink_expand (realpath, buf); + strcpy (realpath, buf); /* We really don't care if an error occurs here. We just assume PATH isn't a symlink and let the caller deal with it. */ if (exec) diff --ignore-all-space -c -r winsup/path.h /src/winsup/path.h *** winsup/path.h Tue Dec 3 19:23:01 1996 --- /src/winsup/path.h Thu Jan 9 00:58:41 1997 *************** *** 27,33 **** int error; ! path_conv (const char * const); inline char *get_win32 () { return path; } }; --- 27,33 ---- int error; ! path_conv (const char * const, int follow_mode = 1); inline char *get_win32 () { return path; } }; diff --ignore-all-space -c -r winsup/syscalls.cc /src/winsup/syscalls.cc *** winsup/syscalls.cc Tue Dec 3 19:23:03 1996 --- /src/winsup/syscalls.cc Thu Jan 9 06:15:39 1997 *************** *** 168,174 **** { int res; ! path_conv win32_name (ourname); syscall_printf ("_unlink (%s)\n", win32_name.get_win32 ()); --- 168,174 ---- { int res; ! path_conv win32_name (ourname, 0); syscall_printf ("_unlink (%s)\n", win32_name.get_win32 ()); *************** *** 477,484 **** _link (const char *a, const char *b) { int res = -1; ! path_conv real_a (a); ! path_conv real_b (b); /* do this with a copy */ if (CopyFileA (real_a.get_win32 (), real_b.get_win32 (), 1)) --- 477,484 ---- _link (const char *a, const char *b) { int res = -1; ! path_conv real_a (a, 0); ! path_conv real_b (b, 0); /* do this with a copy */ if (CopyFileA (real_a.get_win32 (), real_b.get_win32 (), 1)) *************** *** 496,502 **** { int res = -1; ! path_conv real_dir (dir); if (CreateDirectoryA (real_dir.get_win32 (), 0)) res = 0; --- 496,502 ---- { int res = -1; ! path_conv real_dir (dir, 0); if (CreateDirectoryA (real_dir.get_win32 (), 0)) res = 0; *************** *** 513,519 **** { int res = -1; ! path_conv real_dir (dir); if (RemoveDirectoryA (real_dir.get_win32 ())) res = 0; --- 513,519 ---- { int res = -1; ! path_conv real_dir (dir, 0); if (RemoveDirectoryA (real_dir.get_win32 ())) res = 0; *************** *** 708,714 **** debug_printf ("%s (%s, %p)\n", caller, name, buf); ! path_conv real_path (name); if (real_path.error) { set_errno (real_path.error); --- 708,714 ---- debug_printf ("%s (%s, %p)\n", caller, name, buf); ! path_conv real_path (name, !nofollow); if (real_path.error) { set_errno (real_path.error); *************** *** 814,821 **** int _rename (const char *oldpath, const char *newpath) { ! path_conv real_old (oldpath); ! path_conv real_new (newpath); int res; int oldatts = GetFileAttributesA (real_old.get_win32 ()); int newatts = GetFileAttributesA (real_new.get_win32 ()); --- 814,821 ---- int _rename (const char *oldpath, const char *newpath) { ! path_conv real_old (oldpath, 0); ! path_conv real_new (newpath, 0); int res; int oldatts = GetFileAttributesA (real_old.get_win32 ()); int newatts = GetFileAttributesA (real_new.get_win32 ()); - For help on using this list, send a message to "gnu-win32-request AT cygnus DOT com" with one line of text: "help".