diff --git a/ChangeLog b/ChangeLog index 9f3d41ce..7ae30243 100644 --- a/ChangeLog +++ b/ChangeLog @@ -106,6 +106,12 @@ xx/xx/2006 - x.xx.x - . Adapt unix_io pread()/pwrite() device operations to use pread()/ pwrite() system call and adapt win32_io device operations to not supply pread()/pwrite(). (Csaba Henk, Anton) + - mkntfs: Generate a random DCE compliant UUID for the created volume + and include --with-uuid[=PFX] and --without-uuid options. (Anton) + - configure.ac: Set language to C. (Anton) + - mkntfs: Always set default cluster size to 4096 bytes regardless of + volume size. This is what Windows Vista does and it makes perfect + sense from a performance point of view. (Anton) 21/06/2006 - 1.13.1 - Various fixes. diff --git a/configure.ac b/configure.ac index ddded1e8..bea9e751 100644 --- a/configure.ac +++ b/configure.ac @@ -53,6 +53,7 @@ AC_INIT([ntfsprogs],[1.13.2-WIP],[linux-ntfs-dev@lists.sourceforge.net]) LTVERSION_LIBNTFS="10:0:0" AC_SUBST(LTVERSION_LIBNTFS) +AC_LANG([C]) AC_CANONICAL_HOST([]) AC_CANONICAL_TARGET([]) AC_CONFIG_SRCDIR([config.h.in]) @@ -241,6 +242,42 @@ all_includes="$all_includes $USER_INCLUDES" AC_SUBST(all_includes) AC_SUBST(all_libraries) +# Specify support for generating DCE compliant UUIDs (aka GUIDs). We check if +# uuid/uuid.h header is present and the uuid library is present that goes with +# it and then check if uuid_generate() is present and usable. +# +# DCE UUIDs are enabled by default and can be disabled with the --disable-uuid +# option to the configure script. +AC_ARG_WITH(uuid, [ + --with-uuid@<:@=PFX@:>@ generate DCE compliant UUIDs, with optional prefix + to uuid library and headers @<:@default=detect@:>@ + --without-uuid do not generate DCE compliant UUIDs], + if test "$with_uuid" = "yes"; then + extrapath=default + elif test "$with_uuid" = "no"; then + extrapath= + else + extrapath=$with_uuid + fi, + extrapath=default +) +if test "x$extrapath" != "x"; then + if test "x$extrapath" != "xdefault"; then + MKNTFS_CPPFLAGS="$MKNTFS_CPPFLAGS -I$extrapath/include" + MKNTFS_LIBS="$MKNTFS_LIBS -L$extrapath/lib" + fi + AC_CHECK_HEADER([uuid/uuid.h], + AC_CHECK_LIB([uuid], [uuid_generate], + AC_DEFINE([ENABLE_UUID], 1, + [Define this to 1 if you want to enable generation of + DCE compliant UUIDs.]) + MKNTFS_LIBS="$MKNTFS_LIBS -luuid", + AC_MSG_WARN([Linux-NTFS DCE compliant UUID generation code requires the uuid library.]), + ), + AC_MSG_WARN([Linux-NTFS DCE compliant UUID generation code requires the uuid library.]), + ) +fi + # Get compiler name if test ! -z "$CC"; then _cc="$CC" @@ -292,6 +329,9 @@ AC_SUBST(LIBNTFS_CFLAGS) AC_SUBST(LIBNTFS_GNOMEVFS_CFLAGS) AC_SUBST(LIBNTFS_GNOMEVFS_LIBS) +AC_SUBST(MKNTFS_CPPFLAGS) +AC_SUBST(MKNTFS_LIBS) + AC_SUBST(AUTODIRS) # Checks for libraries. diff --git a/include/ntfs/volume.h b/include/ntfs/volume.h index 54ed0b15..61915d07 100644 --- a/include/ntfs/volume.h +++ b/include/ntfs/volume.h @@ -152,6 +152,8 @@ struct _ntfs_volume { u8 major_ver; /* Ntfs major version of volume. */ u8 minor_ver; /* Ntfs minor version of volume. */ u16 flags; /* Bit array of VOLUME_* flags. */ + GUID guid; /* The volume guid if present (otherwise it is + a NULL guid). */ u16 sector_size; /* Byte size of a sector. */ u8 sector_size_bits; /* Log(2) of the byte size of a sector. */ diff --git a/libntfs/dir.c b/libntfs/dir.c index 38c2193c..0343db43 100644 --- a/libntfs/dir.c +++ b/libntfs/dir.c @@ -596,7 +596,6 @@ static const ntfschar dotdot[3] = { const_cpu_to_le16('.'), /** * ntfs_filldir - ntfs specific filldir method - * @dir_ni: ntfs inode of current directory * @pos: current position in directory * @ie: current index entry * @dirent: context for filldir callback supplied by the caller @@ -605,7 +604,7 @@ static const ntfschar dotdot[3] = { const_cpu_to_le16('.'), * Pass information specifying the current directory entry @ie to the @filldir * callback. */ -static int ntfs_filldir(ntfs_inode *dir_ni, s64 *pos, INDEX_ENTRY *ie, +static int ntfs_filldir(s64 *pos, INDEX_ENTRY *ie, void *dirent, ntfs_filldir_t filldir) { FILE_NAME_ATTR *fn = &ie->key.file_name; @@ -857,7 +856,7 @@ int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos, * Submit the directory entry to ntfs_filldir(), which will * invoke the filldir() callback as appropriate. */ - rc = ntfs_filldir(dir_ni, pos, ie, dirent, filldir); + rc = ntfs_filldir(pos, ie, dirent, filldir); if (rc) { ntfs_attr_put_search_ctx(ctx); ctx = NULL; @@ -1018,7 +1017,7 @@ find_next_index_buffer: * Submit the directory entry to ntfs_filldir(), which will * invoke the filldir() callback as appropriate. */ - rc = ntfs_filldir(dir_ni, pos, ie, dirent, filldir); + rc = ntfs_filldir(pos, ie, dirent, filldir); if (rc) goto done; } diff --git a/libntfs/logging.c b/libntfs/logging.c index 6e9a6f43..c3e8bc95 100644 --- a/libntfs/logging.c +++ b/libntfs/logging.c @@ -71,18 +71,20 @@ struct ntfs_logging { /** * ntfs_log - This struct controls all the logging in the library and tools. */ -static struct ntfs_logging ntfs_log = { +static struct ntfs_logging ntfs_log = (struct ntfs_logging) { + .levels = NTFS_LOG_LEVEL_INFO | NTFS_LOG_LEVEL_QUIET | + NTFS_LOG_LEVEL_WARNING | NTFS_LOG_LEVEL_ERROR | + NTFS_LOG_LEVEL_PERROR | NTFS_LOG_LEVEL_CRITICAL | + NTFS_LOG_LEVEL_PROGRESS | #ifdef DEBUG - NTFS_LOG_LEVEL_DEBUG | NTFS_LOG_LEVEL_TRACE | + NTFS_LOG_LEVEL_DEBUG | NTFS_LOG_LEVEL_TRACE | #endif - NTFS_LOG_LEVEL_INFO | NTFS_LOG_LEVEL_QUIET | NTFS_LOG_LEVEL_WARNING | - NTFS_LOG_LEVEL_ERROR | NTFS_LOG_LEVEL_PERROR | NTFS_LOG_LEVEL_CRITICAL | - NTFS_LOG_LEVEL_PROGRESS, - NTFS_LOG_FLAG_ONLYNAME, + 0, + .flags = NTFS_LOG_FLAG_ONLYNAME, #ifdef DEBUG - ntfs_log_handler_outerr + .handler = ntfs_log_handler_outerr, #else - ntfs_log_handler_null + .handler = ntfs_log_handler_null, #endif }; @@ -343,8 +345,10 @@ int ntfs_log_redirect(const char *function, const char *file, #ifdef HAVE_SYSLOG_H int ntfs_log_handler_syslog(const char *function __attribute__((unused)), - const char *file, __attribute__((unused)) int line, u32 level, - void *data __attribute__((unused)), const char *format, va_list args) + const char *file, int line __attribute__((unused)), + u32 level __attribute__((unused)), + void *data __attribute__((unused)), const char *format, + va_list args) { int ret = 0; int olderr = errno; diff --git a/ntfsprogs/.cvsignore b/ntfsprogs/.cvsignore index d31d1c5a..fdb0f809 100644 --- a/ntfsprogs/.cvsignore +++ b/ntfsprogs/.cvsignore @@ -4,6 +4,7 @@ Makefile Makefile.in mkntfs ntfscat +ntfsck ntfsclone ntfscluster ntfscmp diff --git a/ntfsprogs/Makefile.am b/ntfsprogs/Makefile.am index 17f3902b..398a7917 100644 --- a/ntfsprogs/Makefile.am +++ b/ntfsprogs/Makefile.am @@ -44,8 +44,9 @@ ntfsfix_SOURCES = ntfsfix.c utils.c utils.h ntfsfix_LDADD = $(AM_LIBS) ntfsfix_LDFLAGS = $(AM_LFLAGS) +mkntfs_CPPFLAGS = $(AM_CPPFLAGS) $(MKNTFS_CPPFLAGS) mkntfs_SOURCES = attrdef.c attrdef.h upcase.c upcase.h boot.c boot.h sd.c sd.h mkntfs.c utils.c utils.h -mkntfs_LDADD = $(AM_LIBS) +mkntfs_LDADD = $(AM_LIBS) $(MKNTFS_LIBS) mkntfs_LDFLAGS = $(AM_LFLAGS) ntfslabel_SOURCES = ntfslabel.c utils.c utils.h diff --git a/ntfsprogs/mkntfs.8.in b/ntfsprogs/mkntfs.8.in index 38c13021..69ecd9e1 100644 --- a/ntfsprogs/mkntfs.8.in +++ b/ntfsprogs/mkntfs.8.in @@ -127,20 +127,7 @@ Enable compression on the volume. Specify the size of clusters in bytes. Valid cluster size values are powers of two, with at least 256, and at most 65536 bytes per cluster. If omitted, .B mkntfs -determines the -.I cluster\-size -from the volume size. The value is determined as follows: -.TS -box; -lB lB lB -l l r. -Volume size Default cluster size -0 \- 512MB 512 bytes -512MB \- 1GB 1024 bytes -1GB \- 2GB 2048 bytes -2GB + 4096 bytes -.TE -.sp +uses 4096 bytes as the default cluster size. .sp Note that the default cluster size is set to be at least equal to the sector size as a cluster cannot be smaller than a sector. Also, note that values @@ -150,7 +137,7 @@ by Windows). .TP \fB\-N\fR, \fB\-\-ntfs\-version\fR STRING Select the version of NTFS you wish to create. This can be "1.2" -(Windows NT 4.0) or "3.1" (Windows XP, Server 2003 and Vista). +(Windows NT 4.0) or "3.1" (Windows XP, Server 2003, and Vista). Versions are upwards compatible and Windows 2000, which uses version "3.0", can read/write both. diff --git a/ntfsprogs/mkntfs.c b/ntfsprogs/mkntfs.c index 70904b2f..967362e5 100644 --- a/ntfsprogs/mkntfs.c +++ b/ntfsprogs/mkntfs.c @@ -81,6 +81,10 @@ #ifdef HAVE_LIBGEN_H #include #endif +#ifdef ENABLE_UUID +#include +#endif + #ifdef HAVE_GETOPT_H #include @@ -2083,6 +2087,34 @@ static int add_attr_file_name(MFT_RECORD *m, const MFT_REF parent_dir, return i; } +#ifdef ENABLE_UUID + +/** + * add_attr_object_id - + * + * Note we insert only a basic object id which only has the GUID and none of + * the extended fields. This is because we currently only use this function + * when creating the object id for the volume. + * + * Return 0 on success or -errno on error. + */ +static int add_attr_object_id(MFT_RECORD *m, const GUID *object_id) +{ + OBJECT_ID_ATTR oi; + int err; + + oi = (OBJECT_ID_ATTR) { + .object_id = *object_id, + }; + err = insert_resident_attr_in_mft_record(m, AT_OBJECT_ID, NULL, + 0, 0, 0, 0, (u8*)&oi, sizeof(oi.object_id)); + if (err < 0) + ntfs_log_error("add_attr_vol_info failed: %s\n", strerror(-err)); + return err; +} + +#endif + /** * add_attr_sd * @@ -2754,9 +2786,8 @@ do_next: idx_entry = (INDEX_ENTRY*)((u8*)idx_entry + le16_to_cpu(idx_entry->length)); } - } else { + } else return -EINVAL; - } memmove((u8*)idx_entry + idx_size, (u8*)idx_entry, le32_to_cpu(m->bytes_in_use) - ((u8*)idx_entry - (u8*)m)); @@ -3300,6 +3331,56 @@ static int create_hardlink(INDEX_BLOCK *idx, const MFT_REF ref_parent, return 0; } +#ifdef ENABLE_UUID + +/** + * index_obj_id_insert + * + * Insert an index entry with the key @guid and data pointing to the mft record + * @ref in the $O index root of the mft record @m (which must be the mft record + * for $ObjId). + * + * Return 0 on success or -errno on error. + */ +static int index_obj_id_insert(MFT_RECORD *m, const GUID *guid, + const MFT_REF ref) +{ + INDEX_ENTRY *idx_entry_new; + int data_ofs, idx_size, err; + OBJ_ID_INDEX_DATA *oi; + + /* + * Insert the index entry for the object id in the index. + * + * First determine the size of the index entry to be inserted. This + * consists of the index entry header, followed by the index key, i.e. + * the GUID, followed by the index data, i.e. OBJ_ID_INDEX_DATA. + */ + data_ofs = (sizeof(INDEX_ENTRY_HEADER) + sizeof(GUID) + 7) & ~7; + idx_size = (data_ofs + sizeof(OBJ_ID_INDEX_DATA) + 7) & ~7; + idx_entry_new = ntfs_calloc(idx_size); + if (!idx_entry_new) + return -errno; + idx_entry_new->data_offset = cpu_to_le16(data_ofs); + idx_entry_new->data_length = cpu_to_le16(sizeof(OBJ_ID_INDEX_DATA)); + idx_entry_new->length = cpu_to_le16(idx_size); + idx_entry_new->key_length = cpu_to_le16(sizeof(GUID)); + idx_entry_new->key.object_id = *guid; + oi = (OBJ_ID_INDEX_DATA*)((u8*)idx_entry_new + data_ofs); + oi->mft_reference = ref; + err = insert_index_entry_in_res_dir_index(idx_entry_new, idx_size, m, + NTFS_INDEX_O, 2, AT_UNUSED); + free(idx_entry_new); + if (err < 0) { + ntfs_log_error("index_obj_id_insert failed inserting index " + "entry: %s\n", strerror(-err)); + return err; + } + return 0; +} + +#endif + /** * mkntfs_cleanup */ @@ -3593,14 +3674,11 @@ static BOOL mkntfs_override_vol_params(ntfs_volume *vol) ntfs_log_debug("volume size = %llikiB\n", volume_size / 1024); /* If user didn't specify the cluster size, determine it now. */ if (!vol->cluster_size) { - if (volume_size <= 512LL << 20) /* <= 512MB */ - vol->cluster_size = 512; - else if (volume_size <= 1LL << 30) /* ]512MB-1GB] */ - vol->cluster_size = 1024; - else if (volume_size <= 2LL << 30) /* ]1GB-2GB] */ - vol->cluster_size = 2048; - else - vol->cluster_size = 4096; + /* + * Windows Vista always uses 4096 bytes as the default cluster + * size regardless of the volume size so we do it, too. + */ + vol->cluster_size = 4096; /* For small volumes on devices with large sector sizes. */ if (vol->cluster_size < (u32)opts.sector_size) vol->cluster_size = opts.sector_size; @@ -4192,11 +4270,16 @@ static BOOL mkntfs_sync_index_record(INDEX_ALLOCATION* idx, MFT_RECORD* m, return TRUE; } - /** * create_file_volume - */ -static BOOL create_file_volume(MFT_RECORD *m, MFT_REF root_ref, VOLUME_FLAGS fl) +static BOOL create_file_volume(MFT_RECORD *m, MFT_REF root_ref, + VOLUME_FLAGS fl + , const GUID *volume_guid +#ifndef ENABLE_UUID + __attribute__((unused)) +#endif + ) { int i, err; u8 *sd; @@ -4216,14 +4299,21 @@ static BOOL create_file_volume(MFT_RECORD *m, MFT_REF root_ref, VOLUME_FLAGS fl) if (!err) err = add_attr_vol_name(m, g_vol->vol_name, g_vol->vol_name ? strlen(g_vol->vol_name) : 0); +#ifdef ENABLE_UUID + if (!err) + err = add_attr_object_id(m, volume_guid); +#endif if (!err) { if (fl & VOLUME_IS_DIRTY) - ntfs_log_quiet("Setting the volume dirty so check disk runs " - "on next reboot into Windows.\n"); - err = add_attr_vol_info(m, fl, g_vol->major_ver, g_vol->minor_ver); + ntfs_log_quiet("Setting the volume dirty so check " + "disk runs on next reboot into " + "Windows.\n"); + err = add_attr_vol_info(m, fl, g_vol->major_ver, + g_vol->minor_ver); } if (err < 0) { - ntfs_log_error("Couldn't create $Volume: %s\n", strerror(-err)); + ntfs_log_error("Couldn't create $Volume: %s\n", + strerror(-err)); return FALSE; } return TRUE; @@ -4672,7 +4762,11 @@ static BOOL mkntfs_create_root_structures(void) volume_flags |= VOLUME_IS_DIRTY; } free(bs); - if (!create_file_volume(m, root_ref, volume_flags)) +#ifdef ENABLE_UUID + /* Generate a GUID for the volume. */ + uuid_generate((void*)&g_vol->guid); +#endif + if (!create_file_volume(m, root_ref, volume_flags, &g_vol->guid)) return FALSE; ntfs_log_verbose("Creating $BadClus (mft record 8)\n"); m = (MFT_RECORD*)(g_buf + 8 * g_vol->mft_record_size); @@ -4768,7 +4862,7 @@ static BOOL mkntfs_create_root_structures(void) if (!err) err = initialize_secure(buf_sds_init, buf_sds_first_size, m); - free (buf_sds_init); + free(buf_sds_init); buf_sds_init = NULL; if (err < 0) { ntfs_log_error("Couldn't create $Secure: %s\n", @@ -4882,7 +4976,6 @@ static BOOL mkntfs_create_root_structures(void) ntfs_log_error("Couldn't create $Quota: %s\n", strerror(-err)); return FALSE; } - ntfs_log_verbose("Creating $ObjId (mft record 25)\n"); m = (MFT_RECORD*)(g_buf + 25 * g_vol->mft_record_size); m->flags |= MFT_RECORD_IS_4; @@ -4897,12 +4990,18 @@ static BOOL mkntfs_create_root_structures(void) /* FIXME: This should be IGNORE_CASE */ if (!err) err = add_attr_index_root(m, "$O", 2, 0, AT_UNUSED, - COLLATION_NTOFS_ULONGS, g_vol->indx_record_size); + COLLATION_NTOFS_ULONGS, + g_vol->indx_record_size); +#ifdef ENABLE_UUID + if (!err) + err = index_obj_id_insert(m, &g_vol->guid, + MK_LE_MREF(FILE_Volume, FILE_Volume)); +#endif if (err < 0) { - ntfs_log_error("Couldn't create $ObjId: %s\n", strerror(-err)); + ntfs_log_error("Couldn't create $ObjId: %s\n", + strerror(-err)); return FALSE; } - ntfs_log_verbose("Creating $Reparse (mft record 26)\n"); m = (MFT_RECORD*)(g_buf + 26 * g_vol->mft_record_size); m->flags |= MFT_RECORD_IS_4; diff --git a/ntfsprogs/ntfsclone.c b/ntfsprogs/ntfsclone.c index 423ac154..dac19f30 100644 --- a/ntfsprogs/ntfsclone.c +++ b/ntfsprogs/ntfsclone.c @@ -1717,7 +1717,7 @@ static void check_dest_free_space(u64 src_bytes) { u64 dest_bytes; struct statvfs stvfs; - struct stat stat; + struct stat st; if (opt.metadata || opt.blkdev_out || opt.std_out) return; @@ -1732,8 +1732,8 @@ static void check_dest_free_space(u64 src_bytes) } /* If file is a FIFO then there is no point in checking the size. */ - if (!fstat(fd_out, &stat)) { - if (S_ISFIFO(stat.st_mode)) + if (!fstat(fd_out, &st)) { + if (S_ISFIFO(st.st_mode)) return; } else Printf("WARNING: fstat failed: %s\n", strerror(errno));