From 762520f3bc4d160d2af658f5dd59dfd09d76bc7f Mon Sep 17 00:00:00 2001
From: Christopher Faylor <me@cgf.cx>
Date: Sat, 8 Mar 2003 03:36:39 +0000
Subject: [PATCH] * path.h (PATH_LNK): New enum val.
 (path_conv::is_lnk_symlink): New function.  True if path represents .lnk
 style symlink. * path.cc (check_shortcut): Set PATH_LNK in pflags when
 appropriate. (symlink_info::check): Ditto.  Remove PATH_LNK from pflags
 initially. * syscalls.cc (unlink): Always remove readonly attribute from a
 symlink regardless of type. (link): (from Corinna Vinschen) Allow links to
 symlinks.  Reset attributes on a symlink after successful link creation.
 (chmod): Use is_lnk_symlink where appropriate. (rename): Ditto. * tty.cc
 (create_tty_master): Call GetComputerName instead of cygwin_gethostname.  Set
 ut_id. * syscalls.cc (login): Call endutent. (setutent): Do not seek after a
 fresh open.

---
 winsup/cygwin/ChangeLog   | 23 ++++++++++++-
 winsup/cygwin/path.cc     |  8 +++--
 winsup/cygwin/path.h      |  2 ++
 winsup/cygwin/syscalls.cc | 68 +++++++++++++++++++++------------------
 winsup/cygwin/tty.cc      |  8 ++++-
 5 files changed, 72 insertions(+), 37 deletions(-)

diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index 160eba75c..43a546c42 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,3 +1,24 @@
+2003-03-07  Christopher Faylor  <cgf@redhat.com>
+
+	* path.h (PATH_LNK): New enum val.
+	(path_conv::is_lnk_symlink): New function.  True if path represents
+	.lnk style symlink.
+	* path.cc (check_shortcut): Set PATH_LNK in pflags when appropriate.
+	(symlink_info::check): Ditto.  Remove PATH_LNK from pflags initially.
+	* syscalls.cc (unlink): Always remove readonly attribute from a symlink
+	regardless of type.
+	(link): (from Corinna Vinschen) Allow links to symlinks.  Reset
+	attributes on a symlink after successful link creation.
+	(chmod): Use is_lnk_symlink where appropriate.
+	(rename): Ditto.
+
+2003-03-07  Pierre Humblet  <pierre.humblet@ieee.org>
+
+	* tty.cc (create_tty_master): Call GetComputerName instead of
+	cygwin_gethostname.  Set ut_id.
+	* syscalls.cc (login): Call endutent.
+	(setutent): Do not seek after a fresh open.
+
 2003-03-07  Corinna Vinschen  <corinna@vinschen.de>
 
 	* syscalls.cc (seteuid32): Fix formatting.
@@ -6,7 +27,7 @@
 
 	* thread.cc (MTinterface::fixup_after_fork): Initialize mainthread
 	prior to pthread objects.
-	
+
 2003-03-04  Jason Tishler <jason@tishler.net>
 
 	* fhandler_socket.cc (fhandler_socket::dup): Initialize type.
diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc
index dea1d372f..40a20fb14 100644
--- a/winsup/cygwin/path.cc
+++ b/winsup/cygwin/path.cc
@@ -2775,7 +2775,7 @@ check_shortcut (const char *path, DWORD fileattr, HANDLE h,
   contents[len] = '\0';
   res = len;
   if (res) /* It's a symlink.  */
-    *pflags = PATH_SYMLINK;
+    *pflags = PATH_SYMLINK | PATH_LNK;
   goto close_it;
 
 file_not_symlink:
@@ -2990,11 +2990,11 @@ symlink_info::check (char *path, const suffix_info *suffixes, unsigned opt)
   suffix_scan suffix;
   contents[0] = '\0';
 
-  is_symlink = TRUE;
+  is_symlink = true;
   ext_here = suffix.has (path, suffixes);
   extn = ext_here - path;
 
-  pflags &= ~PATH_SYMLINK;
+  pflags &= ~(PATH_SYMLINK | PATH_LNK);
 
   case_clash = false;
 
@@ -3043,6 +3043,8 @@ symlink_info::check (char *path, const suffix_info *suffixes, unsigned opt)
 	  (res = get_symlink_ea (suffix.path, contents, sizeof (contents))) > 0)
 	{
 	  pflags = PATH_SYMLINK;
+	  if (sym_check == 1)
+	    pflags |= PATH_LNK;
 	  debug_printf ("Got symlink from EA: %s", contents);
 	  break;
 	}
diff --git a/winsup/cygwin/path.h b/winsup/cygwin/path.h
index 4de14bf4b..bd5b4a286 100644
--- a/winsup/cygwin/path.h
+++ b/winsup/cygwin/path.h
@@ -47,6 +47,7 @@ enum path_types
   PATH_NOTEXEC = MOUNT_NOTEXEC,
   PATH_CYGWIN_EXEC = MOUNT_CYGWIN_EXEC,
   PATH_ALL_EXEC = (PATH_CYGWIN_EXEC | PATH_EXEC),
+  PATH_LNK =	      0x01000000,
   PATH_TEXT =	      0x02000000,
   PATH_ISDISK =	      0x04000000,
   PATH_HAS_SYMLINKS = 0x10000000,
@@ -97,6 +98,7 @@ class path_conv
     return 0;
   }
   int issymlink () const {return path_flags & PATH_SYMLINK;}
+  int is_lnk_symlink () const {return path_flags & PATH_LNK;}
   int issocket () const {return path_flags & PATH_SOCKET;}
   int iscygexec () const {return path_flags & PATH_CYGWIN_EXEC;}
   bool exists () const {return fileattr != INVALID_FILE_ATTRIBUTES;}
diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc
index e8f298c05..f184c03f1 100644
--- a/winsup/cygwin/syscalls.cc
+++ b/winsup/cygwin/syscalls.cc
@@ -134,12 +134,8 @@ unlink (const char *ourname)
     }
 
   /* Check for shortcut as symlink condition. */
-  if (win32_name.has_attribute (FILE_ATTRIBUTE_READONLY))
-    {
-      int len = strlen (win32_name);
-      if (len > 4 && strcasematch ((char *) win32_name + len - 4, ".lnk"))
-	SetFileAttributes (win32_name, (DWORD) win32_name & ~FILE_ATTRIBUTE_READONLY);
-    }
+  if (win32_name.issymlink ())
+    SetFileAttributes (win32_name, (DWORD) win32_name & ~FILE_ATTRIBUTE_READONLY);
 
   DWORD lasterr;
   lasterr = 0;
@@ -152,7 +148,7 @@ unlink (const char *ourname)
 	}
 
       lasterr = GetLastError ();
-      if (i || lasterr != ERROR_ACCESS_DENIED || win32_name.issymlink ())
+      if (i || lasterr != ERROR_ACCESS_DENIED)
 	break;		/* Couldn't delete it. */
 
       /* if access denied, chmod to be writable, in case it is not,
@@ -616,8 +612,9 @@ link (const char *a, const char *b)
 {
   int res = -1;
   sigframe thisframe (mainthread);
-  path_conv real_a (a, PC_SYM_FOLLOW | PC_FULL);
+  path_conv real_a (a, PC_SYM_NOFOLLOW | PC_FULL);
   path_conv real_b (b, PC_SYM_NOFOLLOW | PC_FULL);
+  extern BOOL allow_winsymlinks;
 
   if (real_a.error)
     {
@@ -645,14 +642,20 @@ link (const char *a, const char *b)
       goto done;
     }
 
+  /* Shortcut hack. */
+  char new_lnk_buf[MAX_PATH + 5];
+  if (allow_winsymlinks && real_a.is_lnk_symlink () && !real_b.case_clash)
+    {
+      strcpy (new_lnk_buf, b);
+      strcat (new_lnk_buf, ".lnk");
+      b = new_lnk_buf;
+      real_b.check (b, PC_SYM_NOFOLLOW);
+    }
   /* Try to make hard link first on Windows NT */
   if (wincap.has_hard_links ())
     {
       if (CreateHardLinkA (real_b, real_a, NULL))
-	{
-	  res = 0;
-	  goto done;
-	}
+	goto success;
 
       HANDLE hFileSource;
 
@@ -734,7 +737,13 @@ link (const char *a, const char *b)
       if (!bSuccess)
 	goto docopy;
 
+    success:
       res = 0;
+      if (!allow_winsymlinks && real_a.is_lnk_symlink ())
+	SetFileAttributes (real_b, (DWORD) real_a
+			           | FILE_ATTRIBUTE_SYSTEM
+				   | FILE_ATTRIBUTE_READONLY);
+
       goto done;
     }
 docopy:
@@ -923,7 +932,7 @@ chmod (const char *path, mode_t mode)
       else
 	(DWORD) win32_path |= FILE_ATTRIBUTE_READONLY;
 
-      if (S_ISLNK (mode) || S_ISSOCK (mode))
+      if (!win32_path.is_lnk_symlink () && S_ISLNK (mode) || S_ISSOCK (mode))
 	(DWORD) win32_path |= FILE_ATTRIBUTE_SYSTEM;
 
       if (!SetFileAttributes (win32_path, win32_path))
@@ -1257,16 +1266,12 @@ rename (const char *oldpath, const char *newpath)
 
   /* Shortcut hack. */
   char new_lnk_buf[MAX_PATH + 5];
-  if (real_old.issymlink () && !real_new.error && !real_new.case_clash)
+  if (real_old.is_lnk_symlink () && !real_new.error && !real_new.case_clash)
     {
-      int len_old = strlen (real_old.get_win32 ());
-      if (strcasematch (real_old.get_win32 () + len_old - 4, ".lnk"))
-	{
-	  strcpy (new_lnk_buf, newpath);
-	  strcat (new_lnk_buf, ".lnk");
-	  newpath = new_lnk_buf;
-	  real_new.check (newpath, PC_SYM_NOFOLLOW);
-	}
+      strcpy (new_lnk_buf, newpath);
+      strcat (new_lnk_buf, ".lnk");
+      newpath = new_lnk_buf;
+      real_new.check (newpath, PC_SYM_NOFOLLOW);
     }
 
   if (real_new.error || real_new.case_clash)
@@ -1296,9 +1301,8 @@ rename (const char *oldpath, const char *newpath)
     SetFileAttributes (real_new, (DWORD) real_new & ~FILE_ATTRIBUTE_READONLY);
 
   /* Shortcut hack No. 2, part 1 */
-  if (!real_old.issymlink () && !real_new.error && real_new.issymlink () &&
-      real_new.known_suffix && strcasematch (real_new.known_suffix, ".lnk") &&
-      (lnk_suffix = strrchr (real_new.get_win32 (), '.')))
+  if (!real_old.issymlink () && !real_new.error && real_new.is_lnk_symlink ()
+      && (lnk_suffix = strrchr (real_new.get_win32 (), '.')))
      *lnk_suffix = '\0';
 
   if (!MoveFile (real_old, real_new))
@@ -1385,7 +1389,7 @@ static void system_cleanup (void *args)
   signal (SIGINT, cleanup_args->oldint);
   signal (SIGQUIT, cleanup_args->oldquit);
   (void) sigprocmask (SIG_SETMASK, &cleanup_args->old_mask, 0);
-}  
+}
 
 extern "C" int
 system (const char *cmdstring)
@@ -2472,6 +2476,7 @@ login (struct utmp *ut)
   register int fd;
 
   pututline (ut);
+  endutent ();
   if ((fd = open (_PATH_WTMP, O_WRONLY | O_APPEND | O_BINARY, 0)) >= 0)
     {
       (void) write (fd, (char *) ut, sizeof (struct utmp));
@@ -2519,8 +2524,8 @@ logout (char *line)
 	      /* Found the entry for LINE; mark it as logged out.  */
 	      {
 		/* Zero out entries describing who's logged in.  */
-		bzero (ut->ut_name, sizeof (ut->ut_name));
-		bzero (ut->ut_host, sizeof (ut->ut_host));
+		memset (ut->ut_name, 0, sizeof (ut->ut_name));
+		memset (ut->ut_host, 0, sizeof (ut->ut_host));
 		time (&ut->ut_time);
 
 		/* Now seek back to the position in utmp at which UT occured,
@@ -2551,10 +2556,9 @@ setutent ()
 {
   sigframe thisframe (mainthread);
   if (utmp_fd == -2)
-    {
-      utmp_fd = open (utmp_file, O_RDWR);
-    }
-  lseek (utmp_fd, 0, SEEK_SET);
+    utmp_fd = open (utmp_file, O_RDWR);
+  else
+    lseek (utmp_fd, 0, SEEK_SET);
 }
 
 extern "C" void
diff --git a/winsup/cygwin/tty.cc b/winsup/cygwin/tty.cc
index 242a2a846..371887c20 100644
--- a/winsup/cygwin/tty.cc
+++ b/winsup/cygwin/tty.cc
@@ -81,12 +81,18 @@ create_tty_master (int ttynum)
     {
       /* Log utmp entry */
       struct utmp our_utmp;
+      DWORD len = sizeof our_utmp.ut_host;
 
       bzero ((char *) &our_utmp, sizeof (utmp));
       (void) time (&our_utmp.ut_time);
       strncpy (our_utmp.ut_name, getlogin (), sizeof (our_utmp.ut_name));
-      cygwin_gethostname (our_utmp.ut_host, sizeof (our_utmp.ut_host));
+      GetComputerName (our_utmp.ut_host, &len);
       __small_sprintf (our_utmp.ut_line, "tty%d", ttynum);
+      if ((len = strlen (our_utmp.ut_line)) >= UT_IDLEN)
+	len -= UT_IDLEN;
+      else
+	len = 0;
+      strncpy (our_utmp.ut_id, our_utmp.ut_line + len, UT_IDLEN);
       our_utmp.ut_type = USER_PROCESS;
       our_utmp.ut_pid = myself->pid;
       myself->ctty = ttynum;