+/* Inserts a new DOS name into the map */
+static int insert_dos_name(struct dos_name_map *map,
+ const ntfschar *dos_name, int name_len,
+ u64 ntfs_ino)
+{
+ struct dos_name_node *new_node;
+ struct rb_node **p;
+ struct rb_root *root;
+ struct rb_node *rb_parent;
+
+ DEBUG("DOS name_len = %d", name_len);
+ new_node = MALLOC(sizeof(struct dos_name_node));
+ if (!new_node)
+ return -1;
+
+ /* DOS names are supposed to be 12 characters max (that's 24 bytes,
+ * assuming 2-byte ntfs characters) */
+ wimlib_assert(name_len * sizeof(ntfschar) <= sizeof(new_node->dos_name));
+
+ /* Initialize the DOS name, DOS name length, and NTFS inode number of
+ * the red-black tree node */
+ memcpy(new_node->dos_name, dos_name, name_len * sizeof(ntfschar));
+ new_node->name_len_bytes = name_len * sizeof(ntfschar);
+ new_node->ntfs_ino = ntfs_ino;
+
+ /* Insert the red-black tree node */
+ root = &map->rb_root;
+ p = &root->rb_node;
+ rb_parent = NULL;
+ while (*p) {
+ struct dos_name_node *this;
+
+ this = container_of(*p, struct dos_name_node, rb_node);
+ rb_parent = *p;
+ if (new_node->ntfs_ino < this->ntfs_ino)
+ p = &((*p)->rb_left);
+ else if (new_node->ntfs_ino > this->ntfs_ino)
+ p = &((*p)->rb_right);
+ else {
+ /* This should be impossible since a NTFS inode cannot
+ * have multiple DOS names, and we only should get each
+ * DOS name entry once from the ntfs_readdir() calls. */
+ ERROR("NTFS inode %"PRIu64" has multiple DOS names",
+ ntfs_ino);
+ return -1;
+ }
+ }
+ rb_link_node(&new_node->rb_node, rb_parent, p);
+ rb_insert_color(&new_node->rb_node, root);
+ DEBUG("Inserted DOS name for inode %"PRIu64, ntfs_ino);
+ return 0;
+}
+
+/* Returns a structure that contains the DOS name and its length for a NTFS
+ * inode, or NULL if the inode has no DOS name. */
+static struct dos_name_node *
+lookup_dos_name(const struct dos_name_map *map, u64 ntfs_ino)
+{
+ struct rb_node *node = map->rb_root.rb_node;
+ while (node) {
+ struct dos_name_node *this;
+ this = container_of(node, struct dos_name_node, rb_node);
+ if (ntfs_ino < this->ntfs_ino)
+ node = node->rb_left;
+ else if (ntfs_ino > this->ntfs_ino)
+ node = node->rb_right;
+ else
+ return this;
+ }
+ return NULL;
+}
+
+static int set_dentry_dos_name(struct wim_dentry *dentry, void *arg)
+{
+ const struct dos_name_map *map = arg;
+ const struct dos_name_node *node;
+
+ if (dentry->is_win32_name) {
+ node = lookup_dos_name(map, dentry->d_inode->i_ino);
+ if (node) {
+ dentry->short_name = MALLOC(node->name_len_bytes);
+ if (!dentry->short_name)
+ return WIMLIB_ERR_NOMEM;
+ memcpy(dentry->short_name, node->dos_name,
+ node->name_len_bytes);
+ dentry->short_name_len = node->name_len_bytes;
+ DEBUG("Assigned DOS name to ino %"PRIu64,
+ dentry->d_inode->i_ino);
+ } else {
+ WARNING("NTFS inode %"PRIu64" has Win32 name with no "
+ "corresponding DOS name",
+ dentry->d_inode->i_ino);
+ }
+ }
+ return 0;
+}
+
+static void free_dos_name_tree(struct rb_node *node) {
+ if (node) {
+ free_dos_name_tree(node->rb_left);
+ free_dos_name_tree(node->rb_right);
+ FREE(container_of(node, struct dos_name_node, rb_node));
+ }
+}
+
+static void destroy_dos_name_map(struct dos_name_map *map)
+{
+ free_dos_name_tree(map->rb_root.rb_node);
+}