X-Git-Url: https://wimlib.net/git/?a=blobdiff_plain;f=src%2Fntfs-apply.c;h=fc71b9b5aa2055c80eb92a9a155edb63849f8c86;hb=5ed5a1ef610700e463abd0c07aed377cce5eef47;hp=39de5d678d8291761363a57a4804766944e9d7f7;hpb=49f2ae12d9940ab43f9a6df793facb1d8dddf5ea;p=wimlib diff --git a/src/ntfs-apply.c b/src/ntfs-apply.c index 39de5d67..fc71b9b5 100644 --- a/src/ntfs-apply.c +++ b/src/ntfs-apply.c @@ -88,6 +88,7 @@ static int write_ntfs_data_streams(ntfs_inode *ni, const struct wim_dentry *dent unsigned stream_idx = 0; ntfschar *stream_name = AT_UNNAMED; u32 stream_name_len = 0; + const char *stream_name_utf8; const struct wim_inode *inode = dentry->d_inode; struct wim_lookup_table_entry *lte; @@ -99,6 +100,15 @@ static int write_ntfs_data_streams(ntfs_inode *ni, const struct wim_dentry *dent lte = inode->i_lte; while (1) { if (stream_name_len) { + + /* Skip special UNIX data entries (see documentation for + * WIMLIB_ADD_IMAGE_FLAG_UNIX_DATA) */ + if (stream_name_len == WIMLIB_UNIX_DATA_TAG_LEN + && !memcmp(stream_name_utf8, + WIMLIB_UNIX_DATA_TAG, + WIMLIB_UNIX_DATA_TAG_LEN)) + goto cont; + /* Create an empty named stream. */ ret = ntfs_attr_add(ni, AT_DATA, stream_name, stream_name_len, NULL, 0); @@ -148,11 +158,13 @@ static int write_ntfs_data_streams(ntfs_inode *ni, const struct wim_dentry *dent * have been extracted. */ progress_info->extract.completed_bytes += wim_resource_size(lte); } + cont: if (stream_idx == inode->i_num_ads) /* Has the last stream been extracted? */ break; /* Get the name and lookup table entry for the next stream. */ stream_name = (ntfschar*)inode->i_ads_entries[stream_idx].stream_name; + stream_name_utf8 = inode->i_ads_entries[stream_idx].stream_name_utf8; stream_name_len = inode->i_ads_entries[stream_idx].stream_name_len / 2; lte = inode->i_ads_entries[stream_idx].lte; stream_idx++; @@ -198,26 +210,20 @@ static ntfs_inode *dentry_open_parent_ni(const struct wim_dentry *dentry, * existing NTFS inode which already has a name @inode->i_extracted_file. * * The new name is made in the POSIX namespace (this is the behavior of - * ntfs_link()). I am assuming this is an acceptable behavior; however, it's - * possible that the original name was actually in the Win32 namespace. Note - * that the WIM format does not provide enough information to distinguish Win32 - * names from POSIX names in all cases. + * ntfs_link()). * - * Return 0 on success, nonzero on failure. + * Return 0 on success, nonzero on failure. dir_ni is closed either way. */ static int apply_ntfs_hardlink(const struct wim_dentry *from_dentry, const struct wim_inode *inode, - ntfs_inode **dir_ni_p) + ntfs_inode *dir_ni) { int ret; ntfs_inode *to_ni; - ntfs_inode *dir_ni; ntfs_volume *vol; - dir_ni = *dir_ni_p; vol = dir_ni->vol; ret = ntfs_inode_close(dir_ni); - *dir_ni_p = NULL; if (ret != 0) { ERROR_WITH_ERRNO("Error closing directory"); return WIMLIB_ERR_NTFS_3G; @@ -239,12 +245,12 @@ static int apply_ntfs_hardlink(const struct wim_dentry *from_dentry, return WIMLIB_ERR_NTFS_3G; } - *dir_ni_p = dir_ni; - ret = ntfs_link(to_ni, dir_ni, (ntfschar*)from_dentry->file_name, from_dentry->file_name_len / 2); - if (ntfs_inode_close_in_dir(to_ni, dir_ni) || ret != 0) { + ret |= ntfs_inode_close(dir_ni); + ret |= ntfs_inode_close(to_ni); + if (ret) { ERROR_WITH_ERRNO("Could not create hard link `%s' => `%s'", from_dentry->full_path_utf8, inode->i_extracted_file); @@ -344,6 +350,7 @@ static int apply_reparse_data(ntfs_inode *ni, const struct wim_dentry *dentry, u8 reparse_data_buf[8 + wim_resource_size(lte)]; u8 *p = reparse_data_buf; p = put_u32(p, dentry->d_inode->i_reparse_tag); /* ReparseTag */ + DEBUG("ReparseTag = %#x", dentry->d_inode->i_reparse_tag); p = put_u16(p, wim_resource_size(lte)); /* ReparseDataLength */ p = put_u16(p, 0); /* Reserved */ @@ -376,7 +383,6 @@ static int do_apply_dentry_ntfs(struct wim_dentry *dentry, ntfs_inode *dir_ni, int ret = 0; mode_t type; ntfs_inode *ni = NULL; - ntfs_volume *vol = dir_ni->vol; struct wim_inode *inode = dentry->d_inode; dentry->is_extracted = 1; @@ -386,14 +392,13 @@ static int do_apply_dentry_ntfs(struct wim_dentry *dentry, ntfs_inode *dir_ni, type = S_IFREG; if (inode->i_nlink > 1) { /* Inode has multiple dentries referencing it. */ - if (inode->i_extracted_file) { /* Already extracted another dentry in the hard * link group. Make a hard link instead of * extracting the file data. */ - ret = apply_ntfs_hardlink(dentry, inode, - &dir_ni); - goto out_close_dir_ni; + ret = apply_ntfs_hardlink(dentry, inode, dir_ni); + /* dir_ni was closed */ + goto out; } else { /* None of the dentries of this inode have been * extracted yet, so go ahead and extract the @@ -523,76 +528,78 @@ int apply_dentry_ntfs(struct wim_dentry *dentry, void *arg) /* Treat the root dentry specially. */ if (dentry_is_root(dentry)) return apply_root_dentry_ntfs(dentry, vol, w); + /* NTFS filename namespaces need careful consideration. A name for a * NTFS file may be in either the POSIX, Win32, DOS, or Win32+DOS - * namespaces. The following list of assumptions and facts clarify the - * way that WIM dentries are mapped to NTFS files. The statements - * marked ASSUMPTION are statements I am assuming to be true due to the - * lack of documentation; they are verified in verify_dentry() and - * verify_inode() in verify.c. + * namespaces. A NTFS file (a.k.a. inode) may have multiple names in + * multiple directories (i.e. hard links); however, a NTFS file can have + * at most 1 DOS name total. Furthermore, a Win32 name is always + * associated with a DOS name (either as a Win32+DOS name, or a Win32 + * name and a DOS name separately), which implies that a NTFS file can + * have at most 1 Win32 name. * - * - ASSUMPTION: The root WIM dentry has neither a "long name" nor a - * "short name". + * A WIM dentry just contains a "long name", which wimlib makes sure is + * non-empty, and a "short name", which may be empty. So, wimlib must + * map these to the correct NTFS names. wimlib collects all WIM + * dentries that map to the same NTFS inode and factors out the common + * information into a 'struct wim_inode', so this should make the + * mapping a little more obvious. As a NTFS file can have at most 1 DOS + * name, a WIM inode cannot have more than 1 dentry with a non-empty + * short name, and this is checked in the verify_inode() function in + * verify.c. Furthermore, a WIM dentry, if any, that has a DOS name + * must have a long name that corresponds to a Win32 name or Win32+DOS + * name. * - * - ASSUMPTION: Every WIM dentry other than the root directory provides - * a non-empty "long name" and a possibly empty "short name". The - * "short name" corresponds to the DOS name of the file, while the - * "long name" may be Win32 or POSIX. + * WIM dentries that have a long name but no associated short name are + * assumed to be in the POSIX namespace. * - * XXX It may actually be legal to have a short name but no long name + * So, given a WIM inode that is to map to a NTFS inode, we must apply + * the Win32 and DOS or Win32+DOS names, if they exist, then any + * additional (POSIX) names. A caveat when actually doing this: as + * confirmed by the libntfs-3g authors, ntfs_set_ntfs_dos_name() is only + * guaranteed to associate a DOS name with the appropriate long name if + * it's called when that long name is the only one in existence for that + * file. So, this implies that the correct ordering of function calls + * to extract a NTFS file are: * - * - FACT: If a dentry has a "long name" but no "short name", then it is - * ambigious whether the name is POSIX or Win32+DOS, unless the name - * is a valid POSIX name but not a valid Win32+DOS name. wimlib - * currently will always create POSIX names for these files, as this - * is the behavior of the ntfs_create() and ntfs_link() functions. - * - * - FACT: Multiple WIM dentries may correspond to the same underlying - * inode, as provided at this point in the code by the d_inode member. + * if (file has a DOS name) { + * - Call ntfs_create() to create long name associated with + * the DOS name (this initially creates a POSIX name) + * - Call ntfs_set_ntfs_dos_name() to associate a DOS name + * with the long name just created. This either changes + * the POSIX name to Win32+DOS, or changes the POSIX name + * to Win32 and creates a separate DOS name. + * } else { + * - Call ntfs_create() to create the first link to the + * file in the POSIX namespace + * } + * - Call ntfs_link() to create the other names of the file, in the + * POSIX namespace. */ - - - /* Currently wimlib does not apply DOS names to hard linked files due to - * issues with ntfs-3g, so the following is commented out. */ -#if 0 again: - /* - * libntfs-3g requires that for an NTFS inode with a DOS name, the - * corresponding long name be extracted first so that the DOS name is - * associated with the correct long name. Note that by the last - * ASSUMPTION above, a NTFS inode can have at most one DOS name (i.e. a - * WIM inode can have at most one non-empty short name). - * - * Therefore, search for an alias of this dentry that has a short name, - * and extract it first unless it was already extracted. - */ orig_dentry = NULL; - if (!dentry->d_inode->i_dos_name_extracted) { + if (!dentry->d_inode->i_dos_name_extracted && + dentry->short_name_len == 0) + { inode_for_each_dentry(other, dentry->d_inode) { - if (other->short_name_len && other != dentry && - !other->is_extracted) - { + if (other->short_name_len != 0) { orig_dentry = dentry; dentry = other; break; } } - dentry->d_inode->i_dos_name_extracted = 1; } -#endif - + dentry->d_inode->i_dos_name_extracted = 1; ntfs_inode *dir_ni = dentry_open_parent_ni(dentry, vol); - if (dir_ni) + if (dir_ni) { ret = do_apply_dentry_ntfs(dentry, dir_ni, arg); - else + if (ret == 0 && orig_dentry != NULL) { + dentry = orig_dentry; + goto again; + } + } else { ret = WIMLIB_ERR_NTFS_3G; - -#if 0 - if (ret == 0 && orig_dentry) { - dentry = orig_dentry; - goto again; } -#endif return ret; }