add ntfs_link, update ntfsmount to use it
parent
7fee848c26
commit
464eab4178
|
@ -44,6 +44,8 @@ extern ntfs_inode *ntfs_create(ntfs_inode *dir_ni, ntfschar *name, u8 name_len,
|
|||
const unsigned type);
|
||||
extern int ntfs_delete(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name,
|
||||
u8 name_len);
|
||||
extern int ntfs_link(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name,
|
||||
u8 name_len);
|
||||
|
||||
/*
|
||||
* File types (adapted from include <linux/fs.h>)
|
||||
|
|
|
@ -1406,3 +1406,96 @@ err_out:
|
|||
err = errno;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_link - create hard link for file or directory
|
||||
* @ni: ntfs inode for object to create hard link
|
||||
* @dir_ni: ntfs inode for directory in which new link should be placed
|
||||
* @name: unicode name of the new link
|
||||
* @name_len: length of the name in unicode characters
|
||||
*
|
||||
* Return 0 on success or -1 on error with errno set to the error code.
|
||||
*/
|
||||
int ntfs_link(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name, u8 name_len)
|
||||
{
|
||||
FILE_NAME_ATTR *fn = NULL;
|
||||
int fn_len, err;
|
||||
|
||||
ntfs_debug("Entering.");
|
||||
if (!ni || !dir_ni || !name || !name_len) {
|
||||
err = errno;
|
||||
ntfs_error(, "Invalid arguments.");
|
||||
goto err_out;
|
||||
}
|
||||
/* Create FILE_NAME attribute. */
|
||||
fn_len = sizeof(FILE_NAME_ATTR) + name_len * sizeof(ntfschar);
|
||||
fn = calloc(1, fn_len);
|
||||
if (!fn) {
|
||||
err = errno;
|
||||
ntfs_error(, "Not enough memory.");
|
||||
goto err_out;
|
||||
}
|
||||
fn->parent_directory = MK_LE_MREF(dir_ni->mft_no,
|
||||
le16_to_cpu(dir_ni->mrec->sequence_number));
|
||||
fn->file_name_length = name_len;
|
||||
fn->file_name_type = FILE_NAME_POSIX;
|
||||
if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
|
||||
fn->file_attributes = FILE_ATTR_DUP_FILE_NAME_INDEX_PRESENT;
|
||||
fn->creation_time = utc2ntfs(ni->creation_time);
|
||||
fn->last_data_change_time = utc2ntfs(ni->last_data_change_time);
|
||||
fn->last_mft_change_time = utc2ntfs(ni->last_mft_change_time);
|
||||
fn->last_access_time = utc2ntfs(ni->last_access_time);
|
||||
memcpy(fn->file_name, name, name_len * sizeof(ntfschar));
|
||||
/* Add FILE_NAME attribute to index. */
|
||||
if (ntfs_index_add_filename(dir_ni, fn, MK_MREF(ni->mft_no,
|
||||
le16_to_cpu(ni->mrec->sequence_number)))) {
|
||||
err = errno;
|
||||
ntfs_error(, "Failed to add entry to the index.");
|
||||
goto err_out;
|
||||
}
|
||||
/* Add FILE_NAME attribute to inode. */
|
||||
if (ntfs_attr_add(ni, AT_FILE_NAME, AT_UNNAMED, 0, (u8*)fn, fn_len)) {
|
||||
ntfs_index_context *ictx;
|
||||
|
||||
err = errno;
|
||||
ntfs_error(, "Failed to add FILE_NAME attribute.");
|
||||
/* Try to remove just added attribute from index. */
|
||||
ictx = ntfs_index_ctx_get(dir_ni, I30, 4);
|
||||
if (!ictx)
|
||||
goto rollback_failed;
|
||||
if (ntfs_index_lookup(fn, fn_len, ictx)) {
|
||||
ntfs_index_ctx_put(ictx);
|
||||
goto rollback_failed;
|
||||
}
|
||||
if (ntfs_index_rm(ictx)) {
|
||||
ntfs_index_ctx_put(ictx);
|
||||
goto rollback_failed;
|
||||
}
|
||||
goto err_out;
|
||||
}
|
||||
/* Increment hard links count. */
|
||||
ni->mrec->link_count = cpu_to_le16(le16_to_cpu(
|
||||
ni->mrec->link_count) + 1);
|
||||
/*
|
||||
* Do not set attributes and file size, instead of this mark filenames
|
||||
* dirty to force attribute and size update during sync.
|
||||
* NOTE: File size may will be not updated and not all attributes will
|
||||
* be set, but it is acceptable since windows driver does not update
|
||||
* all file names when one of the hard links changed.
|
||||
* FIXME: It will be nice to update them all.
|
||||
*/
|
||||
NInoFileNameSetDirty(ni);
|
||||
/* Done! */
|
||||
ntfs_inode_mark_dirty(ni);
|
||||
free(fn);
|
||||
ntfs_debug("Done.");
|
||||
return 0;
|
||||
rollback_failed:
|
||||
ntfs_error(, "Rollback failed. Leaving inconsist metadata.");
|
||||
err_out:
|
||||
ntfs_error(, "Failed.");
|
||||
if (fn)
|
||||
free(fn);
|
||||
errno = err;
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -628,6 +628,54 @@ static int ntfs_fuse_mknod(const char *org_path, mode_t mode,
|
|||
return res;
|
||||
}
|
||||
|
||||
static int ntfs_fuse_link(const char *old_path, const char *new_path)
|
||||
{
|
||||
char *name;
|
||||
ntfschar *uname = NULL;
|
||||
ntfs_inode *dir_ni = NULL, *ni;
|
||||
char *path;
|
||||
int res = 0, uname_len;
|
||||
|
||||
path = strdup(new_path);
|
||||
if (!path)
|
||||
return -errno;
|
||||
/* Open file for which create hard link. */
|
||||
ni = ntfs_pathname_to_inode(ctx->vol, NULL, old_path);
|
||||
if (!ni) {
|
||||
res = -errno;
|
||||
goto exit;
|
||||
}
|
||||
/* Generate unicode filename. */
|
||||
name = strrchr(path, '/');
|
||||
name++;
|
||||
uname_len = ntfs_mbstoucs(name, &uname, 0);
|
||||
if (uname_len < 0) {
|
||||
res = -errno;
|
||||
goto exit;
|
||||
}
|
||||
/* Open parent directory. */
|
||||
*name = 0;
|
||||
dir_ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
|
||||
if (!dir_ni) {
|
||||
res = -errno;
|
||||
if (res == -ENOENT)
|
||||
res = -EIO;
|
||||
goto exit;
|
||||
}
|
||||
/* Create hard link. */
|
||||
if (ntfs_link(ni, dir_ni, uname, uname_len))
|
||||
res = -errno;
|
||||
exit:
|
||||
if (ni)
|
||||
ntfs_inode_close(ni);
|
||||
if (uname)
|
||||
free(uname);
|
||||
if (dir_ni)
|
||||
ntfs_inode_close(dir_ni);
|
||||
free(path);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int ntfs_fuse_rm(const char *org_path)
|
||||
{
|
||||
char *name;
|
||||
|
@ -1042,6 +1090,7 @@ static struct fuse_operations ntfs_fuse_oper = {
|
|||
.statfs = ntfs_fuse_statfs,
|
||||
.chmod = ntfs_fuse_chmod,
|
||||
.mknod = ntfs_fuse_mknod,
|
||||
.link = ntfs_fuse_link,
|
||||
.unlink = ntfs_fuse_unlink,
|
||||
.mkdir = ntfs_fuse_mkdir,
|
||||
.rmdir = ntfs_fuse_rmdir,
|
||||
|
|
Loading…
Reference in New Issue