Richard W.M. Jones wrote:
On Sat, Sep 03, 2011 at 04:45:28PM +0200, Gillen Daniel wrote:
> I'm just posting this here in case someone is interested in building
> hivex on Windows (mingw32). The attached patch allows building the
> lib but not the tools (hivexsh etc..) as there are some more
> problems to solve.
>
> In short terms, this patch replaces file i/o functions and mmap(),
> munmap() with their win32api pendants.
NACK ... This patch is too invasive.
We are already linking with gnulib, which ought to provide a degree of
platform independence. By adding the right gnulib modules (see the
file 'bootstrap' in the toplevel directory) it should be possible to
make hivex compile directly on Windows, while requiring fewer source
code changes.
gnulib can almost certainly do all the file things. I don't see a
gnulib module for mmap, which could be a problem, but a less invasive
change should still be possible for that.
Rich.
> diff --git a/lib/hivex.c b/lib/hivex.c
> index 4b9fcf0..986bdeb 100644
> --- a/lib/hivex.c
> +++ b/lib/hivex.c
> @@ -30,13 +30,19 @@
> #include <unistd.h>
> #include <errno.h>
> #include <iconv.h>
> -#include <sys/mman.h>
> +#ifndef __MINGW32__
> + #include <sys/mman.h>
> +#else
> + #include <windows.h>
> +#endif
> #include <sys/stat.h>
> #include <assert.h>
>
> #include "c-ctype.h"
> -#include "full-read.h"
> -#include "full-write.h"
> +#ifndef __MINGW32__
> + #include "full-read.h"
> + #include "full-write.h"
> +#endif
>
> #define STREQ(a,b) (strcmp((a),(b)) == 0)
> #define STRCASEEQ(a,b) (strcasecmp((a),(b)) == 0)
> @@ -62,7 +68,13 @@ static size_t utf16_string_len_in_bytes_max (const char *str,
size_t len);
>
> struct hive_h {
> char *filename;
> +#ifndef __MINGW32__
> int fd;
> +#else
> + HANDLE fd;
> + HANDLE winmap;
> +#endif
> +
> size_t size;
> int msglvl;
> int writable;
> @@ -294,28 +306,48 @@ hivex_open (const char *filename, int flags)
> if (h->filename == NULL)
> goto error;
>
> -#ifdef O_CLOEXEC
> - h->fd = open (filename, O_RDONLY | O_CLOEXEC);
> -#else
> - h->fd = open (filename, O_RDONLY);
> -#endif
> - if (h->fd == -1)
> - goto error;
> -#ifndef O_CLOEXEC
> - fcntl (h->fd, F_SETFD, FD_CLOEXEC);
> -#endif
> -
> +#ifndef __MINGW32__
> + #ifdef O_CLOEXEC
> + h->fd = open (filename, O_RDONLY | O_CLOEXEC);
> + #else
> + h->fd = open (filename, O_RDONLY);
> + #endif
> + if (h->fd == -1)
> + goto error;
> + #ifndef O_CLOEXEC
> + fcntl (h->fd, F_SETFD, FD_CLOEXEC);
> + #endif
> +
> struct stat statbuf;
> if (fstat (h->fd, &statbuf) == -1)
> goto error;
>
> h->size = statbuf.st_size;
> +#else
> + h->fd = CreateFile (filename, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
> + if (h->fd == INVALID_HANDLE_VALUE)
> + goto error;
> +
> + // XXX: There might be a problem if hive > 2^32 bytes
> + h->size = GetFileSize (h->fd, NULL);
> +#endif
>
> if (!h->writable) {
> +#ifndef __MINGW32__
> h->addr = mmap (NULL, h->size, PROT_READ, MAP_SHARED, h->fd, 0);
> if (h->addr == MAP_FAILED)
> goto error;
> -
> +#else
> + // Mingw does not support mmap, we have to use native API
> + // Create file mapping
> + h->winmap = CreateFileMapping (h->fd, NULL, PAGE_READONLY, 0, 0, NULL);
> + if (h->winmap == NULL)
> + goto error;
> + // Create map view
> + h->addr = MapViewOfFile (h->winmap, FILE_MAP_READ, 0, 0, h->size);
> + if (h->addr == NULL)
> + goto error;
> +#endif
> if (h->msglvl >= 2)
> fprintf (stderr, "hivex_open: mapped file at %p\n", h->addr);
> } else {
> @@ -323,15 +355,29 @@ hivex_open (const char *filename, int flags)
> if (h->addr == NULL)
> goto error;
>
> +#ifndef __MINGW32__
> if (full_read (h->fd, h->addr, h->size) < h->size)
> goto error;
> +#else
> + DWORD bytes_read=0;
> + if (!ReadFile (h->fd, h->addr, h->size, &bytes_read, NULL))
> + goto error;
> + if (bytes_read != h->size)
> + goto error;
> +#endif
>
> /* We don't need the file descriptor along this path, since we
> * have read all the data.
> */
> +#ifndef __MINGW32__
> if (close (h->fd) == -1)
> goto error;
> h->fd = -1;
> +#else
> + if (!CloseHandle (h->fd))
> + goto error;
> + h->fd = INVALID_HANDLE_VALUE;
> +#endif
> }
>
> /* Check header. */
> @@ -532,14 +578,28 @@ hivex_open (const char *filename, int flags)
> int err = errno;
> if (h) {
> free (h->bitmap);
> +#ifndef __MINGW32__
> if (h->addr && h->size && h->addr != MAP_FAILED) {
> - if (!h->writable)
> +#else
> + if (h->addr && h->size && h->addr != NULL) {
> +#endif
> + if (!h->writable) {
> +#ifndef __MINGW32__
> munmap (h->addr, h->size);
> - else
> +#else
> + UnmapViewOfFile (h->addr);
> + CloseHandle (h->winmap);
> +#endif
> + } else
> free (h->addr);
> }
> +#ifndef __MINGW32__
> if (h->fd >= 0)
> close (h->fd);
> +#else
> + if (h->fd != INVALID_HANDLE_VALUE)
> + CloseHandle (h->fd);
> +#endif
> free (h->filename);
> free (h);
> }
> @@ -556,12 +616,22 @@ hivex_close (hive_h *h)
> fprintf (stderr, "hivex_close\n");
>
> free (h->bitmap);
> - if (!h->writable)
> + if (!h->writable) {
> +#ifndef __MINGW32__
> munmap (h->addr, h->size);
> - else
> +#else
> + UnmapViewOfFile (h->addr);
> + CloseHandle (h->winmap);
> +#endif
> + } else
> free (h->addr);
> +#ifndef __MINGW32__
> if (h->fd >= 0)
> r = close (h->fd);
> +#else
> + if (h->fd != INVALID_HANDLE_VALUE)
> + r = CloseHandle (h->fd) ? 0 : 1;
> +#endif
> else
> r = 0;
> free (h->filename);
> @@ -2100,9 +2170,15 @@ hivex_commit (hive_h *h, const char *filename, int flags)
> }
>
> filename = filename ? : h->filename;
> +#ifndef __MINGW32__
> int fd = open (filename, O_WRONLY|O_CREAT|O_TRUNC|O_NOCTTY, 0666);
> if (fd == -1)
> return -1;
> +#else
> + HANDLE fd = CreateFile (filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
> + if (fd == INVALID_HANDLE_VALUE)
> + return -1;
> +#endif
>
> /* Update the header fields. */
> uint32_t sequence = le32toh (h->hdr->sequence1);
> @@ -2119,6 +2195,7 @@ hivex_commit (hive_h *h, const char *filename, int flags)
> if (h->msglvl >= 2)
> fprintf (stderr, "hivex_commit: new header checksum: 0x%x\n", sum);
>
> +#ifndef __MINGW32__
> if (full_write (fd, h->addr, h->size) != h->size) {
> int err = errno;
> close (fd);
> @@ -2128,6 +2205,20 @@ hivex_commit (hive_h *h, const char *filename, int flags)
>
> if (close (fd) == -1)
> return -1;
> +#else
> + DWORD bytes_written;
> + if (!WriteFile (fd, h->addr, h->size, &bytes_written, NULL)) {
> + CloseHandle (fd);
> + return -1;
> + }
> + if (bytes_written != h->size) {
> + CloseHandle (fd);
> + return -1;
> + }
> +
> + if (!CloseHandle (fd))
> + return -1;
> +#endif
>
> return 0;
> }
Thanks for the patch, Gillen, but as Rich says, parts look unnecessary.
In particular, why do you ifdef the uses of full_read and full_write?
I've Cc'd bug-gnulib.