Many files:
pass4.c (e2fsck_pass4): If an inode is set in the inode_imagic_map
bitmap, don't check to see if it is disconnected from the inode tree
(because it almost certainly will be). Free inode_imagic_map at the
end of pass 4.
pass2.c (check_dir_block, check_filetype): If the FILETYPE feature is
set, check the directory entry's filetype information field, and
fix/set it if necessary. (e2fsck_pass2): Free the inode_reg_map
bitmap at the end of pass 2.
pass1.c (e2fsck_pass1, alloc_imagic_map): Allocate and fill in
information for inode_reg_map and inode_imagic_map, which indicates
which inodes are regular files and AFS inodes, respectively.
Since only the master superblock is written during a restart, force
that superblock to be used after a restart; otherwise changes to the
block group descriptors end up getting ignored.
problem.c, problemP.h: If e2fsck is run -n, make def_yn variable be 0
for "no". Add support for a new flag, PR_NO_NOMSG, which supresses
the problem message if e2fsck is run with the -n option.
problem.c, problem.h (PR_2_SET_FILETYPE, PR_2_BAD_FILETYPE): Add new
problem codes.
message.c (expand_dirent_expression): Add support for %dt which prints
the dirent type information.
e2fsck.c (e2fsck_reset_context): Free new bitmaps (inode_reg_map and
inode_imagic_map).
e2fsck.h (e2fsck_t): Add new inode_reg_map and inode_magic_map to the
context structure.
ChangeLog, nt_io.c:
nt_io.c: New file which supports I/O under Windows NT.
ChangeLog, gen_uuid_nt.c:
gen_uuid_nt.c: New file which creates a UUID under Windows NT.
Many files:
Add support for non-Unix compiles
diff --git a/e2fsck/ChangeLog b/e2fsck/ChangeLog
index 28960be..0fc1540 100644
--- a/e2fsck/ChangeLog
+++ b/e2fsck/ChangeLog
@@ -1,3 +1,43 @@
+1999-10-21 <tytso@valinux.com>
+
+ * pass4.c (e2fsck_pass4): If an inode is set in the
+ inode_imagic_map bitmap, don't check to see if it is
+ disconnected from the inode tree (because it almost
+ certainly will be). Free inode_imagic_map at the end of
+ pass 4.
+
+ * pass2.c (check_dir_block, check_filetype): If the FILETYPE
+ feature is set, check the directory entry's filetype
+ information field, and fix/set it if necessary.
+ (e2fsck_pass2): Free the inode_reg_map bitmap at the end
+ of pass 2.
+
+ * pass1.c (e2fsck_pass1, alloc_imagic_map): Allocate and fill in
+ information for inode_reg_map and inode_imagic_map, which
+ indicates which inodes are regular files and AFS inodes,
+ respectively.
+ Since only the master superblock is written during a
+ restart, force that superblock to be used after a restart;
+ otherwise changes to the block group descriptors end up
+ getting ignored.
+
+ * problem.c, problemP.h: If e2fsck is run -n, make def_yn variable
+ be 0 for "no". Add support for a new flag, PR_NO_NOMSG,
+ which supresses the problem message if e2fsck is run with
+ the -n option.
+
+ * problem.c, problem.h (PR_2_SET_FILETYPE, PR_2_BAD_FILETYPE): Add
+ new problem codes.
+
+ * message.c (expand_dirent_expression): Add support for %dt which
+ prints the dirent type information.
+
+ * e2fsck.c (e2fsck_reset_context): Free new bitmaps (inode_reg_map
+ and inode_imagic_map).
+
+ * e2fsck.h (e2fsck_t): Add new inode_reg_map and inode_magic_map
+ to the context structure.
+
1999-09-24 <tytso@valinux.com>
* unix.c (PRS), util.c (ask_yn): Add #ifdef's to make
diff --git a/e2fsck/e2fsck.c b/e2fsck/e2fsck.c
index 3cfca69..3028c87 100644
--- a/e2fsck/e2fsck.c
+++ b/e2fsck/e2fsck.c
@@ -50,6 +50,10 @@
ext2fs_free_inode_bitmap(ctx->inode_dir_map);
ctx->inode_dir_map = 0;
}
+ if (ctx->inode_reg_map) {
+ ext2fs_free_inode_bitmap(ctx->inode_reg_map);
+ ctx->inode_dir_map = 0;
+ }
if (ctx->block_found_map) {
ext2fs_free_block_bitmap(ctx->block_found_map);
ctx->block_found_map = 0;
@@ -75,6 +79,10 @@
ext2fs_free_inode_bitmap(ctx->inode_bad_map);
ctx->inode_bad_map = 0;
}
+ if (ctx->inode_imagic_map) {
+ ext2fs_free_inode_bitmap(ctx->inode_imagic_map);
+ ctx->inode_imagic_map = 0;
+ }
/*
* Clear the array of invalid meta-data flags
diff --git a/e2fsck/e2fsck.h b/e2fsck/e2fsck.h
index 86b411c..83f0889 100644
--- a/e2fsck/e2fsck.h
+++ b/e2fsck/e2fsck.h
@@ -143,6 +143,8 @@
ext2fs_inode_bitmap inode_bad_map; /* Inodes which are bad somehow */
ext2fs_inode_bitmap inode_dir_map; /* Inodes which are directories */
ext2fs_inode_bitmap inode_bb_map; /* Inodes which are in bad blocks */
+ ext2fs_inode_bitmap inode_imagic_map; /* AFS inodes */
+ ext2fs_inode_bitmap inode_reg_map; /* Inodes which are regular files*/
ext2fs_block_bitmap block_found_map; /* Blocks which are in use */
ext2fs_block_bitmap block_dup_map; /* Blks referenced more than once */
diff --git a/e2fsck/message.c b/e2fsck/message.c
index 8bb11df..a129f86 100644
--- a/e2fsck/message.c
+++ b/e2fsck/message.c
@@ -20,6 +20,7 @@
* %dn <dirent>->name string
* %dr <dirent>->rec_len
* %dl <dirent>->name_len
+ * %dt <dirent>->filetype
* %D <dir> inode number
* %g <group> integer
* %i <ino> inode number
@@ -301,6 +302,9 @@
case 'l':
printf("%u", dirent->name_len & 0xFF);
break;
+ case 't':
+ printf("%u", dirent->name_len >> 8);
+ break;
default:
no_dirent:
printf("%%D%c", ch);
diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c
index cebc82c..c7475f9 100644
--- a/e2fsck/pass1.c
+++ b/e2fsck/pass1.c
@@ -19,8 +19,10 @@
*
* - A bitmap of which inodes are in use. (inode_used_map)
* - A bitmap of which inodes are directories. (inode_dir_map)
+ * - A bitmap of which inodes are regular files. (inode_reg_map)
* - A bitmap of which inodes have bad fields. (inode_bad_map)
* - A bitmap of which inodes are in bad blocks. (inode_bb_map)
+ * - A bitmap of which inodes are imagic inodes. (inode_imagic_map)
* - A bitmap of which blocks are in use. (block_found_map)
* - A bitmap of which blocks are in use by two inodes (block_dup_map)
* - The data blocks of the directory inodes. (dir_map)
@@ -60,6 +62,7 @@
static void mark_table_blocks(e2fsck_t ctx);
static void alloc_bad_map(e2fsck_t ctx);
static void alloc_bb_map(e2fsck_t ctx);
+static void alloc_imagic_map(e2fsck_t ctx);
static void handle_fs_bad_blocks(e2fsck_t ctx);
static void process_inodes(e2fsck_t ctx, char *block_buf);
static EXT2_QSORT_TYPE process_inode_cmp(const void *a, const void *b);
@@ -199,6 +202,15 @@
ctx->flags |= E2F_FLAG_ABORT;
return;
}
+ pctx.errcode = ext2fs_allocate_inode_bitmap(fs,
+ "regular file inode map",
+ &ctx->inode_reg_map);
+ if (pctx.errcode) {
+ pctx.num = 6;
+ fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
+ ctx->flags |= E2F_FLAG_ABORT;
+ return;
+ }
pctx.errcode = ext2fs_allocate_block_bitmap(fs, "in-use block map",
&ctx->block_found_map);
if (pctx.errcode) {
@@ -405,14 +417,20 @@
alloc_bad_map(ctx);
ext2fs_mark_inode_bitmap(ctx->inode_bad_map, ino);
}
+ if (inode.i_flags & EXT2_IMAGIC_FL) {
+ if (!ctx->inode_imagic_map)
+ alloc_imagic_map(ctx);
+ ext2fs_mark_inode_bitmap(ctx->inode_imagic_map, ino);
+ }
if (LINUX_S_ISDIR(inode.i_mode)) {
ext2fs_mark_inode_bitmap(ctx->inode_dir_map, ino);
e2fsck_add_dir_info(ctx, ino, 0);
ctx->fs_directory_count++;
- } else if (LINUX_S_ISREG (inode.i_mode))
+ } else if (LINUX_S_ISREG (inode.i_mode)) {
+ ext2fs_mark_inode_bitmap(ctx->inode_reg_map, ino);
ctx->fs_regular_count++;
- else if (LINUX_S_ISCHR (inode.i_mode) &&
+ } else if (LINUX_S_ISCHR (inode.i_mode) &&
e2fsck_pass1_check_device_inode(&inode))
ctx->fs_chardev_count++;
else if (LINUX_S_ISBLK (inode.i_mode) &&
@@ -485,6 +503,13 @@
handle_fs_bad_blocks(ctx);
if (ctx->flags & E2F_FLAG_RESTART) {
+ /*
+ * Only the master copy of the superblock and block
+ * group descriptors are going to be written during a
+ * restart, so set the superblock to be used to be the
+ * master superblock.
+ */
+ ctx->use_superblock = 0;
unwind_pass1(fs);
goto endit;
}
@@ -649,6 +674,26 @@
}
/*
+ * This procedure will allocate the inode imagic table
+ */
+static void alloc_imagic_map(e2fsck_t ctx)
+{
+ struct problem_context pctx;
+
+ clear_problem_context(&pctx);
+ pctx.errcode = ext2fs_allocate_inode_bitmap(ctx->fs,
+ "imagic inode map",
+ &ctx->inode_imagic_map);
+ if (pctx.errcode) {
+ pctx.num = 5;
+ fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
+ /* Should never get here */
+ ctx->flags |= E2F_FLAG_ABORT;
+ return;
+ }
+}
+
+/*
* Marks a block as in use, setting the dup_map if it's been set
* already. Called by process_block and process_bad_block.
*
@@ -729,6 +774,7 @@
inode->i_dtime = time(0);
e2fsck_write_inode(ctx, ino, inode, "check_blocks");
ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
+ ext2fs_unmark_inode_bitmap(ctx->inode_reg_map, ino);
ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
/*
* The inode was probably partially accounted for
@@ -752,6 +798,7 @@
inode->i_dtime = time(0);
e2fsck_write_inode(ctx, ino, inode, "check_blocks");
ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
+ ext2fs_unmark_inode_bitmap(ctx->inode_reg_map, ino);
ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
ctx->fs_directory_count--;
pb.is_dir = 0;
diff --git a/e2fsck/pass2.c b/e2fsck/pass2.c
index 37114e3..2eec914 100644
--- a/e2fsck/pass2.c
+++ b/e2fsck/pass2.c
@@ -38,11 +38,18 @@
*
* Pass 2 frees the following data structures
* - The inode_bad_map bitmap
+ * - The inode_reg_map bitmap
*/
#include "e2fsck.h"
#include "problem.h"
+#ifdef NO_INLINE_FUNCS
+#define _INLINE_
+#else
+#define _INLINE_ inline
+#endif
+
/*
* Keeps track of how many times an inode is referenced.
*/
@@ -134,6 +141,10 @@
ext2fs_free_inode_bitmap(ctx->inode_bad_map);
ctx->inode_bad_map = 0;
}
+ if (ctx->inode_reg_map) {
+ ext2fs_free_inode_bitmap(ctx->inode_reg_map);
+ ctx->inode_reg_map = 0;
+ }
#ifdef RESOURCE_TRACK
if (ctx->options & E2F_OPT_TIME2) {
e2fsck_clear_progbar(ctx);
@@ -268,6 +279,57 @@
return ret;
}
+/*
+ * Check the directory filetype (if present)
+ */
+static _INLINE_ int check_filetype(e2fsck_t ctx,
+ struct ext2_dir_entry *dirent,
+ ino_t dir_ino, struct problem_context *pctx)
+{
+ int filetype = dirent->name_len >> 8;
+ int should_be = EXT2_FT_UNKNOWN;
+ struct ext2_inode inode;
+
+ if (!(ctx->fs->super->s_feature_incompat &
+ EXT2_FEATURE_INCOMPAT_FILETYPE))
+ return 0;
+
+ if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, dirent->inode)) {
+ should_be = EXT2_FT_DIR;
+ } else if (ext2fs_test_inode_bitmap(ctx->inode_reg_map,
+ dirent->inode)) {
+ should_be = EXT2_FT_REG_FILE;
+ } else if (ctx->inode_bad_map &&
+ ext2fs_test_inode_bitmap(ctx->inode_bad_map,
+ dirent->inode))
+ should_be = 0;
+ else {
+ e2fsck_read_inode(ctx, dirent->inode, &inode,
+ "check_filetype");
+ if (LINUX_S_ISCHR (inode.i_mode))
+ should_be = EXT2_FT_CHRDEV;
+ else if (LINUX_S_ISBLK (inode.i_mode))
+ should_be = EXT2_FT_BLKDEV;
+ else if (LINUX_S_ISLNK (inode.i_mode))
+ should_be = EXT2_FT_SYMLINK;
+ else if (LINUX_S_ISFIFO (inode.i_mode))
+ should_be = EXT2_FT_FIFO;
+ else if (LINUX_S_ISSOCK (inode.i_mode))
+ should_be = EXT2_FT_SOCK;
+ }
+ if (filetype == should_be)
+ return 0;
+ pctx->num = should_be;
+
+ if (fix_problem(ctx, filetype ? PR_2_BAD_FILETYPE : PR_2_SET_FILETYPE,
+ pctx) == 0)
+ return 0;
+
+ dirent->name_len = (dirent->name_len & 0xFF) | should_be << 8;
+ return 1;
+}
+
+
static int check_dir_block(ext2_filsys fs,
struct ext2_db_entry *db,
void *priv_data)
@@ -465,6 +527,9 @@
if (check_name(ctx, dirent, ino, &cd->pctx))
dir_modified++;
+ if (check_filetype(ctx, dirent, ino, &cd->pctx))
+ dir_modified++;
+
/*
* If this is a directory, then mark its parent in its
* dir_info structure. If the parent field is already
diff --git a/e2fsck/pass4.c b/e2fsck/pass4.c
index 264b1c7..92721bd 100644
--- a/e2fsck/pass4.c
+++ b/e2fsck/pass4.c
@@ -10,6 +10,7 @@
*
* Pass 4 frees the following data structures:
* - A bitmap of which inodes are in bad blocks. (inode_bb_map)
+ * - A bitmap of which inodes are imagic inodes. (inode_imagic_map)
*/
#include "e2fsck.h"
@@ -117,6 +118,8 @@
(i > EXT2_ROOT_INO && i < EXT2_FIRST_INODE(fs->super)))
continue;
if (!(ext2fs_test_inode_bitmap(ctx->inode_used_map, i)) ||
+ (ctx->inode_imagic_map &&
+ ext2fs_test_inode_bitmap(ctx->inode_imagic_map, i)) ||
(ctx->inode_bb_map &&
ext2fs_test_inode_bitmap(ctx->inode_bb_map, i)))
continue;
@@ -151,6 +154,7 @@
ext2fs_free_icount(ctx->inode_link_info); ctx->inode_link_info = 0;
ext2fs_free_icount(ctx->inode_count); ctx->inode_count = 0;
ext2fs_free_inode_bitmap(ctx->inode_bb_map);
+ ext2fs_free_inode_bitmap(ctx->inode_imagic_map);
ctx->inode_bb_map = 0;
#ifdef RESOURCE_TRACK
if (ctx->options & E2F_OPT_TIME2) {
diff --git a/e2fsck/problem.c b/e2fsck/problem.c
index e7a0dc6..3a54926 100644
--- a/e2fsck/problem.c
+++ b/e2fsck/problem.c
@@ -693,6 +693,16 @@
"@i %i (%Q) is an @I socket.\n",
PROMPT_CLEAR, 0 },
+ /* Directory filetype not set */
+ { PR_2_SET_FILETYPE,
+ "Setting filetype for @E to %N.\n",
+ PROMPT_NONE, PR_PREEN_OK | PR_NO_OK | PR_NO_NOMSG },
+
+ /* Directory filetype incorrect */
+ { PR_2_BAD_FILETYPE,
+ "@E has an incorrect filetype (was %dt, should be %N)\n",
+ PROMPT_FIX, 0 },
+
/* Pass 3 errors */
/* Pass 3: Checking directory connectivity */
@@ -1038,7 +1048,9 @@
printf("Unhandled error code (%d)!\n", code);
return 0;
}
- def_yn = (ptr->flags & PR_NO_DEFAULT) ? 0 : 1;
+ def_yn = 1;
+ if ((ptr->flags & PR_NO_DEFAULT) || (ctx->options & E2F_OPT_NO))
+ def_yn= 0;
/*
* Do special latch processing. This is where we ask the
@@ -1060,6 +1072,9 @@
if ((ptr->flags & PR_PREEN_NOMSG) &&
(ctx->options & E2F_OPT_PREEN))
suppress++;
+ if ((ptr->flags & PR_NO_NOMSG) &&
+ (ctx->options & E2F_OPT_NO))
+ suppress++;
if (!suppress) {
message = ptr->e2p_description;
if (ctx->options & E2F_OPT_PREEN) {
diff --git a/e2fsck/problem.h b/e2fsck/problem.h
index 1e21440..ddbc717 100644
--- a/e2fsck/problem.h
+++ b/e2fsck/problem.h
@@ -411,6 +411,12 @@
/* Illegal socket */
#define PR_2_BAD_SOCKET 0x020026
+/* Directory filetype not set */
+#define PR_2_SET_FILETYPE 0x020027
+
+/* Directory filetype incorrect */
+#define PR_2_BAD_FILETYPE 0x020028
+
/*
* Pass 3 errors
*/
diff --git a/e2fsck/problemP.h b/e2fsck/problemP.h
index ceb7bd3..7c75fc6 100644
--- a/e2fsck/problemP.h
+++ b/e2fsck/problemP.h
@@ -33,4 +33,5 @@
/* ask another */
#define PR_PREEN_NOMSG 0x0200 /* Don't print a message if we're preening */
#define PR_NOCOLLATE 0x0400 /* Don't collate answers for this latch */
+#define PR_NO_NOMSG 0x0800 /* Don't print a message if e2fsck -n */
diff --git a/include/nonunix/asm/types.h b/include/nonunix/asm/types.h
new file mode 100644
index 0000000..fccb426
--- /dev/null
+++ b/include/nonunix/asm/types.h
@@ -0,0 +1 @@
+#include "../linux/types.h"
\ No newline at end of file
diff --git a/include/nonunix/config.h b/include/nonunix/config.h
new file mode 100644
index 0000000..cc8ac19
--- /dev/null
+++ b/include/nonunix/config.h
@@ -0,0 +1,18 @@
+
+#define _INO_T_DEFINED 1
+
+#define HAVE_STDLIB_H 1
+#define HAVE_STRING_H 1
+#define HAVE_GETOPT_H 1
+#define HAVE_ERRNO_H 1
+#define HAVE_SETJMP_H 1
+
+#define HAVE_STRCASECMP 1
+#define HAVE_CONIO_H 1
+
+#define HAVE_EXT2_INODE_VERSION 1
+
+#define inline __forceinline
+
+#define _CTYPE_DISABLE_MACROS
+
diff --git a/include/nonunix/dirent.h b/include/nonunix/dirent.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/include/nonunix/dirent.h
diff --git a/include/nonunix/getopt.h b/include/nonunix/getopt.h
new file mode 100644
index 0000000..33ad46c
--- /dev/null
+++ b/include/nonunix/getopt.h
@@ -0,0 +1,135 @@
+/* Declarations for getopt.
+ Copyright (C) 1989,90,91,92,93,94,96,97 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef _GETOPT_H
+#define _GETOPT_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef GETOPT_VARIABLE
+#define GETOPT_VARIABLE
+#endif
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+extern GETOPT_VARIABLE char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ When `getopt' returns -1, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+extern GETOPT_VARIABLE int optind;
+
+/* Callers store zero here to inhibit the error message `getopt' prints
+ for unrecognized options. */
+
+extern GETOPT_VARIABLE int opterr;
+
+/* Set to an option character which was unrecognized. */
+
+extern GETOPT_VARIABLE int optopt;
+
+/* Describe the long-named options requested by the application.
+ The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
+ of `struct option' terminated by an element containing a name which is
+ zero.
+
+ The field `has_arg' is:
+ no_argument (or 0) if the option does not take an argument,
+ required_argument (or 1) if the option requires an argument,
+ optional_argument (or 2) if the option takes an optional argument.
+
+ If the field `flag' is not NULL, it points to a variable that is set
+ to the value given in the field `val' when the option is found, but
+ left unchanged if the option is not found.
+
+ To have a long-named option do something other than set an `int' to
+ a compiled-in constant, such as set a value from `optarg', set the
+ option's `flag' field to zero and its `val' field to a nonzero
+ value (the equivalent single-letter option character, if there is
+ one). For long options that have a zero `flag' field, `getopt'
+ returns the contents of the `val' field. */
+
+struct option
+{
+#if defined (__STDC__) && __STDC__
+ const char *name;
+#else
+ char *name;
+#endif
+ /* has_arg can't be an enum because some compilers complain about
+ type mismatches in all the code that assumes it is an int. */
+ int has_arg;
+ int *flag;
+ int val;
+};
+
+/* Names for the values of the `has_arg' field of `struct option'. */
+
+#define no_argument 0
+#define required_argument 1
+#define optional_argument 2
+
+#if defined (__STDC__) && __STDC__
+#ifdef __GNU_LIBRARY__
+/* Many other libraries have conflicting prototypes for getopt, with
+ differences in the consts, in stdlib.h. To avoid compilation
+ errors, only prototype getopt for the GNU C library. */
+extern int getopt (int argc, char *const *argv, const char *shortopts);
+#else /* not __GNU_LIBRARY__ */
+extern int getopt ();
+#endif /* __GNU_LIBRARY__ */
+extern int getopt_long (int argc, char *const *argv, const char *shortopts,
+ const struct option *longopts, int *longind);
+extern int getopt_long_only (int argc, char *const *argv,
+ const char *shortopts,
+ const struct option *longopts, int *longind);
+
+/* Internal only. Users should not call this directly. */
+extern int _getopt_internal (int argc, char *const *argv,
+ const char *shortopts,
+ const struct option *longopts, int *longind,
+ int long_only);
+#else /* not __STDC__ */
+extern int getopt ();
+extern int getopt_long ();
+extern int getopt_long_only ();
+
+extern int _getopt_internal ();
+#endif /* __STDC__ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GETOPT_H */
diff --git a/include/nonunix/grp.h b/include/nonunix/grp.h
new file mode 100644
index 0000000..4130cb7
--- /dev/null
+++ b/include/nonunix/grp.h
@@ -0,0 +1,17 @@
+
+#pragma once
+
+typedef unsigned short __gid_t;
+__inline __gid_t getgid(void){return 0;}
+__inline struct group * getgrnam(char* g){return 0;}
+
+struct group
+ {
+ char *gr_name;
+ char *gr_passwd;
+ __gid_t gr_gid;
+ char **gr_mem;
+ };
+
+#define getgrgid(i) NULL
+
diff --git a/include/nonunix/linux/types.h b/include/nonunix/linux/types.h
new file mode 100644
index 0000000..8e5bc90
--- /dev/null
+++ b/include/nonunix/linux/types.h
@@ -0,0 +1,28 @@
+#ifndef _LINUX_TYPES_H
+#define _LINUX_TYPES_H
+
+#ifndef _MSC_VER
+#error _MSC_VER not defined
+#endif
+
+
+typedef unsigned __int8 __u8;
+typedef signed __int8 __s8;
+
+typedef signed __int64 __s64;
+typedef unsigned __int64 __u64;
+
+typedef signed __int16 __s16;
+typedef unsigned __int16 __u16;
+
+typedef signed __int32 __s32;
+typedef unsigned __int32 __u32;
+
+typedef signed __int64 __s64;
+typedef unsigned __int64 __u64;
+
+
+typedef __u32 ino_t;
+
+
+#endif /* LINUX_TYPES_H */
diff --git a/include/nonunix/pwd.h b/include/nonunix/pwd.h
new file mode 100644
index 0000000..67e05ea
--- /dev/null
+++ b/include/nonunix/pwd.h
@@ -0,0 +1,22 @@
+
+#pragma once
+
+typedef unsigned short __uid_t;
+__inline __uid_t getuid(void){return 0;}
+__inline int geteuid(void){return 1;}
+__inline struct passwd* getpwnam (char* g){return 0;}
+
+
+struct passwd
+{
+ char *pw_name;
+ char *pw_passwd;
+ __uid_t pw_uid;
+ __gid_t pw_gid;
+ char *pw_gecos;
+ char *pw_dir;
+ char *pw_shell;
+};
+
+#define getpwuid(i) NULL
+
diff --git a/include/nonunix/sys/file.h b/include/nonunix/sys/file.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/include/nonunix/sys/file.h
diff --git a/include/nonunix/sys/ioctl.h b/include/nonunix/sys/ioctl.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/include/nonunix/sys/ioctl.h
diff --git a/include/nonunix/sys/param.h b/include/nonunix/sys/param.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/include/nonunix/sys/param.h
diff --git a/include/nonunix/sys/resource.h b/include/nonunix/sys/resource.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/include/nonunix/sys/resource.h
diff --git a/include/nonunix/sys/socket.h b/include/nonunix/sys/socket.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/include/nonunix/sys/socket.h
diff --git a/include/nonunix/sys/time.h b/include/nonunix/sys/time.h
new file mode 100644
index 0000000..91fd187
--- /dev/null
+++ b/include/nonunix/sys/time.h
@@ -0,0 +1 @@
+#include <time.h>
diff --git a/include/nonunix/sys/wait.h b/include/nonunix/sys/wait.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/include/nonunix/sys/wait.h
diff --git a/include/nonunix/termios.h b/include/nonunix/termios.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/include/nonunix/termios.h
diff --git a/include/nonunix/unistd.h b/include/nonunix/unistd.h
new file mode 100644
index 0000000..5053587
--- /dev/null
+++ b/include/nonunix/unistd.h
@@ -0,0 +1,49 @@
+
+
+#pragma once
+
+#include <stdlib.h>
+#include <process.h>
+#include <io.h>
+
+#define EOPNOTSUPP 95
+
+#define O_NONBLOCK 0
+#define O_RDONLY _O_RDONLY
+#define O_RDWR _O_RDWR
+
+#define popen _popen
+#define pclose _pclose
+#define sleep _sleep
+#define stat _stat
+#define open _open
+#define close _close
+#define fstat _fstat
+#define read _read
+#define write _write
+#define off_t _off_t
+#define lseek _lseek
+#define putenv _putenv
+#define getpid _getpid
+#define utimbuf _utimbuf
+#define sys_nerr _sys_nerr
+#define sys_errlist _sys_errlist
+#define isatty _isatty
+#define getch _getch
+
+#include <grp.h>
+#include <pwd.h>
+
+
+// no-oped sync
+__inline void sync(void){};
+
+
+
+#define gettimeofday(p, v) ((p)->tv_sec = (p)->tv_usec = 0)
+
+
+#define strcasecmp _stricmp
+
+
+
diff --git a/include/nonunix/utime.h b/include/nonunix/utime.h
new file mode 100644
index 0000000..8285f38
--- /dev/null
+++ b/include/nonunix/utime.h
@@ -0,0 +1 @@
+#include <sys/utime.h>
diff --git a/lib/ext2fs/ChangeLog b/lib/ext2fs/ChangeLog
index 275c6b0..5496f16 100644
--- a/lib/ext2fs/ChangeLog
+++ b/lib/ext2fs/ChangeLog
@@ -1,3 +1,7 @@
+1999-09-24 <tytso@valinux.com>
+
+ * nt_io.c: New file which supports I/O under Windows NT.
+
1999-09-07 <tytso@valinux.com>
* ext2fs.h: Add new fields for journalling and define new
diff --git a/lib/ext2fs/nt_io.c b/lib/ext2fs/nt_io.c
new file mode 100644
index 0000000..4b3ce47
--- /dev/null
+++ b/lib/ext2fs/nt_io.c
@@ -0,0 +1,1514 @@
+/*
+/*
+ * nt_io.c --- This is the Nt I/O interface to the I/O manager.
+ *
+ * Implements a one-block write-through cache.
+ *
+ * Copyright (C) 1993, 1994, 1995 Theodore Ts'o.
+ * Copyright (C) 1998 Andrey Shedel
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+
+//
+// I need some warnings to disable...
+//
+
+
+#pragma warning(disable:4514) // unreferenced inline function has been removed
+#pragma warning(push,4)
+
+#pragma warning(disable:4201) // nonstandard extension used : nameless struct/union)
+#pragma warning(disable:4214) // nonstandard extension used : bit field types other than int
+#pragma warning(disable:4115) // named type definition in parentheses
+
+#include <ntddk.h>
+#include <ntdddisk.h>
+#include <ntstatus.h>
+
+#pragma warning(pop)
+
+
+//
+// Some native APIs.
+//
+
+NTSYSAPI
+ULONG
+NTAPI
+RtlNtStatusToDosError(
+ IN NTSTATUS Status
+ );
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+NtClose(
+ IN HANDLE Handle
+ );
+
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+NtOpenFile(
+ OUT PHANDLE FileHandle,
+ IN ACCESS_MASK DesiredAccess,
+ IN POBJECT_ATTRIBUTES ObjectAttributes,
+ OUT PIO_STATUS_BLOCK IoStatusBlock,
+ IN ULONG ShareAccess,
+ IN ULONG OpenOptions
+ );
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+NtFlushBuffersFile(
+ IN HANDLE FileHandle,
+ OUT PIO_STATUS_BLOCK IoStatusBlock
+ );
+
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+NtReadFile(
+ IN HANDLE FileHandle,
+ IN HANDLE Event OPTIONAL,
+ IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
+ IN PVOID ApcContext OPTIONAL,
+ OUT PIO_STATUS_BLOCK IoStatusBlock,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ IN PLARGE_INTEGER ByteOffset OPTIONAL,
+ IN PULONG Key OPTIONAL
+ );
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+NtWriteFile(
+ IN HANDLE FileHandle,
+ IN HANDLE Event OPTIONAL,
+ IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
+ IN PVOID ApcContext OPTIONAL,
+ OUT PIO_STATUS_BLOCK IoStatusBlock,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ IN PLARGE_INTEGER ByteOffset OPTIONAL,
+ IN PULONG Key OPTIONAL
+ );
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+NtDeviceIoControlFile(
+ IN HANDLE FileHandle,
+ IN HANDLE Event OPTIONAL,
+ IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
+ IN PVOID ApcContext OPTIONAL,
+ OUT PIO_STATUS_BLOCK IoStatusBlock,
+ IN ULONG IoControlCode,
+ IN PVOID InputBuffer OPTIONAL,
+ IN ULONG InputBufferLength,
+ OUT PVOID OutputBuffer OPTIONAL,
+ IN ULONG OutputBufferLength
+ );
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+NtFsControlFile(
+ IN HANDLE FileHandle,
+ IN HANDLE Event OPTIONAL,
+ IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
+ IN PVOID ApcContext OPTIONAL,
+ OUT PIO_STATUS_BLOCK IoStatusBlock,
+ IN ULONG IoControlCode,
+ IN PVOID InputBuffer OPTIONAL,
+ IN ULONG InputBufferLength,
+ OUT PVOID OutputBuffer OPTIONAL,
+ IN ULONG OutputBufferLength
+ );
+
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+NtDelayExecution(
+ IN BOOLEAN Alertable,
+ IN PLARGE_INTEGER Interval
+ );
+
+
+#define FSCTL_LOCK_VOLUME CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 6, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define FSCTL_UNLOCK_VOLUME CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 7, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define FSCTL_DISMOUNT_VOLUME CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 8, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define FSCTL_IS_VOLUME_MOUNTED CTL_CODE(FILE_DEVICE_FILE_SYSTEM,10, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+
+//
+// useful macros
+//
+
+#define BooleanFlagOn(Flags,SingleFlag) ((BOOLEAN)((((Flags) & (SingleFlag)) != 0)))
+
+
+//
+// Include Win32 error codes.
+//
+
+#include <winerror.h>
+
+//
+// standard stuff
+//
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <malloc.h>
+
+#include <linux/types.h>
+#include <linux/ext2_fs.h>
+#include <errno.h>
+
+#include "et/com_err.h"
+#include "ext2fs/ext2fs.h"
+#include "ext2fs/ext2_err.h"
+
+
+
+
+//
+// For checking structure magic numbers...
+//
+
+
+#define EXT2_CHECK_MAGIC(struct, code) \
+ if ((struct)->magic != (code)) return (code)
+
+#define EXT2_ET_MAGIC_NT_IO_CHANNEL 0x10ed
+
+
+//
+// Private data block
+//
+
+typedef struct _NT_PRIVATE_DATA {
+ int magic;
+ HANDLE Handle;
+ int Flags;
+ PCHAR Buffer;
+ __u32 BufferBlockNumber;
+ ULONG BufferSize;
+ BOOLEAN OpenedReadonly;
+ BOOLEAN Written;
+}NT_PRIVATE_DATA, *PNT_PRIVATE_DATA;
+
+
+
+//
+// Standard interface prototypes
+//
+
+static errcode_t nt_open(const char *name, int flags, io_channel *channel);
+static errcode_t nt_close(io_channel channel);
+static errcode_t nt_set_blksize(io_channel channel, int blksize);
+static errcode_t nt_read_blk(io_channel channel, unsigned long block,
+ int count, void *data);
+static errcode_t nt_write_blk(io_channel channel, unsigned long block,
+ int count, const void *data);
+static errcode_t nt_flush(io_channel channel);
+
+static struct struct_io_manager struct_nt_manager = {
+ EXT2_ET_MAGIC_IO_MANAGER,
+ "NT I/O Manager",
+ nt_open,
+ nt_close,
+ nt_set_blksize,
+ nt_read_blk,
+ nt_write_blk,
+ nt_flush
+};
+
+
+
+//
+// function to get API
+//
+
+io_manager nt_io_manager()
+{
+ return &struct_nt_manager;
+}
+
+
+
+
+
+//
+// This is a code to convert Win32 errors to unix errno
+//
+
+typedef struct {
+ ULONG WinError;
+ int errnocode;
+}ERROR_ENTRY;
+
+static ERROR_ENTRY ErrorTable[] = {
+ { ERROR_INVALID_FUNCTION, EINVAL },
+ { ERROR_FILE_NOT_FOUND, ENOENT },
+ { ERROR_PATH_NOT_FOUND, ENOENT },
+ { ERROR_TOO_MANY_OPEN_FILES, EMFILE },
+ { ERROR_ACCESS_DENIED, EACCES },
+ { ERROR_INVALID_HANDLE, EBADF },
+ { ERROR_ARENA_TRASHED, ENOMEM },
+ { ERROR_NOT_ENOUGH_MEMORY, ENOMEM },
+ { ERROR_INVALID_BLOCK, ENOMEM },
+ { ERROR_BAD_ENVIRONMENT, E2BIG },
+ { ERROR_BAD_FORMAT, ENOEXEC },
+ { ERROR_INVALID_ACCESS, EINVAL },
+ { ERROR_INVALID_DATA, EINVAL },
+ { ERROR_INVALID_DRIVE, ENOENT },
+ { ERROR_CURRENT_DIRECTORY, EACCES },
+ { ERROR_NOT_SAME_DEVICE, EXDEV },
+ { ERROR_NO_MORE_FILES, ENOENT },
+ { ERROR_LOCK_VIOLATION, EACCES },
+ { ERROR_BAD_NETPATH, ENOENT },
+ { ERROR_NETWORK_ACCESS_DENIED, EACCES },
+ { ERROR_BAD_NET_NAME, ENOENT },
+ { ERROR_FILE_EXISTS, EEXIST },
+ { ERROR_CANNOT_MAKE, EACCES },
+ { ERROR_FAIL_I24, EACCES },
+ { ERROR_INVALID_PARAMETER, EINVAL },
+ { ERROR_NO_PROC_SLOTS, EAGAIN },
+ { ERROR_DRIVE_LOCKED, EACCES },
+ { ERROR_BROKEN_PIPE, EPIPE },
+ { ERROR_DISK_FULL, ENOSPC },
+ { ERROR_INVALID_TARGET_HANDLE, EBADF },
+ { ERROR_INVALID_HANDLE, EINVAL },
+ { ERROR_WAIT_NO_CHILDREN, ECHILD },
+ { ERROR_CHILD_NOT_COMPLETE, ECHILD },
+ { ERROR_DIRECT_ACCESS_HANDLE, EBADF },
+ { ERROR_NEGATIVE_SEEK, EINVAL },
+ { ERROR_SEEK_ON_DEVICE, EACCES },
+ { ERROR_DIR_NOT_EMPTY, ENOTEMPTY },
+ { ERROR_NOT_LOCKED, EACCES },
+ { ERROR_BAD_PATHNAME, ENOENT },
+ { ERROR_MAX_THRDS_REACHED, EAGAIN },
+ { ERROR_LOCK_FAILED, EACCES },
+ { ERROR_ALREADY_EXISTS, EEXIST },
+ { ERROR_FILENAME_EXCED_RANGE, ENOENT },
+ { ERROR_NESTING_NOT_ALLOWED, EAGAIN },
+ { ERROR_NOT_ENOUGH_QUOTA, ENOMEM }
+};
+
+
+
+
+static
+unsigned
+_MapDosError (
+ IN ULONG WinError
+ )
+{
+ int i;
+
+ //
+ // Lookup
+ //
+
+ for (i = 0; i < (sizeof(ErrorTable)/sizeof(ErrorTable[0])); ++i)
+ {
+ if (WinError == ErrorTable[i].WinError)
+ {
+ return ErrorTable[i].errnocode;
+ }
+ }
+
+ //
+ // not in table. Check ranges
+ //
+
+ if ((WinError >= ERROR_WRITE_PROTECT) &&
+ (WinError <= ERROR_SHARING_BUFFER_EXCEEDED))
+ {
+ return EACCES;
+ }
+ else if ((WinError >= ERROR_INVALID_STARTING_CODESEG) &&
+ (WinError <= ERROR_INFLOOP_IN_RELOC_CHAIN))
+ {
+ return ENOEXEC;
+ }
+ else
+ {
+ return EINVAL;
+ }
+}
+
+
+
+
+
+
+
+//
+// Function to map NT status to dos error.
+//
+
+static
+__inline
+unsigned
+_MapNtStatus(
+ IN NTSTATUS Status
+ )
+{
+ return _MapDosError(RtlNtStatusToDosError(Status));
+}
+
+
+
+
+
+//
+// Helper functions to make things easyer
+//
+
+static
+NTSTATUS
+_OpenNtName(
+ IN PCSTR Name,
+ IN BOOLEAN Readonly,
+ OUT PHANDLE Handle,
+ OUT PBOOLEAN OpenedReadonly OPTIONAL
+ )
+{
+ UNICODE_STRING UnicodeString;
+ ANSI_STRING AnsiString;
+ WCHAR Buffer[512];
+ NTSTATUS Status;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ IO_STATUS_BLOCK IoStatusBlock;
+
+ //
+ // Make Unicode name from inlut string
+ //
+
+ UnicodeString.Buffer = &Buffer[0];
+ UnicodeString.Length = 0;
+ UnicodeString.MaximumLength = sizeof(Buffer); // in bytes!!!
+
+ RtlInitAnsiString(&AnsiString, Name);
+
+ Status = RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString, FALSE);
+
+ if(!NT_SUCCESS(Status))
+ {
+ return Status; // Unpappable character?
+ }
+
+ //
+ // Initialize object
+ //
+
+ InitializeObjectAttributes(&ObjectAttributes,
+ &UnicodeString,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL );
+
+ //
+ // Try to open it in initial mode
+ //
+
+ if(ARGUMENT_PRESENT(OpenedReadonly))
+ {
+ *OpenedReadonly = Readonly;
+ }
+
+
+ Status = NtOpenFile(Handle,
+ SYNCHRONIZE | FILE_READ_DATA | (Readonly ? 0 : FILE_WRITE_DATA),
+ &ObjectAttributes,
+ &IoStatusBlock,
+ FILE_SHARE_WRITE | FILE_SHARE_READ,
+ FILE_SYNCHRONOUS_IO_ALERT);
+
+ if(!NT_SUCCESS(Status))
+ {
+ //
+ // Maybe was just mounted? wait 0.5 sec and retry.
+ //
+
+ LARGE_INTEGER Interval;
+ Interval.QuadPart = -5000000; // 0.5 sec. from now
+
+ NtDelayExecution(FALSE, &Interval);
+
+ Status = NtOpenFile(Handle,
+ SYNCHRONIZE | FILE_READ_DATA | (Readonly ? 0 : FILE_WRITE_DATA),
+ &ObjectAttributes,
+ &IoStatusBlock,
+ FILE_SHARE_WRITE | FILE_SHARE_READ,
+ FILE_SYNCHRONOUS_IO_ALERT);
+
+ //
+ // Try to satisfy mode
+ //
+
+ if((STATUS_ACCESS_DENIED == Status) && !Readonly)
+ {
+ if(ARGUMENT_PRESENT(OpenedReadonly))
+ {
+ *OpenedReadonly = TRUE;
+ }
+
+ Status = NtOpenFile(Handle,
+ SYNCHRONIZE | FILE_READ_DATA,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ FILE_SHARE_WRITE | FILE_SHARE_READ,
+ FILE_SYNCHRONOUS_IO_ALERT);
+ }
+ }
+
+
+
+ //
+ // done
+ //
+
+ return Status;
+}
+
+
+static
+NTSTATUS
+_OpenDriveLetter(
+ IN CHAR Letter,
+ IN BOOLEAN ReadOnly,
+ OUT PHANDLE Handle,
+ OUT PBOOLEAN OpenedReadonly OPTIONAL
+ )
+{
+ CHAR Buffer[100];
+
+ sprintf(Buffer, "\\DosDevices\\%c:", Letter);
+
+ return _OpenNtName(Buffer, ReadOnly, Handle, OpenedReadonly);
+}
+
+
+//
+// Flush device
+//
+
+static
+__inline
+NTSTATUS
+_FlushDrive(
+ IN HANDLE Handle
+ )
+{
+ IO_STATUS_BLOCK IoStatusBlock;
+ return NtFlushBuffersFile(Handle, &IoStatusBlock);
+}
+
+
+//
+// lock drive
+//
+
+static
+__inline
+NTSTATUS
+_LockDrive(
+ IN HANDLE Handle
+ )
+{
+ IO_STATUS_BLOCK IoStatusBlock;
+ return NtFsControlFile(Handle, 0, 0, 0, &IoStatusBlock, FSCTL_LOCK_VOLUME, 0, 0, 0, 0);
+}
+
+
+//
+// unlock drive
+//
+
+static
+__inline
+NTSTATUS
+_UnlockDrive(
+ IN HANDLE Handle
+ )
+{
+ IO_STATUS_BLOCK IoStatusBlock;
+ return NtFsControlFile(Handle, 0, 0, 0, &IoStatusBlock, FSCTL_UNLOCK_VOLUME, 0, 0, 0, 0);
+}
+
+static
+__inline
+NTSTATUS
+_DismountDrive(
+ IN HANDLE Handle
+ )
+{
+ IO_STATUS_BLOCK IoStatusBlock;
+ return NtFsControlFile(Handle, 0, 0, 0, &IoStatusBlock, FSCTL_DISMOUNT_VOLUME, 0, 0, 0, 0);
+}
+
+
+//
+// is mounted
+//
+
+static
+__inline
+BOOLEAN
+_IsMounted(
+ IN HANDLE Handle
+ )
+{
+ IO_STATUS_BLOCK IoStatusBlock;
+ NTSTATUS Status;
+ Status = NtFsControlFile(Handle, 0, 0, 0, &IoStatusBlock, FSCTL_IS_VOLUME_MOUNTED, 0, 0, 0, 0);
+ return (BOOLEAN)(STATUS_SUCCESS == Status);
+}
+
+
+static
+__inline
+NTSTATUS
+_CloseDisk(
+ IN HANDLE Handle
+ )
+{
+ return NtClose(Handle);
+}
+
+
+
+
+//
+// Make NT name from any recognized name
+//
+
+static
+PCSTR
+_NormalizeDeviceName(
+ IN PCSTR Device,
+ IN PSTR NormalizedDeviceNameBuffer
+ )
+{
+ int PartitionNumber = -1;
+ UCHAR DiskNumber;
+ PSTR p;
+
+
+ //
+ // Do not try to parse NT name
+ //
+
+ if('\\' == *Device)
+ return Device;
+
+
+
+ //
+ // Strip leading '/dev/' if any
+ //
+
+ if(('/' == *(Device)) &&
+ ('d' == *(Device + 1)) &&
+ ('e' == *(Device + 2)) &&
+ ('v' == *(Device + 3)) &&
+ ('/' == *(Device + 4)))
+ {
+ Device += 5;
+ }
+
+ if('\0' == *Device)
+ {
+ return NULL;
+ }
+
+
+ //
+ // forms: hda[n], fd[n]
+ //
+
+ if('d' != *(Device + 1))
+ {
+ return NULL;
+ }
+
+ if('h' == *Device)
+ {
+ if((*(Device + 2) < 'a') || (*(Device + 2) > ('a' + 9)) ||
+ ((*(Device + 3) != '\0') &&
+ ((*(Device + 4) != '\0') ||
+ ((*(Device + 3) < '0') || (*(Device + 3) > '9'))
+ )
+ )
+ )
+ {
+ return NULL;
+ }
+
+ DiskNumber = (UCHAR)(*(Device + 2) - 'a');
+
+ if(*(Device + 3) != '\0')
+ {
+ PartitionNumber = (*(Device + 3) - '0');
+ }
+
+ }
+ else if('f' == *Device)
+ {
+ //
+ // 3-d letted should be a digit.
+ //
+
+ if((*(Device + 3) != '\0') ||
+ (*(Device + 2) < '0') || (*(Device + 2) > '9'))
+ {
+ return NULL;
+ }
+
+ DiskNumber = (UCHAR)(*(Device + 2) - '0');
+
+ }
+ else
+ {
+ //
+ // invalid prefix
+ //
+
+ return NULL;
+ }
+
+
+
+ //
+ // Prefix
+ //
+
+ strcpy(NormalizedDeviceNameBuffer, "\\Device\\");
+
+ //
+ // Media name
+ //
+
+ switch(*Device)
+ {
+
+ case 'f':
+ strcat(NormalizedDeviceNameBuffer, "Floppy0");
+ break;
+
+ case 'h':
+ strcat(NormalizedDeviceNameBuffer, "Harddisk0");
+ break;
+ }
+
+
+ p = NormalizedDeviceNameBuffer + strlen(NormalizedDeviceNameBuffer) - 1;
+ *p = (CHAR)(*p + DiskNumber);
+
+
+ //
+ // Partition nr.
+ //
+
+ if(PartitionNumber >= 0)
+ {
+ strcat(NormalizedDeviceNameBuffer, "\\Partition0");
+
+ p = NormalizedDeviceNameBuffer + strlen(NormalizedDeviceNameBuffer) - 1;
+ *p = (CHAR)(*p + PartitionNumber);
+ }
+
+
+ return NormalizedDeviceNameBuffer;
+}
+
+
+
+
+static
+VOID
+_GetDeviceSize(
+ IN HANDLE h,
+ OUT unsigned __int64 *FsSize
+ )
+{
+ PARTITION_INFORMATION pi;
+ DISK_GEOMETRY gi;
+ NTSTATUS Status;
+ IO_STATUS_BLOCK IoStatusBlock;
+
+ //
+ // Zero it
+ //
+
+ *FsSize = 0;
+
+ //
+ // Call driver
+ //
+
+ RtlZeroMemory(&pi, sizeof(PARTITION_INFORMATION));
+
+ Status = NtDeviceIoControlFile(
+ h, NULL, NULL, NULL, &IoStatusBlock, IOCTL_DISK_GET_PARTITION_INFO,
+ &pi, sizeof(PARTITION_INFORMATION),
+ &pi, sizeof(PARTITION_INFORMATION));
+
+
+ if(NT_SUCCESS(Status))
+ {
+ *FsSize = pi.PartitionLength.QuadPart;
+ }
+ else if(STATUS_INVALID_DEVICE_REQUEST == Status)
+ {
+ //
+ // No partitions: get device info.
+ //
+
+ RtlZeroMemory(&gi, sizeof(DISK_GEOMETRY));
+
+ Status = NtDeviceIoControlFile(
+ h, NULL, NULL, NULL, &IoStatusBlock, IOCTL_DISK_GET_DRIVE_GEOMETRY,
+ &gi, sizeof(DISK_GEOMETRY),
+ &gi, sizeof(DISK_GEOMETRY));
+
+
+ if(NT_SUCCESS(Status))
+ {
+ *FsSize =
+ gi.BytesPerSector *
+ gi.SectorsPerTrack *
+ gi.TracksPerCylinder *
+ gi.Cylinders.QuadPart;
+ }
+
+ }
+}
+
+
+
+//
+// Open device by name.
+//
+
+static
+BOOLEAN
+_Ext2OpenDevice(
+ IN PCSTR Name,
+ IN BOOLEAN ReadOnly,
+ OUT PHANDLE Handle,
+ OUT PBOOLEAN OpenedReadonly OPTIONAL,
+ OUT unsigned *Errno OPTIONAL
+ )
+{
+ CHAR NormalizedDeviceName[512];
+ NTSTATUS Status;
+
+ if(NULL == Name)
+ {
+ //
+ // Set not found
+ //
+
+ if(ARGUMENT_PRESENT(Errno))
+ *Errno = ENOENT;
+
+ return FALSE;
+ }
+
+
+ if((((*Name) | 0x20) >= 'a') && (((*Name) | 0x20) <= 'z') &&
+ (':' == *(Name + 1)) && ('\0' == *(Name + 2)))
+ {
+ Status = _OpenDriveLetter(*Name, ReadOnly, Handle, OpenedReadonly);
+ }
+ else
+ {
+ //
+ // Make name
+ //
+
+ Name = _NormalizeDeviceName(Name, NormalizedDeviceName);
+
+ if(NULL == Name)
+ {
+ //
+ // Set not found
+ //
+
+ if(ARGUMENT_PRESENT(Errno))
+ *Errno = ENOENT;
+
+ return FALSE;
+ }
+
+ //
+ // Try to open it
+ //
+
+ Status = _OpenNtName(Name, ReadOnly, Handle, OpenedReadonly);
+ }
+
+
+ if(!NT_SUCCESS(Status))
+ {
+ if(ARGUMENT_PRESENT(Errno))
+ *Errno = _MapNtStatus(Status);
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+//
+// Raw block io. Sets dos errno
+//
+
+static
+BOOLEAN
+_BlockIo(
+ IN HANDLE Handle,
+ IN LARGE_INTEGER Offset,
+ IN ULONG Bytes,
+ IN OUT PCHAR Buffer,
+ IN BOOLEAN Read,
+ OUT unsigned* Errno
+ )
+{
+ IO_STATUS_BLOCK IoStatusBlock;
+ NTSTATUS Status;
+
+ //
+ // Should be aligned
+ //
+
+ ASSERT(0 == (Bytes % 512));
+ ASSERT(0 == (Offset.LowPart % 512));
+
+
+ //
+ // perform io
+ //
+
+ if(Read)
+ {
+ Status = NtReadFile(Handle, NULL, NULL, NULL,
+ &IoStatusBlock, Buffer, Bytes, &Offset, NULL);
+ }
+ else
+ {
+ Status = NtWriteFile(Handle, NULL, NULL, NULL,
+ &IoStatusBlock, Buffer, Bytes, &Offset, NULL);
+ }
+
+
+ //
+ // translate error
+ //
+
+ if(NT_SUCCESS(Status))
+ {
+ *Errno = 0;
+ return TRUE;
+ }
+
+ *Errno = _MapNtStatus(Status);
+
+ return FALSE;
+}
+
+
+
+__inline
+BOOLEAN
+_RawWrite(
+ IN HANDLE Handle,
+ IN LARGE_INTEGER Offset,
+ IN ULONG Bytes,
+ OUT const CHAR* Buffer,
+ OUT unsigned* Errno
+ )
+{
+ return _BlockIo(Handle, Offset, Bytes, (PCHAR)Buffer, FALSE, Errno);
+}
+
+__inline
+BOOLEAN
+_RawRead(
+ IN HANDLE Handle,
+ IN LARGE_INTEGER Offset,
+ IN ULONG Bytes,
+ IN PCHAR Buffer,
+ OUT unsigned* Errno
+ )
+{
+ return _BlockIo(Handle, Offset, Bytes, Buffer, TRUE, Errno);
+}
+
+
+
+__inline
+BOOLEAN
+_SetPartType(
+ IN HANDLE Handle,
+ IN UCHAR Type
+ )
+{
+ IO_STATUS_BLOCK IoStatusBlock;
+ return STATUS_SUCCESS == NtDeviceIoControlFile(
+ Handle, NULL, NULL, NULL, &IoStatusBlock, IOCTL_DISK_SET_PARTITION_INFO,
+ &Type, sizeof(Type),
+ NULL, 0);
+}
+
+
+
+//--------------------- interface part
+
+//
+// Interface functions.
+// Is_mounted is set to 1 if the device is mounted, 0 otherwise
+//
+
+errcode_t
+ext2fs_check_if_mounted(const char *file, int *mount_flags)
+{
+ HANDLE h;
+ BOOLEAN Readonly;
+
+ *mount_flags = 0;
+
+ if(!_Ext2OpenDevice(file, TRUE, &h, &Readonly, NULL))
+ {
+ return 0;
+ }
+
+
+ __try{
+ *mount_flags &= _IsMounted(h) ? EXT2_MF_MOUNTED : 0;
+ }
+ __finally{
+ _CloseDisk(h);
+ }
+
+ return 0;
+}
+
+
+
+//
+// Returns the number of blocks in a partition
+//
+
+static __int64 FsSize = 0;
+static char knowndevice[1024] = "";
+
+
+errcode_t
+ext2fs_get_device_size(const char *file, int blocksize,
+ blk_t *retblocks)
+{
+ HANDLE h;
+ BOOLEAN Readonly;
+
+ if((0 == FsSize) || (0 != strcmp(knowndevice, file)))
+ {
+
+ if(!_Ext2OpenDevice(file, TRUE, &h, &Readonly, NULL))
+ {
+ return 0;
+ }
+
+
+ __try{
+
+ //
+ // Get size
+ //
+
+ _GetDeviceSize(h, &FsSize);
+ strcpy(knowndevice, file);
+ }
+ __finally{
+ _CloseDisk(h);
+ }
+
+ }
+
+ *retblocks = (blk_t)(unsigned __int64)(FsSize / blocksize);
+ UNREFERENCED_PARAMETER(file);
+ return 0;
+}
+
+
+
+
+
+
+//
+// Table elements
+//
+
+
+static
+errcode_t
+nt_open(const char *name, int flags, io_channel *channel)
+{
+ io_channel io = NULL;
+ PNT_PRIVATE_DATA NtData = NULL;
+ errcode_t Errno = 0;
+
+ //
+ // Check name
+ //
+
+ if (NULL == name)
+ {
+ return EXT2_ET_BAD_DEVICE_NAME;
+ }
+
+ __try{
+
+ //
+ // Allocate channel handle
+ //
+
+ io = (io_channel) malloc(sizeof(struct struct_io_channel));
+
+ if (NULL == io)
+ {
+ Errno = ENOMEM;
+ __leave;
+ }
+
+ RtlZeroMemory(io, sizeof(struct struct_io_channel));
+ io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
+
+ NtData = (PNT_PRIVATE_DATA)malloc(sizeof(NT_PRIVATE_DATA));
+
+ if (NULL == NtData)
+ {
+ Errno = ENOMEM;
+ __leave;
+ }
+
+
+ io->manager = nt_io_manager();
+ io->name = malloc(strlen(name) + 1);
+ if (NULL == io->name)
+ {
+ Errno = ENOMEM;
+ __leave;
+ }
+
+ strcpy(io->name, name);
+ io->private_data = NtData;
+ io->block_size = 1024;
+ io->read_error = 0;
+ io->write_error = 0;
+ io->refcount = 1;
+
+ //
+ // Initialize data
+ //
+
+ RtlZeroMemory(NtData, sizeof(NT_PRIVATE_DATA));
+
+ NtData->magic = EXT2_ET_MAGIC_NT_IO_CHANNEL;
+ NtData->BufferBlockNumber = 0xffffffff;
+ NtData->BufferSize = 1024;
+ NtData->Buffer = malloc(NtData->BufferSize);
+
+ if (NULL == NtData->Buffer)
+ {
+ Errno = ENOMEM;
+ __leave;
+ }
+
+ //
+ // Open it
+ //
+
+ if(!_Ext2OpenDevice(name, (BOOLEAN)!BooleanFlagOn(flags, EXT2_FLAG_RW), &NtData->Handle, &NtData->OpenedReadonly, &Errno))
+ {
+ __leave;
+ }
+
+
+ //
+ // get size
+ //
+
+ _GetDeviceSize(NtData->Handle, &FsSize);
+ strcpy(knowndevice, name);
+
+
+ //
+ // Lock/dismount
+ //
+
+ if(!NT_SUCCESS(_LockDrive(NtData->Handle)) || !NT_SUCCESS(_DismountDrive(NtData->Handle)))
+ {
+ NtData->OpenedReadonly = TRUE;
+ }
+
+ //
+ // Done
+ //
+
+ *channel = io;
+
+
+ }
+ __finally{
+
+ if(0 != Errno)
+ {
+ //
+ // Cleanup
+ //
+
+ if (NULL != io)
+ {
+ if(NULL != io->name)
+ {
+ free(io->name);
+ }
+
+ free(io);
+ }
+
+ if (NULL != NtData)
+ {
+ if(NULL != NtData->Handle)
+ {
+ _UnlockDrive(NtData->Handle);
+ _CloseDisk(NtData->Handle);
+ }
+
+ if(NULL != NtData->Buffer)
+ {
+ free(NtData->Buffer);
+ }
+
+ free(NtData);
+ }
+ }
+ }
+
+ return Errno;
+}
+
+
+//
+// Close api
+//
+
+static
+errcode_t
+nt_close(io_channel channel)
+{
+ PNT_PRIVATE_DATA NtData = NULL;
+
+ if(NULL == channel)
+ {
+ return 0;
+ }
+
+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+ NtData = (PNT_PRIVATE_DATA) channel->private_data;
+ EXT2_CHECK_MAGIC(NtData, EXT2_ET_MAGIC_NT_IO_CHANNEL);
+
+ if (--channel->refcount > 0)
+ {
+ return 0;
+ }
+
+ if(NULL != channel->name)
+ {
+ free(channel->name);
+ }
+
+
+ free(channel);
+
+ if (NULL != NtData)
+ {
+ if(NULL != NtData->Handle)
+ {
+ _DismountDrive(NtData->Handle);
+ _UnlockDrive(NtData->Handle);
+ _CloseDisk(NtData->Handle);
+ }
+
+ if(NULL != NtData->Buffer)
+ {
+ free(NtData->Buffer);
+ }
+
+ free(NtData);
+ }
+
+ return 0;
+}
+
+
+
+//
+// set block size
+//
+
+static
+errcode_t
+nt_set_blksize(io_channel channel, int blksize)
+{
+ PNT_PRIVATE_DATA NtData = NULL;
+
+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+ NtData = (PNT_PRIVATE_DATA) channel->private_data;
+ EXT2_CHECK_MAGIC(NtData, EXT2_ET_MAGIC_NT_IO_CHANNEL);
+
+ if (channel->block_size != blksize)
+ {
+ channel->block_size = blksize;
+
+ free(NtData->Buffer);
+ NtData->BufferBlockNumber = 0xffffffff;
+ NtData->BufferSize = channel->block_size;
+ ASSERT(0 == (NtData->BufferSize % 512));
+
+ NtData->Buffer = malloc(NtData->BufferSize);
+
+ if (NULL == NtData->Buffer)
+ {
+ return ENOMEM;
+ }
+
+ }
+
+ return 0;
+}
+
+
+//
+// read block
+//
+
+static
+errcode_t
+nt_read_blk(io_channel channel, unsigned long block,
+ int count, void *buf)
+{
+ PVOID BufferToRead;
+ ULONG SizeToRead;
+ ULONG Size;
+ LARGE_INTEGER Offset;
+ PNT_PRIVATE_DATA NtData = NULL;
+ unsigned Errno = 0;
+
+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+ NtData = (PNT_PRIVATE_DATA) channel->private_data;
+ EXT2_CHECK_MAGIC(NtData, EXT2_ET_MAGIC_NT_IO_CHANNEL);
+
+ //
+ // If it's in the cache, use it!
+ //
+
+ if ((1 == count) &&
+ (block == NtData->BufferBlockNumber) &&
+ (NtData->BufferBlockNumber != 0xffffffff))
+ {
+ memcpy(buf, NtData->Buffer, channel->block_size);
+ return 0;
+ }
+
+ Size = (count < 0) ? (ULONG)(-count) : (ULONG)(count * channel->block_size);
+
+ Offset.QuadPart = block * channel->block_size;
+
+ //
+ // If not fit to the block
+ //
+
+ if(Size <= NtData->BufferSize)
+ {
+ //
+ // Update the cache
+ //
+
+ NtData->BufferBlockNumber = block;
+ BufferToRead = NtData->Buffer;
+ SizeToRead = NtData->BufferSize;
+ }
+ else
+ {
+ SizeToRead = Size;
+ BufferToRead = buf;
+ ASSERT(0 == (SizeToRead % channel->block_size));
+ }
+
+ if(!_RawRead(NtData->Handle, Offset, SizeToRead, BufferToRead, &Errno))
+ {
+
+ if (channel->read_error)
+ {
+ return (channel->read_error)(channel, block, count, buf,
+ Size, 0, Errno);
+ }
+ else
+ {
+ return Errno;
+ }
+ }
+
+
+ if(BufferToRead != buf)
+ {
+ ASSERT(Size <= SizeToRead);
+ memcpy(buf, BufferToRead, Size);
+ }
+
+ return 0;
+}
+
+
+//
+// write block
+//
+
+static
+errcode_t
+nt_write_blk(io_channel channel, unsigned long block,
+ int count, const void *buf)
+{
+ ULONG SizeToWrite;
+ LARGE_INTEGER Offset;
+ PNT_PRIVATE_DATA NtData = NULL;
+ unsigned Errno = 0;
+
+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+ NtData = (PNT_PRIVATE_DATA) channel->private_data;
+ EXT2_CHECK_MAGIC(NtData, EXT2_ET_MAGIC_NT_IO_CHANNEL);
+
+ if(NtData->OpenedReadonly)
+ {
+ return EACCES;
+ }
+
+ if (count == 1)
+ {
+ SizeToWrite = channel->block_size;
+ }
+ else
+ {
+ NtData->BufferBlockNumber = 0xffffffff;
+
+ if (count < 0)
+ {
+ SizeToWrite = (ULONG)(-count);
+ }
+ else
+ {
+ SizeToWrite = (ULONG)(count * channel->block_size);
+ }
+ }
+
+
+ ASSERT(0 == (SizeToWrite % 512));
+ Offset.QuadPart = block * channel->block_size;
+
+ if(!_RawWrite(NtData->Handle, Offset, SizeToWrite, buf, &Errno))
+ {
+ if (channel->write_error)
+ {
+ return (channel->write_error)(channel, block, count, buf,
+ SizeToWrite, 0, Errno);
+ }
+ else
+ {
+ return Errno;
+ }
+ }
+
+
+ //
+ // Stash a copy.
+ //
+
+ if(SizeToWrite >= NtData->BufferSize)
+ {
+ NtData->BufferBlockNumber = block;
+ memcpy(NtData->Buffer, buf, NtData->BufferSize);
+ }
+
+ NtData->Written = TRUE;
+
+ return 0;
+
+}
+
+
+
+//
+// Flush data buffers to disk. Since we are currently using a
+// write-through cache, this is a no-op.
+//
+
+static
+errcode_t
+nt_flush(io_channel channel)
+{
+ PNT_PRIVATE_DATA NtData = NULL;
+
+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+ NtData = (PNT_PRIVATE_DATA) channel->private_data;
+ EXT2_CHECK_MAGIC(NtData, EXT2_ET_MAGIC_NT_IO_CHANNEL);
+
+ if(NtData->OpenedReadonly)
+ {
+ return 0; // EACCESS;
+ }
+
+
+ //
+ // Flush file buffers.
+ //
+
+ _FlushDrive(NtData->Handle);
+
+
+ //
+ // Test and correct partition type.
+ //
+
+ if(NtData->Written)
+ {
+ _SetPartType(NtData->Handle, 0x83);
+ }
+
+ return 0;
+}
+
+
diff --git a/lib/uuid/ChangeLog b/lib/uuid/ChangeLog
index a913d29..b5536e1 100644
--- a/lib/uuid/ChangeLog
+++ b/lib/uuid/ChangeLog
@@ -1,3 +1,7 @@
+1999-09-24 <tytso@valinux.com>
+
+ * gen_uuid_nt.c: New file which creates a UUID under Windows NT.
+
1999-07-18 Theodore Ts'o <tytso@rsts-11.mit.edu>
* Release of E2fsprogs 1.15
diff --git a/lib/uuid/gen_uuid_nt.c b/lib/uuid/gen_uuid_nt.c
new file mode 100644
index 0000000..56aeecb
--- /dev/null
+++ b/lib/uuid/gen_uuid_nt.c
@@ -0,0 +1,25 @@
+
+
+//
+// Use NT api to generate uuid
+//
+
+
+
+#include "uuidP.h"
+
+
+#pragma comment(lib, "ntdll.lib")
+
+unsigned long
+__stdcall
+NtAllocateUuids(
+ void* p1, // 8 bytes
+ void* p2, // 4 bytes
+ void* p3 // 4 bytes
+ );
+
+void uuid_generate(uuid_t out)
+{
+ NtAllocateUuids(out, ((char*)out)+8, ((char*)out)+12 );
+}