public inbox for cygwin-apps-cvs@sourceware.org
help / color / mirror / Atom feed
* [rebase - The rebase tool, core of the automatic rebase facility during postinstall] branch master, updated. 6aab23f9cf5fd50a06c6d51ffb8396b872d2b8fc
@ 2022-07-14 14:53 Corinna Vinschen
  0 siblings, 0 replies; only message in thread
From: Corinna Vinschen @ 2022-07-14 14:53 UTC (permalink / raw)
  To: cygwin-apps-cvs




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 ()
 {



^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-07-14 14:53 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-07-14 14:53 [rebase - The rebase tool, core of the automatic rebase facility during postinstall] branch master, updated. 6aab23f9cf5fd50a06c6d51ffb8396b872d2b8fc Corinna Vinschen

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).