New Upstream Release - winregfs

Ready changes

Summary

Merged new upstream version: 0.8 (was: 0.7).

Resulting package

Built on 2023-01-04T19:02 (took 5m19s)

The resulting binary packages can be installed (if you have the apt repository enabled) by running one of:

apt install -t fresh-releases winregfs

Lintian Result

Diff

diff --git a/LICENSE b/LICENSE
deleted file mode 100644
index a43ea21..0000000
--- a/LICENSE
+++ /dev/null
@@ -1,339 +0,0 @@
-		    GNU GENERAL PUBLIC LICENSE
-		       Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
-                          675 Mass Ave, Cambridge, MA 02139, USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-			    Preamble
-
-  The licenses for most software are designed to take away your
-freedom to share and change it.  By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users.  This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it.  (Some other Free Software Foundation software is covered by
-the GNU Library General Public License instead.)  You can apply it to
-your programs, too.
-
-  When we speak of free software, we are referring to freedom, not
-price.  Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
-  To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
-  For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have.  You must make sure that they, too, receive or can get the
-source code.  And you must show them these terms so they know their
-rights.
-
-  We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
-  Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software.  If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
-  Finally, any free program is threatened constantly by software
-patents.  We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary.  To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
-  The precise terms and conditions for copying, distribution and
-modification follow.
-
-		    GNU GENERAL PUBLIC LICENSE
-   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
-  0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License.  The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language.  (Hereinafter, translation is included without limitation in
-the term "modification".)  Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope.  The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
-  1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
-  2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
-    a) You must cause the modified files to carry prominent notices
-    stating that you changed the files and the date of any change.
-
-    b) You must cause any work that you distribute or publish, that in
-    whole or in part contains or is derived from the Program or any
-    part thereof, to be licensed as a whole at no charge to all third
-    parties under the terms of this License.
-
-    c) If the modified program normally reads commands interactively
-    when run, you must cause it, when started running for such
-    interactive use in the most ordinary way, to print or display an
-    announcement including an appropriate copyright notice and a
-    notice that there is no warranty (or else, saying that you provide
-    a warranty) and that users may redistribute the program under
-    these conditions, and telling the user how to view a copy of this
-    License.  (Exception: if the Program itself is interactive but
-    does not normally print such an announcement, your work based on
-    the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole.  If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works.  But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
-  3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
-    a) Accompany it with the complete corresponding machine-readable
-    source code, which must be distributed under the terms of Sections
-    1 and 2 above on a medium customarily used for software interchange; or,
-
-    b) Accompany it with a written offer, valid for at least three
-    years, to give any third party, for a charge no more than your
-    cost of physically performing source distribution, a complete
-    machine-readable copy of the corresponding source code, to be
-    distributed under the terms of Sections 1 and 2 above on a medium
-    customarily used for software interchange; or,
-
-    c) Accompany it with the information you received as to the offer
-    to distribute corresponding source code.  (This alternative is
-    allowed only for noncommercial distribution and only if you
-    received the program in object code or executable form with such
-    an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it.  For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable.  However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
-  4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License.  Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
-  5. You are not required to accept this License, since you have not
-signed it.  However, nothing else grants you permission to modify or
-distribute the Program or its derivative works.  These actions are
-prohibited by law if you do not accept this License.  Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
-  6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions.  You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
-  7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License.  If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all.  For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices.  Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
-  8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded.  In such case, this License incorporates
-the limitation as if written in the body of this License.
-
-  9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time.  Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number.  If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation.  If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
-  10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission.  For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this.  Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
-			    NO WARRANTY
-
-  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
-  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
-		     END OF TERMS AND CONDITIONS
-
-	Appendix: How to Apply These Terms to Your New Programs
-
-  If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
-  To do so, attach the following notices to the program.  It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
-    <one line to give the program's name and a brief idea of what it does.>
-    Copyright (C) 19yy  <name of author>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
-    Gnomovision version 69, Copyright (C) 19yy name of author
-    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
-    This is free software, and you are welcome to redistribute it
-    under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License.  Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary.  Here is a sample; alter the names:
-
-  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
-  `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
-  <signature of Ty Coon>, 1 April 1989
-  Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs.  If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library.  If this is what you want to do, use the GNU Library General
-Public License instead of this License.
diff --git a/LGPL.txt b/LICENSE-LGPLv2.1
similarity index 100%
rename from LGPL.txt
rename to LICENSE-LGPLv2.1
diff --git a/LICENSE-MIT b/LICENSE-MIT
new file mode 100644
index 0000000..9167167
--- /dev/null
+++ b/LICENSE-MIT
@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (C) 2014-2021 Jody Lee Bruchon and contributors
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/README b/README
index 81feea8..6d0d8fd 100644
--- a/README
+++ b/README
@@ -4,6 +4,16 @@
      If you have any questions, comments, or patches, send me an email:
                                jody@jodybruchon.com
 
+    This program's components are distributed under either LGPL v2.1 or
+       The MIT License. Compiled binaries thus fall under LGPL v2.1.
+
+********** BIG FAT WARNING **********
+
+ALWAYS BACK UP REGISTRY HIVES BEFORE EDITING THEM WITH WINREGFS! THIS SOFTWARE
+IS NOT PRODUCTION-SAFE! IT WORKS, BUT HAS SEVERAL BUGS! YOU HAVE BEEN WARNED!
+
+********** BIG FAT WARNING **********
+
 One of the most difficult things to deal with in years of writing Linux
 utilities to work with and repair Windows PCs is the Windows registry.
 While many excellent tools exist to work with NTFS filesystems and to change
@@ -146,6 +156,7 @@ You can probably figure out what to do with it from here. ;-)
 LICENSING NOTICE
 ----------------
 
-ntreg.c and ntreg.h are distributed under the terms of the LGPL as described
-in LGPL.txt while all other winregfs components are licensed under the terms
-of the GNU GPL as described in LICENSE.
+ntreg.c and ntreg.h are distributed under the terms of the LGPL v2.1 (see
+LICENSE-LGPLv2.1); all other components are distributed under the terms of
+The MIT License (see LICENSE-MIT). Any binaries compiled from this code are
+under LGPL v2.1.
diff --git a/TODO b/TODO
index a9595fa..1520ae8 100644
--- a/TODO
+++ b/TODO
@@ -1,15 +1,14 @@
           Windows Registry FUSE Filesystem TODO list
           ------------------------------------------
 
+* Fix issue where empty (default) value (@) can't be opened
+
 * Fix 8 KiB file write limit issue (may really be in ntreg.c)
   For now an error is issued on attempts to write >8192 bytes
   since there are extremely few values that contain this much
   data; the XP compatibility shim cache is pretty much the
   only value of such a size (all others are <6000 bytes)
 
-* Allow arbitrary value types using a hexadecimal extension
-(used in SAM and some MS Click-to-Run registry keys)
-
 * Unicode and non-ASCII character support
   This is not only useful for non-Latin characters, it also
   can be used to find novel registry-resident malware such as
diff --git a/debian/changelog b/debian/changelog
index 09fbd51..b288464 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+winregfs (0.8-1) UNRELEASED; urgency=low
+
+  * New upstream release.
+
+ -- Debian Janitor <janitor@jelmer.uk>  Wed, 04 Jan 2023 18:57:28 -0000
+
 winregfs (0.7-4) unstable; urgency=medium
 
   [ Giovani Augusto Ferreira ]
diff --git a/debian/patches/cross.patch b/debian/patches/cross.patch
index 825684f..c8d603c 100644
--- a/debian/patches/cross.patch
+++ b/debian/patches/cross.patch
@@ -1,10 +1,10 @@
 Description: Fix fail to cross build from source.
 Author: Helmut Grohne <helmut@subdivi.de>
 Last-Update: 2018-06-03
-Index: winregfs/Makefile
+Index: winregfs.git/Makefile
 ===================================================================
---- winregfs.orig/Makefile
-+++ winregfs/Makefile
+--- winregfs.git.orig/Makefile
++++ winregfs.git/Makefile
 @@ -1,4 +1,6 @@
  CC=gcc
 +INSTALL?=install
diff --git a/debian/patches/fix-install.patch b/debian/patches/fix-install.patch
index 8f9412d..765f5ec 100644
--- a/debian/patches/fix-install.patch
+++ b/debian/patches/fix-install.patch
@@ -1,10 +1,10 @@
 Description: Fix install path to manpages and add GCC hardening.
 Author: Giovani Augusto Ferreira <giovani@debian.org>
 Last-Update: 2017-06-24
-Index: winregfs-0.7/Makefile
+Index: winregfs.git/Makefile
 ===================================================================
---- winregfs-0.7.orig/Makefile
-+++ winregfs-0.7/Makefile
+--- winregfs.git.orig/Makefile
++++ winregfs.git/Makefile
 @@ -1,14 +1,14 @@
  CC=gcc
 -CFLAGS=-O2 -g
diff --git a/fsck.winregfs.8 b/fsck.winregfs.8
index b29ca0c..e876f7f 100644
--- a/fsck.winregfs.8
+++ b/fsck.winregfs.8
@@ -1,7 +1,7 @@
-.\" Copyright (c) 2014-2017 Jody Bruchon
-.\" Licensed under the GNU General Public License v2
+.\" Copyright (c) 2014-2021 Jody Bruchon
+.\" Released under The MIT License
 .\"
-.TH winregfs 8 "20 May 2014" "fsck.winregfs"
+.TH winregfs 8 "10 Jul 2021" "fsck.winregfs"
 .SH NAME
 fsck.winregfs \- Check a Windows registry file
 .SH SYNOPSIS
diff --git a/fsck_winregfs.c b/fsck_winregfs.c
index 34477ad..3c90c86 100644
--- a/fsck_winregfs.c
+++ b/fsck_winregfs.c
@@ -2,10 +2,8 @@
  * Windows registry "filesystem checker"
  * Reads all the keys in a hive and reports any errors triggered
  *
- * Copyright (C) 2014-2017 by Jody Bruchon <jody@jodybruchon.com>
- *
- * Licensed under GNU GPL v2. See LICENSE and README for details.
- *
+ * Copyright (C) 2014-2021 by Jody Bruchon <jody@jodybruchon.com>
+ * Released under The MIT License
  */
 
 #define FSCK_WINREGFS
diff --git a/jody_hash.c b/jody_hash.c
index 02887f3..b58eb0f 100644
--- a/jody_hash.c
+++ b/jody_hash.c
@@ -5,7 +5,7 @@
  * a secure hash algorithm, but the calculation is drastically simpler
  * and faster.
  *
- * Copyright (C) 2014-2017 by Jody Bruchon <jody@jodybruchon.com>
+ * Copyright (C) 2014-2021 by Jody Bruchon <jody@jodybruchon.com>
  * Released under The MIT License
  */
 
@@ -17,23 +17,23 @@
  * This shift was decided upon after lots of testing and
  * changing it will likely cause lots of hash collisions. */
 #ifndef JODY_HASH_SHIFT
-#define JODY_HASH_SHIFT 11
+#define JODY_HASH_SHIFT 14
 #endif
 
 /* The salt value's purpose is to cause each byte in the
- * hash_t word to have a positionally dependent variation.
+ * jodyhash_t word to have a positionally dependent variation.
  * It is injected into the calculation to prevent a string of
  * identical bytes from easily producing an identical hash. */
 
 /* The tail mask table is used for block sizes that are
- * indivisible by the width of a hash_t. It is ANDed with the
- * final hash_t-sized element to zero out data in the buffer
+ * indivisible by the width of a jodyhash_t. It is ANDed with the
+ * final jodyhash_t-sized element to zero out data in the buffer
  * that is not part of the data to be hashed. */
 
 /* Set hash parameters based on requested hash width */
 #if JODY_HASH_WIDTH == 64
 #define JODY_HASH_CONSTANT 0x1f3d5b79U
-static const hash_t tail_mask[] = {
+static const jodyhash_t tail_mask[] = {
 	0x0000000000000000,
 	0x00000000000000ff,
 	0x000000000000ffff,
@@ -47,7 +47,7 @@ static const hash_t tail_mask[] = {
 #endif /* JODY_HASH_WIDTH == 64 */
 #if JODY_HASH_WIDTH == 32
 #define JODY_HASH_CONSTANT 0x1f3d5b79U
-static const hash_t tail_mask[] = {
+static const jodyhash_t tail_mask[] = {
 	0x00000000,
 	0x000000ff,
 	0x0000ffff,
@@ -57,7 +57,7 @@ static const hash_t tail_mask[] = {
 #endif /* JODY_HASH_WIDTH == 32 */
 #if JODY_HASH_WIDTH == 16
 #define JODY_HASH_CONSTANT 0x1f5bU
-static const hash_t tail_mask[] = {
+static const jodyhash_t tail_mask[] = {
 	0x0000,
 	0x00ff,
 	0xffff,
@@ -65,47 +65,47 @@ static const hash_t tail_mask[] = {
 #endif /* JODY_HASH_WIDTH == 16 */
 
 
-/* Hash a block of arbitrary size; must be divisible by sizeof(hash_t)
+/* Hash a block of arbitrary size; must be divisible by sizeof(jodyhash_t)
  * The first block should pass a start_hash of zero.
  * All blocks after the first should pass start_hash as the value
  * returned by the last call to this function. This allows hashing
  * of any amount of data. If data is not divisible by the size of
- * hash_t, it is MANDATORY that the caller provide a data buffer
- * which is divisible by sizeof(hash_t). */
-extern hash_t jody_block_hash(const hash_t * restrict data,
-		const hash_t start_hash, const size_t count)
+ * jodyhash_t, it is MANDATORY that the caller provide a data buffer
+ * which is divisible by sizeof(jodyhash_t). */
+extern jodyhash_t jody_block_hash(const jodyhash_t * restrict data,
+		const jodyhash_t start_hash, const size_t count)
 {
-	hash_t hash = start_hash;
-	hash_t element;
-	hash_t partial_salt;
+	jodyhash_t hash = start_hash;
+	jodyhash_t element;
+	jodyhash_t partial_salt;
 	size_t len;
 
 	/* Don't bother trying to hash a zero-length block */
 	if (count == 0) return hash;
 
-	len = count / sizeof(hash_t);
+	len = count / sizeof(jodyhash_t);
 	for (; len > 0; len--) {
 		element = *data;
 		hash += element;
 		hash += JODY_HASH_CONSTANT;
-		hash = (hash << JODY_HASH_SHIFT) | hash >> (sizeof(hash_t) * 8 - JODY_HASH_SHIFT);
+		hash = (hash << JODY_HASH_SHIFT) | hash >> (sizeof(jodyhash_t) * 8 - JODY_HASH_SHIFT); /* bit rotate left */
 		hash ^= element;
-		hash = (hash << JODY_HASH_SHIFT) | hash >> (sizeof(hash_t) * 8 - JODY_HASH_SHIFT);
+		hash = (hash << JODY_HASH_SHIFT) | hash >> (sizeof(jodyhash_t) * 8 - JODY_HASH_SHIFT);
 		hash ^= JODY_HASH_CONSTANT;
 		hash += element;
 		data++;
 	}
 
-	/* Handle data tail (for blocks indivisible by sizeof(hash_t)) */
-	len = count & (sizeof(hash_t) - 1);
+	/* Handle data tail (for blocks indivisible by sizeof(jodyhash_t)) */
+	len = count & (sizeof(jodyhash_t) - 1);
 	if (len) {
 		partial_salt = JODY_HASH_CONSTANT & tail_mask[len];
 		element = *data & tail_mask[len];
 		hash += element;
 		hash += partial_salt;
-		hash = (hash << JODY_HASH_SHIFT) | hash >> (sizeof(hash_t) * 8 - JODY_HASH_SHIFT);
+		hash = (hash << JODY_HASH_SHIFT) | hash >> (sizeof(jodyhash_t) * 8 - JODY_HASH_SHIFT);
 		hash ^= element;
-		hash = (hash << JODY_HASH_SHIFT) | hash >> (sizeof(hash_t) * 8 - JODY_HASH_SHIFT);
+		hash = (hash << JODY_HASH_SHIFT) | hash >> (sizeof(jodyhash_t) * 8 - JODY_HASH_SHIFT);
 		hash ^= partial_salt;
 		hash += element;
 	}
diff --git a/jody_hash.h b/jody_hash.h
index 8cfabf5..eebe10d 100644
--- a/jody_hash.h
+++ b/jody_hash.h
@@ -12,26 +12,30 @@ extern "C" {
 #include <stdint.h>
 
 /* Width of a jody_hash. Changing this will also require
- * changing the width of tail masks and endian conversion */
+ * changing the width of tail masks to match. */
 #ifndef JODY_HASH_WIDTH
 #define JODY_HASH_WIDTH 64
 #endif
 
 #if JODY_HASH_WIDTH == 64
-typedef uint64_t hash_t;
+typedef uint64_t jodyhash_t;
 #endif
 #if JODY_HASH_WIDTH == 32
-typedef uint32_t hash_t;
+typedef uint32_t jodyhash_t;
 #endif
 #if JODY_HASH_WIDTH == 16
-typedef uint16_t hash_t;
+typedef uint16_t jodyhash_t;
+#endif
+
+#ifndef JODY_HASH_NOCOMPAT
+typedef jodyhash_t hash_t;
 #endif
 
 /* Version increments when algorithm changes incompatibly */
-#define JODY_HASH_VERSION 4
+#define JODY_HASH_VERSION 5
 
-extern hash_t jody_block_hash(const hash_t * restrict data,
-		const hash_t start_hash, const size_t count);
+extern jodyhash_t jody_block_hash(const jodyhash_t * restrict data,
+		const jodyhash_t start_hash, const size_t count);
 
 #ifdef __cplusplus
 }
diff --git a/jody_string.c b/jody_string.c
index ddcf4b7..ccd9985 100644
--- a/jody_string.c
+++ b/jody_string.c
@@ -1,7 +1,7 @@
 /*
  * Jody Bruchon's string function library  <jody@jodybruchon.com>
- * Copyright (C) 2015-2017
- * Distributed under the GNU General Public License version 2
+ * Copyright (C) 2015-2021
+ * Released under The MIT License
  */
 
 #include <stdint.h>
diff --git a/jody_string.h b/jody_string.h
index d0bf44d..f3aa6c2 100644
--- a/jody_string.h
+++ b/jody_string.h
@@ -1,7 +1,8 @@
 /*
- * Jody Bruchon's string function library  <jody@jodybruchon.com>
- * Copyright (C) 2015-2017
- * Distributed under the GNU General Public License version 2
+ * Jody Bruchon's string function library
+ *
+ * Copyright (C) 2015-2021 by Jody Bruchon <jody@jodybruchon.com>
+ * See jody_string.c for license information
  */
 
 #ifndef JODY_STRING_H
diff --git a/mount.winregfs.8 b/mount.winregfs.8
index 9fb8c62..8545eed 100644
--- a/mount.winregfs.8
+++ b/mount.winregfs.8
@@ -1,7 +1,7 @@
-.\" Copyright (c) 2014-2017 Jody Bruchon
-.\" Licensed under the GNU General Public License v2
+.\" Copyright (c) 2014-2021 Jody Bruchon
+.\" Released under The MIT License
 .\"
-.TH winregfs 8 "10 Mar 2017" "mount.winregfs"
+.TH winregfs 8 "10 Mar 2021" "mount.winregfs"
 .SH NAME
 winregfs \- Windows registry FUSE filesystem
 .SH SYNOPSIS
diff --git a/ntreg.c b/ntreg.c
index 0446f82..dd485d3 100644
--- a/ntreg.c
+++ b/ntreg.c
@@ -9,6 +9,8 @@
  *
  * NTREG - Window registry file reader / writer library
  * Copyright (c) 1997-2014 Petter Nordahl-Hagen.
+ * Heavily modified for winregfs (https://github.com/jbruchon/winregfs)
+ * by Jody Bruchon <jody@jodybruchon.com> (C) 2014-2021
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -19,7 +21,7 @@
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Lesser General Public License for more details.
- * See file LGPL.txt for the full license.
+ * See file LICENSE-LGPL for the full license.
  *
  * Modified for Windows Registry FUSE filesystem project "winregfs"
  * by Jody Bruchon <jody@jodybruchon.com> since 2014-04-16
@@ -49,8 +51,6 @@
 #define DLOG(...) printf(__VA_ARGS__)
 #endif
 
-static char *blank = '\0';
-
 static inline int de_escape(char *s, int wide);
 
 const char *val_types[REG_MAX+1] = {
@@ -353,7 +353,7 @@ int find_page_start(struct hive * const hdesc, const int vofs)
     h = (struct hbin_page *)(hdesc->buffer + r);
     if (h->id != 0x6E696268) return 0;
     if (h->ofs_next == 0) {
-      LOG("find_page_start: zero len or ofs_next found in page at 0x%x\n",r);
+      LOG("find_page_start: zero len or ofs_next found in page at 0x%x\n", r);
       return 0;
     }
     r += h->ofs_next;
@@ -380,7 +380,7 @@ int find_free_blk(struct hive * const hdesc, const int pofs, const int size)
   while ((vofs - pofs) < (p->ofs_next - HBIN_ENDFILL)) {
     seglen = get_int32(hdesc->buffer + vofs);
     if (seglen == 0) {
-      LOG("find_free_blk: Zero data block size; block at offset %0x\n",vofs);
+      LOG("find_free_blk: Zero data block size; block at offset %0x\n", vofs);
       if ((vofs - pofs) == (p->ofs_next - 4)) {
 	LOG("find_free_blk: at exact end of hbin, do not care.\n");
 	return 0;
@@ -557,7 +557,7 @@ int alloc_block(struct hive *hdesc, int ofs, int size)
   }
 
   if (blk) {  /* Got the space */
-    oldsz = get_int32(hdesc->buffer+blk);
+    oldsz = get_int32(hdesc->buffer + blk);
     trailsize = oldsz - size;
 
     if (trailsize == 4) {
@@ -600,9 +600,9 @@ int alloc_block(struct hive *hdesc, int ofs, int size)
 
     return blk;
   } else {
-    LOG("alloc_block: failed to alloc %d bytes, trying to expand hive.\n",size);
+    LOG("alloc_block: failed to alloc %d bytes, trying to expand hive.\n", size);
 
-    newbin = add_bin(hdesc,size);
+    newbin = add_bin(hdesc, size);
     if (newbin) return alloc_block(hdesc, newbin, size); /* Nasty... recall ourselves. */
     /* Fallthrough to fail if add_bin fails */
   }
@@ -619,7 +619,7 @@ int alloc_block(struct hive *hdesc, int ofs, int size)
 
 int free_block(struct hive * const hdesc, int blk)
 {
-  int pofs,vofs,seglen,next,nextsz,prevsz,size;
+  int pofs, vofs, seglen, next, nextsz, prevsz, size;
   int prev = 0;
   struct hbin_page *p;
 
@@ -630,9 +630,9 @@ int free_block(struct hive * const hdesc, int blk)
     return 0;
   }
 
-  size = get_int32(hdesc->buffer+blk);
+  size = get_int32(hdesc->buffer + blk);
   if (size >= 0) {
-    LOG("free_block: trying to free already free block: %x\n",blk);
+    LOG("free_block: trying to free already free block: %x\n", blk);
     return 0;
   }
   size = -size;
@@ -651,7 +651,7 @@ int free_block(struct hive * const hdesc, int blk)
   if (vofs != blk) {  /* Block is not at start of page? */
     while ((vofs - pofs) < (p->ofs_next - HBIN_ENDFILL)) {
 
-      seglen = get_int32(hdesc->buffer+vofs);
+      seglen = get_int32(hdesc->buffer + vofs);
       if (seglen == 0) {
 	LOG("free_block: Zero data block size (not registry or corrupt file?)\n");
 	return 0;
@@ -665,17 +665,18 @@ int free_block(struct hive * const hdesc, int blk)
     }
 
     if (vofs != blk) {
-      LOG("free_block: Ran off end of page. Error in chains? vofs %x, pofs %x, blk %x\n",vofs,pofs,blk);
+      LOG("free_block: Ran off end of page. Error in chains? vofs %x, pofs %x, blk %x\n", vofs, pofs, blk);
       return 0;
     }
-    prevsz = get_int32(hdesc->buffer+prev);
+    prevsz = get_int32(hdesc->buffer + prev);
   }
 
   /* We also need details on next block (unless at end of page) */
   next = blk + size;
 
   nextsz = 0;
-  if ((next - pofs) < (p->ofs_next - HBIN_ENDFILL)) nextsz = get_int32(hdesc->buffer+next);
+  if ((next - pofs) < (p->ofs_next - HBIN_ENDFILL))
+    nextsz = get_int32(hdesc->buffer + next);
 
   /* Now check if next block is free, if so merge it with the one to be freed */
   if (nextsz > 0) {
@@ -686,7 +687,7 @@ int free_block(struct hive * const hdesc, int blk)
   }
 
   /* Now free the block (possibly with ajusted size as above) */
-  *(int *)((hdesc->buffer)+blk) = (int)size;
+  *(int *)((hdesc->buffer) + blk) = (int)size;
   hdesc->usetot -= size;
   hdesc->unusetot -= size;  /* FIXME !?!? */
   hdesc->unuseblk--;
@@ -699,7 +700,7 @@ int free_block(struct hive * const hdesc, int blk)
     hdesc->unusetot += prevsz;
     prevsz += size;
     /* And swallow current.. */
-    *(int *)((hdesc->buffer)+prev) = (int)prevsz;
+    *(int *)((hdesc->buffer) + prev) = (int)prevsz;
     if (mark_pages_dirty(hdesc, prev, prev)) return -1;
     hdesc->useblk--;
     return prevsz;
@@ -778,6 +779,8 @@ int ex_next_n(const struct hive * const hdesc, int nkofs,
   if (hdesc->size < newnkofs) goto error_nk_eof;
   sptr->nkoffs = newnkofs;
   newnkkey = (struct nk_key *)(hdesc->buffer + newnkofs + 4);
+  if ((uintptr_t)newnkkey > ((uintptr_t)hdesc->buffer + hdesc->size) ||
+      (uintptr_t)newnkkey < (uintptr_t)hdesc->buffer) goto error_newnkkey_bounds;
   sptr->nk = newnkkey;
 
   DLOG("ex_next_n: sptr->nk 0x%p, newnkkey 0x%p, newnkofs 0x%d\n", (void *)sptr->nk, (void *)newnkkey, newnkofs);
@@ -785,7 +788,7 @@ int ex_next_n(const struct hive * const hdesc, int nkofs,
   if (newnkkey->id != 0x6b6e) goto error_not_nk2;
   else {
     if (newnkkey->len_name <= 0) {
-      LOG("ex_next_n: nk at 0x%0x has no name\n",newnkofs);
+      LOG("ex_next_n: nk at 0x%0x has no name\n", newnkofs);
     } else if (newnkkey->type & 0x20) {
       str_memcpy(sptr->name, newnkkey->keyname, newnkkey->len_name);
     } else {
@@ -815,6 +818,9 @@ error_li_eof:
 error_nk_eof:
   LOG("ex_next_n: error: new 'nk' pointer beyond end of file\n");
   return -1;
+error_newnkkey_bounds:
+  LOG("ex_next_n: error: new 'nk' key pointer out of bounds\n");
+  return -1;
 }
 
 /* "directory scan" for VALUES, return next name/pointer of a value on each call
@@ -893,7 +899,7 @@ error_nk_eof:
   LOG("ex_next_v: 'nk' offset beyond end of file\n");
   return -1;
 error_not_nk:
-  LOG("ex_next_v: not a 'nk' node at 0x%0x\n",nkofs);
+  LOG("ex_next_v: not a 'nk' node at 0x%0x\n", nkofs);
   return -1;
 error_vlistofs_size:
   LOG("ex_next_v: value list offset too large\n");
@@ -902,7 +908,7 @@ error_key_offset_size:
   LOG("ex_next_v: value key offset too large\n");
   return -1;
 error_not_vk:
-  LOG("ex_next_v: hit non-VK node during scan at offset 0x%0x\n",vkofs);
+  LOG("ex_next_v: hit non-VK node (0x%x) during scan at offset 0x%0x\n", vkofs, vkkey->id);
   return -1;
 }
 
@@ -945,7 +951,7 @@ int get_abs_path(struct hive *hdesc, int nkofs, char *path, int maxlen)
   }
   len_name = strlen(keyname);
   if ((int)(strlen(path) + len_name) >= maxlen - 6) {
-    snprintf(path,maxlen,"(...)%s",tmp);
+    snprintf(path, maxlen, "(...)%s", tmp);
     return strlen(path);   /* Stop trace when string exhausted */
   }
   *path = '\\';
@@ -1178,23 +1184,23 @@ void nk_ls(struct hive *hdesc, char *path, int vofs, int type)
   nkofs = trav_path(hdesc, vofs, path, 0);
 
   if(!nkofs) {
-    printf("nk_ls: Key <%s> not found\n",path);
+    printf("nk_ls: Key <%s> not found\n", path);
     return;
   }
   nkofs += 4;
 
   key = (struct nk_key *)(hdesc->buffer + nkofs);
 
-  if (key->id != 0x6b6e) printf("Error: Not a 'nk' node at offset %x!\n",nkofs);
+  if (key->id != 0x6b6e) printf("Error: Not a 'nk' node at offset %x!\n", nkofs);
 
-  printf("Node has %d subkeys and %d values",key->no_subkeys,key->no_values);
-  if (key->len_classnam) printf(", and class-data of %d bytes",key->len_classnam);
+  printf("Node has %d subkeys and %d values", key->no_subkeys, key->no_values);
+  if (key->len_classnam) printf(", and class-data of %d bytes", key->len_classnam);
   printf("\n");
 
   if (key->no_subkeys) {
     printf("  key name\n");
     while ((ex_next_n(hdesc, nkofs, &count, &countri, &ex) > 0)) {
-      printf("[%6x] %c <%s>\n", ex.nkoffs, (ex.nk->len_classnam)?'*':' ',ex.name);
+      printf("[%6x] %c <%s>\n", ex.nkoffs, (ex.nk->len_classnam)?'*':' ', ex.name);
       free(ex.name);
     }
   }
@@ -1205,7 +1211,7 @@ void nk_ls(struct hive *hdesc, char *path, int vofs, int type)
 	printf("%6d  %x %-16s   <%s>", vex.size, vex.type,
 	       (vex.type < REG_MAX ? val_types[vex.type] : "(unknown)"), vex.name);
 
-      if (vex.type == REG_DWORD) printf(" %*d [0x%x]",25-(int)strlen(vex.name),vex.val , vex.val);
+      if (vex.type == REG_DWORD) printf(" %*d [0x%x]", 25 - (int)strlen(vex.name), vex.val, vex.val);
       printf("\n");
       free(vex.name);
     }
@@ -1221,7 +1227,7 @@ int get_val_type(struct hive *hdesc, int vofs, char *path, int exact)
 
   LOAD_WD_LOGONLY();
 
-  vkofs = trav_path(hdesc, vofs,path,exact | TPF_VK_EXACT);
+  vkofs = trav_path(hdesc, vofs, path, exact | TPF_VK_EXACT);
   if (!vkofs) {
 	LOG("get_val_type: trav_path failed: %s offset %d\n", path, vofs);
 	return -1;
@@ -1241,7 +1247,7 @@ int set_val_type(struct hive *hdesc, int vofs, char *path, int exact, int type)
 
   LOAD_WD_LOGONLY();
 
-  vkofs = trav_path(hdesc, vofs,path,exact | TPF_VK_EXACT);
+  vkofs = trav_path(hdesc, vofs, path, exact | TPF_VK_EXACT);
   if (!vkofs) {
 	LOG("set_val_type: trav_path failed: %s offset %d\n", path, vofs);
 	return -1;
@@ -1261,13 +1267,13 @@ int get_val_len(struct hive *hdesc, int vofs, char *path, int exact)
 
   LOAD_WD_LOGONLY();
 
-  vkofs = trav_path(hdesc, vofs,path,exact | TPF_VK_EXACT);
+  vkofs = trav_path(hdesc, vofs, path, exact | TPF_VK_EXACT);
   if (!vkofs) {
 	LOG("get_val_len: trav_path failed: %s offset %d\n", path, vofs);
 	return -1;
   }
 
-  vkofs +=4;
+  vkofs += 4;
   if (vkofs > hdesc->size) {
 	  LOG("get_val_len: error: 'vk' offset too large: %x\n", vkofs);
 	  return -1;
@@ -1275,7 +1281,7 @@ int get_val_len(struct hive *hdesc, int vofs, char *path, int exact)
 
   vkkey = (struct vk_key *)(hdesc->buffer + vkofs);
   if (vkkey->id != 0x6b76) {
-    LOG("get_val_len: Cell ID is not 'vk': offset 0x%x, subpath \\%s\n", vkofs, path);
+    LOG("get_val_len: cell ID is not 'vk': offset 0x%x, subpath \\%s\n", vkofs, path);
     return -1;
   }
 
@@ -1300,7 +1306,7 @@ void *get_val_data(struct hive *hdesc, int vofs, char *path, int val_type, int e
 
   LOAD_WD_LOGONLY();
 
-  vkofs = trav_path(hdesc,vofs,path,exact | TPF_VK);
+  vkofs = trav_path(hdesc, vofs, path, exact | TPF_VK);
   if (!vkofs) {
     LOG("get_val_data: not found: %s\n", path);
     return NULL;
@@ -1323,7 +1329,7 @@ void *get_val_data(struct hive *hdesc, int vofs, char *path, int val_type, int e
   }
 
   if (val_type && vkkey->val_type && (vkkey->val_type) != val_type) {
-    LOG("get_val_data: not of correct type: %s\n",path);
+    LOG("get_val_data: not of correct type: %s\n", path);
     return NULL;
   }
 
@@ -1400,8 +1406,8 @@ struct keyval *get_val2buf(struct hive *hdesc, struct keyval *kv,
       /* Copy this part, up to size of block or rest lenght in last block */
       copylen = (blocksize > restlen) ? restlen : blocksize;
 
-      DLOG("get_val2buf: Datablock %d offset %x, size %x (%d)\n",i,blockofs,blocksize,blocksize);
-      DLOG("             : Point = %x, restlen = %x, copylen = %x\n",point,restlen,copylen);
+      DLOG("get_val2buf: Datablock %d offset %x, size %x (%d)\n", i, blockofs, blocksize, blocksize);
+      DLOG("             : Point = %x, restlen = %x, copylen = %x\n", point, restlen, copylen);
 
       addr = (void *)((int *)kr->data + point);
       memcpy(addr, hdesc->buffer + blockofs + 4, copylen);
@@ -1438,7 +1444,7 @@ int fill_block(struct hive *hdesc, int ofs, void *data, int size)
   return 0;
 
 error_too_small:
-  LOG("fill_block: too small for data: ofs %x, size %x, blksize %x\n",ofs,size,blksize);
+  LOG("fill_block: too small for data: ofs %x, size %x, blksize %x\n", ofs, size, blksize);
   return -1;
 error_dirty:
   LOG("fill_block: mark_pages_dirty returned an error\n");
@@ -1455,7 +1461,7 @@ int free_val_data(struct hive *hdesc, int vkofs)
 {
   struct vk_key *vkkey;
   struct db_key *db;
-  int len,i,blockofs,parts,list;
+  int len, i, blockofs, parts, list;
 #if LOG_IS_USED
   int blocksize;
 #endif
@@ -1483,7 +1489,7 @@ int free_val_data(struct hive *hdesc, int vkofs)
 	blockofs = get_int32(hdesc->buffer + list + (i << 2)) + 0x1000;
 #if LOG_IS_USED
 	blocksize = -get_int32(hdesc->buffer + blockofs);
-	LOG("free_val_data: Freeing long block %d: offset %x, size %x (%d)\n",i, blockofs, blocksize, blocksize);
+	LOG("free_val_data: Freeing long block %d: offset %x, size %x (%d)\n", i, blockofs, blocksize, blocksize);
 #endif
 	free_block(hdesc, blockofs);
       }
@@ -1512,17 +1518,17 @@ int free_val_data(struct hive *hdesc, int vkofs)
  * Returns: 0 - error, >0 pointer to actual dataspace
  */
 
-int alloc_val_data(struct hive *hdesc, int vofs, char *path, int size,int exact)
+int alloc_val_data(struct hive *hdesc, int vofs, char *path, int size, int exact)
 {
   struct vk_key *vkkey;
   struct db_key *db;
-  int vkofs,dbofs,listofs,blockofs,blocksize,parts;
+  int vkofs, dbofs, listofs, blockofs, blocksize, parts;
   int datablk, i, j;
   int *ptr;
 
   LOAD_WD_LOGONLY();
 
-  vkofs = trav_path(hdesc,vofs,path,exact);
+  vkofs = trav_path(hdesc, vofs, path, exact);
   if (!vkofs) goto error_trav_path;
 
   vkofs +=4;
@@ -1550,7 +1556,7 @@ int alloc_val_data(struct hive *hdesc, int vofs, char *path, int size,int exact)
       for (i = 0; i < parts; i++) {
 	blocksize = VAL_DIRECT_LIMIT;      /* Windows seem to alway allocate the whole block */
 	blockofs = alloc_block(hdesc, vkofs, blocksize);
-	LOG("alloc_val_data: block %d, blockofs %x\n",i,blockofs);
+	LOG("alloc_val_data: block %d, blockofs %x\n", i, blockofs);
 	j = listofs + 4 + (i << 2);
 	ptr = (int *)(hdesc->buffer + j);
 	*ptr = blockofs - 0x1000;
@@ -1613,6 +1619,7 @@ struct vk_key *add_value(struct hive *hdesc, int nkofs, char *name, int type)
   LOAD_WD_LOGONLY();
 
   if (!name || !*name) goto error_null_name;
+  DLOG("add_value: nkofs %d, name '%s', type 0x%x\n", nkofs, name, type);
   nk = (struct nk_key *)(hdesc->buffer + nkofs);
   if (nk->id != 0x6b6e) goto error_not_nk;
 
@@ -1620,7 +1627,7 @@ struct vk_key *add_value(struct hive *hdesc, int nkofs, char *name, int type)
     if(!del_value(hdesc, nkofs, name)) goto error_del_value;
   }
 
-  if (!streq(name, "@")) name = blank;
+  if (!streq(name, "@")) *name = '\0';
 
   if (nk->no_values) oldvlist = nk->ofs_vallist;
 
@@ -1665,7 +1672,7 @@ struct vk_key *add_value(struct hive *hdesc, int nkofs, char *name, int type)
   /* Finally update the key and free the old valuelist */
   nk->no_values++;
   nk->ofs_vallist = newvlist - 0x1000;
-  if (oldvlist) free_block(hdesc,oldvlist + 0x1000);
+  if (oldvlist) free_block(hdesc, oldvlist + 0x1000);
   if (mark_pages_dirty(hdesc, newvkofs + 4, newvkofs + 4)) goto error_dirty;
 
   return newvkkey;
@@ -1739,7 +1746,7 @@ int del_value(struct hive *hdesc, int nkofs, char *name)
 	  LOG("del_value: Null or empty name given\n");
 	  return 1;
   }
-  if (!streq(name, "@")) name = blank;
+  if (!streq(name, "@")) *name = '\0';
   nk = (struct nk_key *)(hdesc->buffer + nkofs);
   if (nk->id != 0x6b6e) {
     LOG("del_value: Key pointer not to 'nk' node: %s\n", name);
@@ -1766,10 +1773,10 @@ int del_value(struct hive *hdesc, int nkofs, char *name)
   del_vk(hdesc, vkofs);
 
   /* Copy out old index list */
-  CREATE(tmplist,int32_t,nk->no_values);
+  CREATE(tmplist, int32_t, nk->no_values);
   memcpy(tmplist, vlistkey, nk->no_values * sizeof(int32_t));
 
-  free_block(hdesc,vlistofs-4);  /* Get rid of old list */
+  free_block(hdesc, vlistofs - 4);  /* Get rid of old list */
 
   nk->no_values--;
 
@@ -1865,7 +1872,7 @@ struct nk_key *add_key(struct hive *hdesc, int nkofs, char *name)
 	newli->id = oldli->id;
 
 	/* Now copy old, checking where to insert (alphabetically) */
-	for (o = 0, n = 0; o < oldli->no_keys; o++,n++) {
+	for (o = 0, n = 0; o < oldli->no_keys; o++, n++) {
 	  onkofs = oldli->hash[o].ofs_nk;
 	  onk = (struct nk_key *)(onkofs + hdesc->buffer + 0x1004);
 	  if (slot == -1) {
@@ -1891,7 +1898,7 @@ struct nk_key *add_key(struct hive *hdesc, int nkofs, char *name)
 	newlf->id = oldlf->id;
 
 	/* Now copy old, checking where to insert (alphabetically) */
-	for (o = 0, n = 0; o < oldlf->no_keys; o++,n++) {
+	for (o = 0, n = 0; o < oldlf->no_keys; o++, n++) {
 	  onkofs = oldlf->h.hash[o].ofs_nk;
 	  onk = (struct nk_key *)(onkofs + hdesc->buffer + 0x1004);
 	  if (slot == -1) {
@@ -1990,8 +1997,8 @@ struct nk_key *add_key(struct hive *hdesc, int nkofs, char *name)
     key->ofs_lf = (newlf ? newlfofs : newliofs) - 0x1000;
   }
 
-  if (newlf && oldlfofs) free_block(hdesc,oldlfofs + 0x1000);
-  if (newli && oldliofs) free_block(hdesc,oldliofs + 0x1000);
+  if (newlf && oldlfofs) free_block(hdesc, oldlfofs + 0x1000);
+  if (newli && oldliofs) free_block(hdesc, oldliofs + 0x1000);
 
   free(newlf);
   free(newli);
@@ -2001,7 +2008,7 @@ error_not_nk:
   LOG("add_key: current pointer not 'nk'\n");
   return NULL;
 error_bad_index_type:
-  LOG("add_key: index type not supported: 0x%04x\n",oldlf->id);
+  LOG("add_key: index type not supported: 0x%04x\n", oldlf->id);
   return NULL;
 error_key_exists:
   free(newlf);
@@ -2014,12 +2021,12 @@ error_newnkofs:
   return NULL;
 error_newliofs:
   free(newli);
-  free_block(hdesc,newnkofs);
+  free_block(hdesc, newnkofs);
   LOG("add_key: can't alloc space for index table for %s\n", name);
   return NULL;
 error_alloc_index:
   free(newlf);
-  free_block(hdesc,newnkofs);
+  free_block(hdesc, newnkofs);
   LOG("add_key: can't alloc space for index table for %s\n", name);
   return NULL;
 error_fill_block:
@@ -2097,7 +2104,7 @@ int del_key(struct hive *hdesc, int nkofs, char *name)
       newli->id = oldli->id;
 
       /* Now copy old, checking where to delete */
-      for (o = 0, n = 0; o < oldli->no_keys; o++,n++) {
+      for (o = 0, n = 0; o < oldli->no_keys; o++, n++) {
 	onkofs = oldli->hash[o].ofs_nk;
 	onk = (struct nk_key *)(onkofs + hdesc->buffer + 0x1004);
 	if (slot == -1 && onk->len_name == namlen && !strneq(name, onk->keyname, (onk->len_name > namlen) ? onk->len_name : namlen)) {
@@ -2118,7 +2125,7 @@ int del_key(struct hive *hdesc, int nkofs, char *name)
       newlf->id = oldlf->id;
 
       /* Now copy old, checking where to delete */
-      for (o = 0, n = 0; o < oldlf->no_keys; o++,n++) {
+      for (o = 0, n = 0; o < oldlf->no_keys; o++, n++) {
 
 	onkofs = oldlf->h.hash[o].ofs_nk;
 	onk = (struct nk_key *)(onkofs + hdesc->buffer + 0x1004);
@@ -2205,7 +2212,7 @@ int del_key(struct hive *hdesc, int nkofs, char *name)
 	ALLOC(newri, 8 + 4*ri->no_lis - 4, 1);
 	newri->no_lis = ri->no_lis - 1;
 	newri->id = ri->id;
-	for (o = 0, n = 0; o < ri->no_lis; o++,n++) {
+	for (o = 0, n = 0; o < ri->no_lis; o++, n++) {
 	  if (n == rislot) o++;
 	  newri->hash[n].ofs_li = ri->hash[o].ofs_li;
 	}
@@ -2248,7 +2255,7 @@ error_subkey_not_found:
   free(newli);
   return 1;
 error_not_empty:
-  LOG("del_key: subkey %s has subkeys or values. Not deleted.\n",name);
+  LOG("del_key: subkey %s has subkeys or values. Not deleted.\n", name);
   free(newlf);
   free(newli);
   return 1;
@@ -2305,7 +2312,7 @@ int put_buf2val(struct hive *hdesc, struct keyval *kv,
 
   keydataptr = get_val_data(hdesc, vofs, path, type, exact);
   if (!keydataptr) {
-      LOG("put_buf2val: get_val_data failed: %s\n",path);
+      LOG("put_buf2val: get_val_data failed: %s\n", path);
       return 0;
   }
 
@@ -2362,7 +2369,7 @@ error_null_kv:
   struct keyval *kr;
   int r;
 
-  ALLOC(kr,1,16);
+  ALLOC(kr, 1, 16);
 
   kr->len = 4;
   *(kr->data) = dword;
@@ -2552,7 +2559,7 @@ error_flush:
 struct hive *open_hive(char *filename, int mode)
 {
   struct hive *hdesc;
-  int r,vofs;
+  int r, vofs;
   char fmode[] = "r+";
   struct stat sbuf;
   uint32_t pofs;
@@ -2587,12 +2594,12 @@ struct hive *open_hive(char *filename, int mode)
 
   hdesc->fp = fopen(hdesc->filename, fmode);
   if (hdesc->fp == NULL) {
-    LOG("open_hive: failed: %s: %s; trying read-only\n",strerror(errno),hdesc->filename);
+    LOG("open_hive: failed: %s: %s; trying read-only\n", strerror(errno), hdesc->filename);
     fmode[1] = '\0';
     mode |= HMODE_RO;
     hdesc->fp = fopen(hdesc->filename, fmode);
     if (hdesc->fp == NULL) {
-      LOG("open_hive: read-only failed: %s: %s\n",strerror(errno),hdesc->filename);
+      LOG("open_hive: read-only failed: %s: %s\n", strerror(errno), hdesc->filename);
       close_hive(hdesc);
       return NULL;
     }
@@ -2621,7 +2628,7 @@ struct hive *open_hive(char *filename, int mode)
 
    hdr = (struct regf_header *)hdesc->buffer;
    if (hdr->id != 0x66676572) {
-     LOG("open_hive: not a registry file: %s\n",filename);
+     LOG("open_hive: not a registry file: %s\n", filename);
      return hdesc;
    }
 
@@ -2633,7 +2640,7 @@ struct hive *open_hive(char *filename, int mode)
 
    hdesc->rootofs = hdr->ofs_rootkey + 0x1000;
 
-   /* Cache the roots subkey index type (li,lf,lh) so we can use the correct
+   /* Cache the roots subkey index type (li, lf, lh) so we can use the correct
     * one when creating the first subkey in a key */
 
    nk = (struct nk_key *)(hdesc->buffer + hdesc->rootofs + 4);
diff --git a/ntreg.h b/ntreg.h
index db17c30..6a84579 100644
--- a/ntreg.h
+++ b/ntreg.h
@@ -7,6 +7,8 @@
  *
  * NTREG - Window registry file reader / writer library
  * Copyright (c) 1997-2013 Petter Nordahl-Hagen.
+ * Heavily modified for winregfs (https://github.com/jbruchon/winregfs)
+ * by Jody Bruchon <jody@jodybruchon.com> (C) 2014-2021
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -17,7 +19,7 @@
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Lesser General Public License for more details.
- * See file LGPL.txt for the full license.
+ * See file LICENSE-LGPL for the full license.
  * 
  * Modified for Windows Registry FUSE filesystem project "winregfs"
  * by Jody Bruchon <jody@jodybruchon.com> since 2014-04-16
diff --git a/version.h b/version.h
index b3e6cc0..8237c96 100644
--- a/version.h
+++ b/version.h
@@ -7,6 +7,6 @@
 
 #ifndef WINREGFS_VERSION_H
 #define WINREGFS_VERSION_H
-#define VER "0.7"
-#define VERDATE "2017-03-10"
+#define VER "0.8"
+#define VERDATE "2021-09.15"
 #endif	/* WINREGFS_VERSION_H */
diff --git a/winregfs.c b/winregfs.c
index a72374f..f2eb64a 100644
--- a/winregfs.c
+++ b/winregfs.c
@@ -1,15 +1,14 @@
 /*
  * Windows Registry FUSE Filesystem
  *
- * Copyright (C) 2014-2017 Jody Bruchon <jody@jodybruchon.com>
+ * Copyright (C) 2014-2021 Jody Bruchon <jody@jodybruchon.com>
+ * Released under The MIT License
  *
  * Mounts a Windows registry hive file as a filesystem using FUSE
  * Registry keys become directories and values become files
  * Value files have an extension based on the value type
  * (blah.sz = REG_SZ string; blah.dw = REG_DWORD 32-bit number)
  *
- * Licensed under GNU GPL v2. See LICENSE and README for details.
- *
  */
 
 #include <stdio.h>
@@ -33,7 +32,7 @@
 #define PATH_IS_ROOT(a) (a[0] == '/' && a[1] == '\0')
 
 /* Use Jody's block hash algorithm for the cache */
-#define cache_hash(a) jody_block_hash((const hash_t *)a, 0, strlen(a))
+#define cache_hash(a) jody_block_hash((const jodyhash_t *)a, 0, strlen(a))
 
 /* Value type file extensions */
 const char *ext[REG_MAX + 1] = {
@@ -132,6 +131,14 @@ static int process_ext(char * const node)
 	if (str_ext == NULL) return -1;
 	*str_ext = '\0';
 	str_ext++;
+
+	/* Handle non-standard types with 0x prefix */
+	if (*str_ext == '0' && *(str_ext + 1) == 'x') {
+		i = strtol(str_ext, NULL, 0);
+		return i;
+	}
+
+	/* Handle standard types */
 	for (; i < REG_MAX; i++) {
 		if (!strcaseeq(str_ext, ext[i])) return i;
 	}
@@ -140,18 +147,24 @@ static int process_ext(char * const node)
 
 
 /* Add the type extension to the registry value name */
-static int add_val_ext(char * const restrict filename,
+static int add_val_ext(char * restrict filename,
 		const struct vex_data * const restrict vex)
 {
 	LOAD_WD_LOGONLY();
 
-	if (vex->type > REG_MAX) {
-		LOG("add_val_ext: error: value type out of range: %s\n", filename);
-		return 1;
-	}
-	xstrcpy(filename, vex->name);
+	if (filename == NULL || vex == NULL || vex->name == NULL) return -1;
+	DLOG("add_val_ext: %s.", filename);
+	if (*(vex->name) == '\0') xstrcpy(filename, "@");
+	else xstrcpy(filename, vex->name);
 	strncat(filename, ".", ABSPATHLEN);
-	strncat(filename, ext[vex->type], ABSPATHLEN);
+	if (vex->type <= REG_MAX) {
+		strncat(filename, ext[vex->type], ABSPATHLEN);
+		DLOG("%s\n", ext[vex->type]);
+	} else {
+		while (*filename != '\0') filename++;
+		snprintf(filename, 11, "0x%x", vex->type);
+		DLOG("0x%x\n", vex->type);
+	}
 	return 0;
 }
 
@@ -295,7 +308,7 @@ void invalidate_nk_cache(void)
 
 	DLOG("winregfs cache invalidated\n");
 	LOCK();
-	for (i=0; i < NKOFS_CACHE_ITEMS; i++) wd->nk_hash[i] = '\0';
+	for (i = 0; i < NKOFS_CACHE_ITEMS; i++) wd->nk_hash[i] = '\0';
 	UNLOCK();
 	return;
 }
@@ -313,16 +326,15 @@ static int get_path_nkofs(struct winregfs_data * const restrict wd,
 
 #if ENABLE_NKOFS_CACHE
 	int i;
-	hash_t hash;
+	jodyhash_t hash;
 
 	/* Check the cached path to avoid extra traversals */
 	hash = cache_hash(keypath);
 
-	LOCK();
-
 	/* Work backwards in the hash cache ring until we come back
 	 * where we started or encounter a zeroed (non-existent) hash */
 	i = wd->nk_cache_pos;
+	LOCK();
 	while (1) {
 		if (!wd->nk_hash[i]) break;  /* 0 = end of recorded hashes */
 		if (wd->nk_hash[i] == hash) {
@@ -338,6 +350,7 @@ static int get_path_nkofs(struct winregfs_data * const restrict wd,
 					nkofs = trav_path(wd->hive, 0, keypath, TPF_NK_EXACT);
 					if (!nkofs) {
 						LOG("get_path_nkofs: trav_path failed: %s\n", keypath);
+						UNLOCK();
 						return 0;
 					}
 					nkofs += 4;
@@ -348,7 +361,10 @@ static int get_path_nkofs(struct winregfs_data * const restrict wd,
 				}
 			} else { nk_cache_stats(wd, HASH_FAIL); }
 		} else { nk_cache_stats(wd, HASH_MISS); }
-		if (update_cache) return 0;
+		if (update_cache) {
+			UNLOCK();
+			return 0;
+		}
 		/* If we've hit item 0, return the cache ring position to the end of the ring */
 		if (!i) i = NKOFS_CACHE_ITEMS;
 		i--;
@@ -453,8 +469,9 @@ static int winregfs_access(const char * const restrict path, int mode)
 	count = 0;
 	if (key->no_values) {
 		while (ex_next_v(wd->hive, nkofs, &count, &vex) > 0) {
-			if (strlen(vex.name) == 0) xstrcpy(filename, "@.sz");
-			else add_val_ext(filename, &vex);
+			if (strlen(vex.name) == 0) xstrcpy(filename, "@");
+			else *filename = '\0';
+			add_val_ext(filename, &vex);
 			if (!strcaseeq(node, filename)) {
 				if (!(mode & X_OK)) {
 					DLOG("access: OK: ex_v: nkofs %x vkofs %x size %d c %d\n",
@@ -562,8 +579,9 @@ static int winregfs_getattr(const char * const restrict path,
 	DLOG("getattr: key->no_values = %d\n", key->no_values);
 	if (key->no_values) {
 		while (ex_next_v(wd->hive, nkofs, &count, &vex) > 0) {
-			if (strlen(vex.name) == 0) xstrcpy(filename, "@.sz");
-			else add_val_ext(filename, &vex);
+			if (strlen(vex.name) == 0) xstrcpy(filename, "@");
+			else *filename = '\0';
+			add_val_ext(filename, &vex);
 
 			/* Wildcard accesses with no extension */
 			if (!strrchr(node, '.')) {
@@ -670,18 +688,14 @@ static int winregfs_readdir(const char * const restrict path,
 	DLOG("readdir: key->no_values = %d\n", key->no_values);
 	if (key->no_values) {
 		while (ex_next_v(wd->hive, nkofs, &count, &vex) > 0) {
-			if (strlen(vex.name) == 0) {
-				xstrcpy(filename, "@.sz");
+			DLOG("readdir: next_v: %x %s\n", vex.type, vex.name);
+			if (strlen(vex.name) == 0) xstrcpy(filename, "@");
+			if (!add_val_ext(filename, &vex)) {
+				escape_fwdslash(filename);
 				DLOG("readdir: v_filler: %s\n", filename);
 				filler(buf, filename, NULL, 0);
 			} else {
-				if (!add_val_ext(filename, &vex)) {
-					escape_fwdslash(filename);
-					DLOG("readdir: v_filler: %s\n", filename);
-					filler(buf, filename, NULL, 0);
-				} else {
-					LOG("readdir: error reading %s/%s\n", path, filename);
-				}
+				LOG("readdir: error reading %s/%s\n", path, filename);
 			}
 		}
 	}
@@ -745,8 +759,9 @@ static int winregfs_open(const char * const restrict path,
 	count = 0;
 	if (key->no_values) {
 		while (ex_next_v(wd->hive, nkofs, &count, &vex) > 0) {
-			if (strlen(vex.name) == 0) xstrcpy(filename, "@.sz");
-			else add_val_ext(filename, &vex);
+			if (strlen(vex.name) == 0) xstrcpy(filename, "@");
+			else *filename = '\0';
+			add_val_ext(filename, &vex);
 
 			/* Wildcard accesses with no extension */
 			if (!strrchr(node, '.')) {
@@ -968,6 +983,7 @@ static int winregfs_write(const char * const restrict path,
 		if (!i) goto error_write;
 		break;
 
+	default: /* All non-standard types are treated as REG_BINARY */
 	case REG_BINARY:
 		if (offset != 0 && kv->len > newsize) newsize = kv->len;
 		if (offset > kv->len) goto error_long_write;
@@ -1041,9 +1057,6 @@ static int winregfs_write(const char * const restrict path,
 
 		if (!i) goto error_write;
 		break;
-	default:
-		goto error_type_not_sup;
-		break;
 	}
 
 	if (write_hive(wd->hive)) {
@@ -1093,10 +1106,6 @@ error_short_write:
 	LOG("write: short write: %s (%d/%d)\n", path, i, (int)newkv->len);
 	free(newkv->data); free(newkv); free(kv->data); free(kv);
 	return -ENOSPC;
-error_type_not_sup:
-	LOG("write: type %d not supported: %s\n", type, path);
-	free(kv->data); free(kv);
-	return -EINVAL;
 }
 
 
@@ -1135,6 +1144,7 @@ static int winregfs_mknod(const char * const restrict path,
 	sanitize_path(path, keypath, node);
 
 	ktype = process_ext(node);
+	DLOG("mknod: ktype: %x\n", ktype);
 	if (ktype < 0) {
 		LOG("mknod: bad extension: %s\n", path);
 		return -EPERM;
@@ -1453,6 +1463,8 @@ int main(int argc, char *argv[])
 #if ENABLE_LOGGING
 	LOG("winregfs %s (%s) started for hive %s\n", VER, VERDATE, file);
 #endif
+	fprintf(stderr, "WARNING: ALWAYS back up hives before using winregfs 0.x on them!\n");
+	fprintf(stderr, "This program has known bugs and IS NOT production-safe.\n");
 	i = fuse_main(argc, argv, &winregfs_oper, wd);
 	close_hive(wd->hive);
 #if ENABLE_LOGGING
diff --git a/winregfs.h b/winregfs.h
index 9fdbd62..852a1db 100644
--- a/winregfs.h
+++ b/winregfs.h
@@ -1,10 +1,8 @@
 /*
  * Windows Registry FUSE Filesystem
  *
- * Copyright (C) 2014-2017 by Jody Bruchon <jody@jodybruchon.com>
- *
- * Licensed under GNU GPL v2. See LICENSE and README for details.
- *
+ * Copyright (C) 2014-2021 by Jody Bruchon <jody@jodybruchon.com>
+ * See winregfs.c for license information
  */
 
 #ifndef WINREGFS_H
@@ -72,7 +70,7 @@ struct winregfs_data {
 	char *nk_last_path[NKOFS_CACHE_ITEMS];
 	int nk_last_nkofs[NKOFS_CACHE_ITEMS];
 	struct nk_key *nk_last_key[NKOFS_CACHE_ITEMS];
-	hash_t nk_hash[NKOFS_CACHE_ITEMS];
+	jodyhash_t nk_hash[NKOFS_CACHE_ITEMS];
 # if ENABLE_NKOFS_CACHE_STATS
 	int delay;  /* Cache log throttling interval */
 	int nk_cache_miss;

Debdiff

File lists identical (after any substitutions)

No differences were encountered in the control files

More details

Full run details