add ntfs_link, update ntfsmount to use it

edge.strict_endians
cha0smaster 2005-09-24 15:20:49 +00:00
parent 7fee848c26
commit 464eab4178
3 changed files with 144 additions and 0 deletions

View File

@ -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>)

View File

@ -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;
}

View File

@ -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,