public inbox for cygwin-apps-cvs@sourceware.org
help / color / mirror / Atom feed
From: Corinna Vinschen <corinna@sourceware.org>
To: cygwin-apps-cvs@sourceware.org
Subject: [rebase - The rebase tool, core of the automatic rebase facility during postinstall] branch master, updated. 6aab23f9cf5fd50a06c6d51ffb8396b872d2b8fc
Date: Thu, 14 Jul 2022 14:53:35 +0000 (GMT)	[thread overview]
Message-ID: <20220714145335.AB0DF3858C55@sourceware.org> (raw)




https://sourceware.org/git/gitweb.cgi?p=cygwin-apps/rebase.git;h=6aab23f9cf5fd50a06c6d51ffb8396b872d2b8fc

commit 6aab23f9cf5fd50a06c6d51ffb8396b872d2b8fc
Author: Christian Franke <christian.franke@t-online.de>
Date:   Thu Jul 14 13:54:12 2022 +0200

    Add support for Compact OS compression
    
    Preserve compression of manually rebased files.
    Align compression with Cygwin DLL if database is used.
    Only check for writability if file needs rebasing to keep
    compression of unchanged files.
    
    Signed-off-by: Christian Franke <christian.franke@t-online.de>


Diff:
---
 rebase.c | 189 ++++++++++++++++++++++++++++++++++++++++++++++++---------------
 1 file changed, 145 insertions(+), 44 deletions(-)

diff --git a/rebase.c b/rebase.c
index a403c85..5cda123 100644
--- a/rebase.c
+++ b/rebase.c
@@ -37,8 +37,10 @@
 #include <getopt.h>
 #include <string.h>
 #include <errno.h>
+#include <io.h>
 #include "imagehelper.h"
 #include "rebase-db.h"
+#include <versionhelpers.h> /* requires <windows.h> */
 
 BOOL save_image_info ();
 BOOL load_image_info ();
@@ -48,6 +50,8 @@ void print_image_info ();
 BOOL rebase (const char *pathname, ULONG64 *new_image_base, BOOL down_flag);
 void parse_args (int argc, char *argv[]);
 unsigned long long string_to_ulonglong (const char *string);
+static int compactos_get_algorithm (const char *pathname);
+static int compactos_compress_file (const char *pathname, int algorithm);
 void usage ();
 void help ();
 BOOL is_rebaseable (const char *pathname);
@@ -259,9 +263,15 @@ main (int argc, char *argv[])
       ULONG64 new_image_base = image_base;
       for (i = 0; i < img_info_size; ++i)
 	{
+	  int compactos_algorithm
+	      = compactos_get_algorithm (img_info_list[i].name);
 	  status = rebase (img_info_list[i].name, &new_image_base, down_flag);
 	  if (!status)
 	    return 2;
+	  /* Reapply previous compression. */
+	  if (compactos_algorithm >= 0)
+	    compactos_compress_file (img_info_list[i].name,
+				     compactos_algorithm);
 	}
     }
   else
@@ -269,6 +279,9 @@ main (int argc, char *argv[])
       /* Rebase with database support. */
       BOOL header;
 
+#if defined(__CYGWIN__)
+      int compactos_algorithm = compactos_get_algorithm ("/bin/cygwin1.dll");
+#endif
       if (merge_image_info () < 0)
 	return 2;
       status = TRUE;
@@ -279,6 +292,14 @@ main (int argc, char *argv[])
 	    status = rebase (img_info_list[i].name, &new_image_base, FALSE);
 	    if (status)
 	      img_info_list[i].flag.needs_rebasing = 0;
+#if defined(__CYGWIN__)
+	    /* If Cygwin DLL is compressed, assume setup was used with option
+	       --compact-os.  Align compression with Cygwin DLL. */
+	    if (compactos_algorithm >= 0
+		&& compactos_compress_file (img_info_list[i].name,
+					    compactos_algorithm) < 0)
+	      compactos_algorithm = -1;
+#endif
 	  }
       for (header = FALSE, i = 0; i < img_info_size; ++i)
 	if (img_info_list[i].flag.cannot_rebase == 1)
@@ -589,6 +610,7 @@ set_cannot_rebase (img_info_t *img)
    * is set to 2 on loading the database entries */
   if (img->flag.cannot_rebase <= 1 )
     {
+      /* This also removes Compact OS compression. */
       int fd = open (img->name, O_WRONLY);
       if (fd < 0)
 	img->flag.cannot_rebase = 1;
@@ -711,7 +733,7 @@ merge_image_info ()
      to match with reality. */
   for (i = 0; i < img_info_rebase_start; ++i)
     {
-      ULONG64 cur_base;
+      ULONG64 cur_base, cur_base_orig;
       ULONG cur_size, slot_size;
 
       /* Files with the needs_rebasing or cannot_rebase flags set have been
@@ -733,55 +755,61 @@ merge_image_info ()
 	  continue;
 	}
       slot_size = roundup2 (cur_size, ALLOCATION_SLOT);
-      if (set_cannot_rebase (&img_info_list[i]))
-	img_info_list[i].base = cur_base;
-      else
+      cur_base_orig = cur_base;
+      /* If the file has been reinstalled, try to rebase to the same address
+	 in the first place. */
+      if (cur_base != img_info_list[i].base)
 	{
-	  /* If the file has been reinstalled, try to rebase to the same address
-	     in the first place. */
-	  if (cur_base != img_info_list[i].base)
-	    {
-	      img_info_list[i].flag.needs_rebasing = 1;
-	      if (verbose)
-		fprintf (stderr, "rebasing %s because it's base has changed (due to being reinstalled?)\n", img_info_list[i].name);
-	      /* Set cur_base to the old base to simplify subsequent tests. */
-	      cur_base = img_info_list[i].base;
-	    }
-	  /* However, if the DLL got bigger and doesn't fit into its slot
-	     anymore, rebase this DLL from scratch. */
-	  if (i + 1 < img_info_rebase_start
-	      && cur_base + slot_size + offset > img_info_list[i + 1].base)
-	    {
-	      img_info_list[i].base = 0;
-	      if (verbose)
-		fprintf (stderr, "rebasing %s because it won't fit in it's old slot without overlapping next DLL\n", img_info_list[i].name);
-	    }
-	  /* Does the previous DLL reach into the address space of this
-	     DLL?  This happens if the previous DLL is not rebaseable. */
-	  else if (i > 0 && cur_base < img_info_list[i - 1].base
-				       + img_info_list[i - 1].slot_size)
-	    {
-	      img_info_list[i].base = 0;
-	      if (verbose)
-		fprintf (stderr, "rebasing %s because previous DLL now overlaps\n", img_info_list[i].name);
-	    }
-	  /* Does the file match the base address requirements?  If not,
-	     rebase from scratch. */
-	  else if ((down_flag && cur_base + slot_size + offset > image_base)
-		   || (!down_flag && cur_base < image_base))
-	    {
-	      img_info_list[i].base = 0;
-	      if (verbose)
-		fprintf (stderr, "rebasing %s because it's base address is outside the expected area\n", img_info_list[i].name);
-	    }
+	  img_info_list[i].flag.needs_rebasing = 1;
+	  if (verbose)
+	    fprintf (stderr, "rebasing %s because it's base has changed (due to being reinstalled?)\n", img_info_list[i].name);
+	  /* Set cur_base to the old base to simplify subsequent tests. */
+	  cur_base = img_info_list[i].base;
+	}
+      /* However, if the DLL got bigger and doesn't fit into its slot
+	 anymore, rebase this DLL from scratch. */
+      if (i + 1 < img_info_rebase_start
+	  && cur_base + slot_size + offset > img_info_list[i + 1].base)
+	{
+	  img_info_list[i].base = 0;
+	  if (verbose)
+	    fprintf (stderr, "rebasing %s because it won't fit in it's old slot without overlapping next DLL\n", img_info_list[i].name);
+	}
+      /* Does the previous DLL reach into the address space of this
+	 DLL?  This happens if the previous DLL is not rebaseable. */
+      else if (i > 0 && cur_base < img_info_list[i - 1].base
+				   + img_info_list[i - 1].slot_size)
+	{
+	  img_info_list[i].base = 0;
+	  if (verbose)
+	    fprintf (stderr, "rebasing %s because previous DLL now overlaps\n", img_info_list[i].name);
+	}
+      /* Does the file match the base address requirements?  If not,
+	 rebase from scratch. */
+      else if ((down_flag && cur_base + slot_size + offset > image_base)
+	       || (!down_flag && cur_base < image_base))
+	{
+	  img_info_list[i].base = 0;
+	  if (verbose)
+	    fprintf (stderr, "rebasing %s because it's base address is outside the expected area\n", img_info_list[i].name);
 	}
-      /* Unconditionally overwrite old with new size. */
-      img_info_list[i].size = cur_size;
-      img_info_list[i].slot_size = slot_size;
       /* Make sure all DLLs with base address 0 have the needs_rebasing
 	 flag set. */
       if (img_info_list[i].base == 0)
 	img_info_list[i].flag.needs_rebasing = 1;
+      /* Only check for writability if file needs rebasing to keep
+	 Compact OS compression of unchanged files.  Revert rebase
+	 decision if not writeable. */
+      if (img_info_list[i].flag.needs_rebasing && set_cannot_rebase (&img_info_list[i]))
+	{
+	  img_info_list[i].flag.needs_rebasing = 0;
+	  img_info_list[i].base = cur_base_orig;
+	  if (verbose)
+	    fprintf (stderr, "rebasing %s deferred because file is not writable\n", img_info_list[i].name);
+	}
+      /* Unconditionally overwrite old with new size. */
+      img_info_list[i].size = cur_size;
+      img_info_list[i].slot_size = slot_size;
     }
   /* The remainder of the function expects img_info_size to be > 0. */
   if (img_info_size == 0)
@@ -1380,6 +1408,79 @@ string_to_ulonglong (const char *string)
   return number;
 }
 
+static int
+compactos_get_algorithm (const char *pathname)
+{
+  /* Requires Win10. */
+  if (!IsWindows10OrGreater ())
+    return -1;
+
+  int fd = open (pathname, O_RDONLY);
+  if (fd == -1)
+    return -1;
+
+  struct {
+    WOF_EXTERNAL_INFO Wof;
+    FILE_PROVIDER_EXTERNAL_INFO_V1 FileProvider;
+  } wfp = { {0, 0}, {0, 0, 0} };
+
+  int rc;
+  if (!DeviceIoControl ((HANDLE) _get_osfhandle (fd),
+			FSCTL_GET_EXTERNAL_BACKING, NULL, 0,
+			&wfp, sizeof(wfp), NULL, NULL))
+    rc = -1;
+  else
+    rc = (wfp.Wof.Provider == WOF_PROVIDER_FILE ?
+	  wfp.FileProvider.Algorithm : -1);
+
+  close (fd);
+  return rc;
+}
+
+static int
+compactos_compress_file (const char *pathname, int algorithm)
+{
+  /* Do not apply unknown algorithms. */
+  if (!(FILE_PROVIDER_COMPRESSION_XPRESS4K <= algorithm &&
+        algorithm <= FILE_PROVIDER_COMPRESSION_XPRESS16K))
+    return 0;
+
+  int fd = open (pathname, O_RDONLY);
+  if (fd == -1)
+    return -1;
+  HANDLE h = (HANDLE) _get_osfhandle (fd);
+
+  /* Older versions of Win10 set mtime to current time. */
+  FILETIME ft;
+  BOOL ft_valid = GetFileTime (h, NULL, NULL, &ft);
+
+  struct {
+    WOF_EXTERNAL_INFO Wof;
+    FILE_PROVIDER_EXTERNAL_INFO_V1 FileProvider;
+  } wfp;
+  wfp.Wof.Version = WOF_CURRENT_VERSION;
+  wfp.Wof.Provider = WOF_PROVIDER_FILE;
+  wfp.FileProvider.Version = FILE_PROVIDER_CURRENT_VERSION;
+  wfp.FileProvider.Algorithm = algorithm;
+  wfp.FileProvider.Flags = 0;
+
+  int rc;
+  if (!DeviceIoControl (h, FSCTL_SET_EXTERNAL_BACKING, &wfp, sizeof(wfp),
+			NULL, 0, NULL, NULL))
+    rc = (GetLastError() == ERROR_COMPRESSION_NOT_BENEFICIAL ? 0 : -1);
+  else
+    rc = 1;
+
+  if (ft_valid)
+    SetFileTime (h, NULL, NULL, &ft);
+
+  close (fd);
+  if (verbose)
+    printf ("%s: Compact OS algorithm %d %s\n", pathname, algorithm,
+	    (rc < 0 ? "FAILED" : rc == 0 ? "not applied " : "applied"));
+  return rc;
+}
+
 void
 usage ()
 {



                 reply	other threads:[~2022-07-14 14:53 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220714145335.AB0DF3858C55@sourceware.org \
    --to=corinna@sourceware.org \
    --cc=cygwin-apps-cvs@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).