/* Recursively creates all the subdirectories of @dir, which has been created as * the NTFS inode @dir_ni. */ static int ntfs_3g_create_dirs_recursive(ntfs_inode *dir_ni, struct wim_dentry *dir, struct ntfs_3g_apply_ctx *ctx) { struct wim_dentry *child; for_dentry_child(child, dir) { ntfs_inode *ni; int ret; if (!(child->d_inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY)) continue; if (!will_extract_dentry(child)) continue; ni = ntfs_create(dir_ni, 0, child->d_extraction_name, child->d_extraction_name_nchars, S_IFDIR); if (!ni) { ERROR_WITH_ERRNO("Error creating \"%s\" in NTFS volume", dentry_full_path(child)); return WIMLIB_ERR_NTFS_3G; } child->d_inode->i_mft_no = ni->mft_no; ret = report_file_created(&ctx->common); if (!ret) ret = ntfs_3g_set_metadata(ni, child->d_inode, ctx); if (!ret) ret = ntfs_3g_create_any_empty_ads(ni, child->d_inode, ctx); if (!ret) ret = ntfs_3g_create_dirs_recursive(ni, child, ctx); if (ntfs_inode_close_in_dir(ni, dir_ni) && !ret) { ERROR_WITH_ERRNO("Error closing \"%s\" in NTFS volume", dentry_full_path(child)); ret = WIMLIB_ERR_NTFS_3G; } if (ret) return ret; }
ntfs_inode *ntfsCreate (ntfs_vd *vd, const char *path, mode_t type, const char *target) { ntfs_inode *dir_ni = NULL, *ni = NULL; char *dir = NULL; char *name = NULL; ntfschar *uname = NULL, *utarget = NULL; int uname_len, utarget_len; // Sanity check if (!vd) { errno = ENODEV; return NULL; } // You cannot link between devices if(target) { if(vd != ntfsGetVolume(target)) { errno = EXDEV; return NULL; } } // Get the actual paths of the entry path = ntfsRealPath(path); target = ntfsRealPath(target); if (!path) { errno = EINVAL; return NULL; } // Lock ntfsLock(vd); // Get the unicode name for the entry and find its parent directory // TODO: This looks horrible, clean it up dir = strdup(path); if (!dir) { errno = EINVAL; goto cleanup; } name = strrchr(dir, '/'); if (name) name++; else name = dir; uname_len = ntfsLocalToUnicode(name, &uname); if (uname_len < 0) { errno = EINVAL; goto cleanup; } name = strrchr(dir, '/'); if(name) { name++; name[0] = 0; } // Open the entries parent directory dir_ni = ntfsOpenEntry(vd, dir); if (!dir_ni) { goto cleanup; } // Create the entry switch (type) { // Symbolic link case S_IFLNK: if (!target) { errno = EINVAL; goto cleanup; } utarget_len = ntfsLocalToUnicode(target, &utarget); if (utarget_len < 0) { errno = EINVAL; goto cleanup; } ni = ntfs_create_symlink(dir_ni, 0, uname, uname_len, utarget, utarget_len); break; // Directory or file case S_IFDIR: case S_IFREG: ni = ntfs_create(dir_ni, 0, uname, uname_len, type); break; } // If the entry was created if (ni) { // Mark the entry for archiving ni->flags |= FILE_ATTR_ARCHIVE; // Mark the entry as dirty NInoSetDirty(ni); // Sync the entry to disc ntfsSync(vd, ni); // Update parent directories times ntfsUpdateTimes(vd, dir_ni, NTFS_UPDATE_MCTIME); } cleanup: if(dir_ni) ntfsCloseEntry(vd, dir_ni); // use free because the value was not allocated with ntfs_alloc if(utarget) free(utarget); if(uname) free(uname); if(dir) ntfs_free(dir); // Unlock ntfsUnlock(vd); return ni; }