public inbox for cygwin-patches@cygwin.com
 help / color / mirror / Atom feed
* [PATCH rebase] Add support for Compact OS compression for Cygwin
@ 2022-07-14 10:02 Christian Franke
  2022-07-14 10:24 ` Corinna Vinschen
  0 siblings, 1 reply; 6+ messages in thread
From: Christian Franke @ 2022-07-14 10:02 UTC (permalink / raw)
  To: cygwin-patches

[-- Attachment #1: Type: text/plain, Size: 188 bytes --]

[Sorry if this is the wrong list]

This finally completes '--compact-os' support of Cygwin setup.
https://sourceware.org/pipermail/cygwin-apps/2021-May/041225.html

-- 
Regards
Christian


[-- Attachment #2: 0001-Add-support-for-Compact-OS-compression-for-Cygwin.patch --]
[-- Type: text/plain, Size: 10214 bytes --]

From 807ae9fbaef18491f3aa1e94e66dd21eb6748c3e Mon Sep 17 00:00:00 2001
From: Christian Franke <christian.franke@t-online.de>
Date: Thu, 14 Jul 2022 11:59:50 +0200
Subject: [PATCH] Add support for Compact OS compression for Cygwin

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>
---
 rebase.c | 199 +++++++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 155 insertions(+), 44 deletions(-)

diff --git a/rebase.c b/rebase.c
index a403c85..06828bb 100644
--- a/rebase.c
+++ b/rebase.c
@@ -39,6 +39,10 @@
 #include <errno.h>
 #include "imagehelper.h"
 #include "rebase-db.h"
+#if defined(__CYGWIN__)
+#include <io.h>
+#include <versionhelpers.h>
+#endif
 
 BOOL save_image_info ();
 BOOL load_image_info ();
@@ -48,6 +52,10 @@ 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);
+#if defined(__CYGWIN__)
+static int compactos_get_algorithm (const char *pathname);
+static int compactos_compress_file (const char *pathname, int algorithm);
+#endif
 void usage ();
 void help ();
 BOOL is_rebaseable (const char *pathname);
@@ -259,9 +267,19 @@ main (int argc, char *argv[])
       ULONG64 new_image_base = image_base;
       for (i = 0; i < img_info_size; ++i)
 	{
+#if defined(__CYGWIN__)
+	  int compactos_algorithm
+	      = compactos_get_algorithm (img_info_list[i].name);
+#endif
 	  status = rebase (img_info_list[i].name, &new_image_base, down_flag);
 	  if (!status)
 	    return 2;
+#if defined(__CYGWIN__)
+	  /* Reapply previous compression. */
+	  if (compactos_algorithm >= 0)
+	    compactos_compress_file (img_info_list[i].name,
+				     compactos_algorithm);
+#endif
 	}
     }
   else
@@ -269,6 +287,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 +300,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 +618,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 +741,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 +763,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 +1416,81 @@ string_to_ulonglong (const char *string)
   return number;
 }
 
+#if defined(__CYGWIN__)
+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;
+}
+#endif
+
 void
 usage ()
 {
-- 
2.37.1


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2022-07-14 14:54 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-07-14 10:02 [PATCH rebase] Add support for Compact OS compression for Cygwin Christian Franke
2022-07-14 10:24 ` Corinna Vinschen
2022-07-14 12:12   ` Christian Franke
2022-07-14 14:28     ` Corinna Vinschen
2022-07-14 14:41       ` Christian Franke
2022-07-14 14:54         ` 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).