NTFS:Critical fixes for renaming and creating nodes. The adaptation of some functions to the new version of the libntfs3g.

This commit is contained in:
threedeyes
2012-10-22 10:13:02 +00:00
parent 3cd9a30037
commit c0c445f1f4
+247 -258
View File
@@ -113,6 +113,176 @@ get_node_type(ntfs_inode* ni, int* _type)
}
static u64
ntfs_inode_lookup(fs_volume *_vol, ino_t parent, const char *name)
{
nspace *ns = (nspace*)_vol->private_volume;
u64 ino = (u64)-1;
u64 inum;
ntfs_inode *dir_ni;
/* Open target directory. */
dir_ni = ntfs_inode_open(ns->ntvol, parent);
if (dir_ni) {
/* Lookup file */
inum = ntfs_inode_lookup_by_mbsname(dir_ni, name);
/* never return inodes 0 and 1 */
if (MREF(inum) <= 1) {
inum = (u64)-1;
errno = ENOENT;
}
if (ntfs_inode_close(dir_ni)
|| (inum == (u64)-1))
ino = (u64)-1;
else
ino = MREF(inum);
}
return (ino);
}
static int
ntfs_remove(fs_volume *_vol, ino_t parent, const char *name)
{
nspace *ns = (nspace*)_vol->private_volume;
ntfschar *uname = NULL;
ntfs_inode *dir_ni = NULL, *ni = NULL;
int res = B_OK, uname_len;
u64 iref;
/* Open parent directory. */
dir_ni = ntfs_inode_open(ns->ntvol, parent);
if (!dir_ni) {
res = EINVAL;
goto exit;
}
/* Generate unicode filename. */
uname_len = ntfs_mbstoucs(name, &uname);
if (uname_len < 0) {
res = EINVAL;
goto exit;
}
/* Open object for delete. */
iref = ntfs_inode_lookup_by_mbsname(dir_ni, name);
if (iref == (u64)-1) {
res = EINVAL;
goto exit;
}
/* deny unlinking metadata files */
if (MREF(iref) < FILE_first_user) {
res = EINVAL;
goto exit;
}
ni = ntfs_inode_open(ns->ntvol, MREF(iref));
if (!ni) {
res = EINVAL;
goto exit;
}
if (ntfs_delete(ns->ntvol, (char*)NULL, ni, dir_ni, uname, uname_len))
res = EINVAL;
/* ntfs_delete() always closes ni and dir_ni */
ni = dir_ni = NULL;
exit:
if (ni)
ntfs_inode_close(ni);
if (dir_ni)
ntfs_inode_close(dir_ni);
free(uname);
return res;
}
static status_t
do_unlink(fs_volume *_vol, vnode *dir, const char *name, bool isdir)
{
nspace *ns = (nspace*)_vol->private_volume;
ino_t vnid;
vnode *node = NULL;
ntfs_inode *ni = NULL;
ntfs_inode *bi = NULL;
ntfschar *uname = NULL;
int unameLength;
status_t result = B_NO_ERROR;
unameLength = ntfs_mbstoucs(name, &uname);
if (unameLength < 0) {
result = EINVAL;
goto exit1;
}
bi = ntfs_inode_open(ns->ntvol, dir->vnid);
if (bi == NULL) {
result = ENOENT;
goto exit1;
}
vnid = MREF(ntfs_inode_lookup_by_name(bi, uname, unameLength));
if ( vnid == (u64)-1 || vnid == FILE_root) {
result = EINVAL;
goto exit1;
}
result = get_vnode(_vol, vnid, (void**)&node);
if (result != B_NO_ERROR || node==NULL) {
result = ENOENT;
goto exit1;
}
ni = ntfs_inode_open(ns->ntvol, node->vnid);
if (ni == NULL) {
result = ENOENT;
goto exit2;
}
if (isdir) {
if (!(ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)) {
result = ENOTDIR;
goto exit2;
}
if (ntfs_check_empty_dir(ni)<0) {
result = ENOTEMPTY;
goto exit2;
}
} else if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) {
result = EISDIR;
goto exit2;
}
// TODO: the file must not be deleted here, only unlinked!
if (ntfs_delete(ns->ntvol, (char*)NULL, ni, bi, uname, unameLength))
result = errno;
ni = bi = NULL;
node->parent_vnid = dir->vnid;
notify_entry_removed(ns->id, dir->vnid, name, vnid);
remove_vnode(_vol, vnid);
result = 0;
exit2:
put_vnode(_vol, vnid);
exit1:
free(uname);
if (ni)
ntfs_inode_close(ni);
if (bi)
ntfs_inode_close(bi);
return result;
}
void
fs_ntfs_update_times(fs_volume *vol, ntfs_inode *ni,
ntfs_time_update_flags mask)
@@ -964,8 +1134,6 @@ fs_create(fs_volume *_vol, fs_vnode *_dir, const char *name, int omode,
le32 securid = const_cpu_to_le32(0);
ni = ntfs_create(bi, securid, uname, unameLength, S_IFREG);
if (ni) {
NInoSetDirty(ni);
*_vnid = MREF(ni->mft_no);
newNode = (vnode*)ntfs_calloc(sizeof(vnode));
@@ -983,13 +1151,16 @@ fs_create(fs_volume *_vol, fs_vnode *_dir, const char *name, int omode,
newNode->parent_vnid = MREF(bi->mft_no);
set_mime(newNode, name);
ni->flags |= FILE_ATTR_ARCHIVE;
ntfs_inode_update_mbsname(bi, name, ni->mft_no);
NInoSetDirty(ni);
result = B_NO_ERROR;
result = publish_vnode(_vol, *_vnid, (void*)newNode, &gNTFSVnodeOps,
S_IFREG, 0);
ntfs_mark_free_space_outdated(ns);
fs_ntfs_update_times(_vol, bi, NTFS_UPDATE_MCTIME);
ntfs_mark_free_space_outdated(ns);
fs_ntfs_update_times(_vol, bi, NTFS_UPDATE_MCTIME);
notify_entry_created(ns->id, MREF(bi->mft_no), name, *_vnid);
} else
result = errno;
@@ -1470,8 +1641,6 @@ fs_mkdir(fs_volume *_vol, fs_vnode *_dir, const char *name, int perms)
ni = ntfs_create(bi, securid, uname, unameLength, S_IFDIR);
if (ni) {
ino_t vnid = MREF(ni->mft_no);
NInoSetDirty(ni);
newNode = (vnode*)ntfs_calloc(sizeof(vnode));
if (newNode == NULL) {
@@ -1487,6 +1656,10 @@ fs_mkdir(fs_volume *_vol, fs_vnode *_dir, const char *name, int perms)
newNode->vnid = vnid;
newNode->parent_vnid = MREF(bi->mft_no);
set_mime(newNode, ".***");
ni->flags |= FILE_ATTR_ARCHIVE;
ntfs_inode_update_mbsname(bi, name, ni->mft_no);
NInoSetDirty(ni);
result = publish_vnode(_vol, vnid, (void*)newNode, &gNTFSVnodeOps,
S_IFDIR, 0);
@@ -1513,30 +1686,24 @@ exit:
status_t
fs_rename(fs_volume *_vol, fs_vnode *_odir, const char *oldname,
fs_rename(fs_volume *_vol, fs_vnode *_odir, const char *name,
fs_vnode *_ndir, const char *newname)
{
nspace *ns = (nspace*)_vol->private_volume;
vnode *odir = (vnode*)_odir->private_node;
vnode *ndir = (vnode*)_ndir->private_node;
vnode *file = NULL;
ino_t parent = odir->vnid;
ino_t newparent = ndir->vnid;
vnode *onode = NULL;
vnode *nnode = NULL;
ino_t ino, xino;
ino_t ovnid, nvnid;
ntfs_inode *oi = NULL;
ntfs_inode *ndi = NULL;
ntfs_inode *odi = NULL;
ntfschar *unewname = NULL;
ntfschar *uoldname = NULL;
int unewnameLength;
int uoldnameLength;
ntfs_inode *ni = NULL;
ntfs_inode *dir_ni = NULL;
status_t result = B_NO_ERROR;
char path[MAX_PATH];
if (ns->flags & B_FS_IS_READONLY) {
ERROR("ntfs is read-only\n");
@@ -1545,156 +1712,70 @@ fs_rename(fs_volume *_vol, fs_vnode *_odir, const char *oldname,
LOCK_VOL(ns);
TRACE("fs_rename - oldname:%s newname:%s\n", oldname, newname);
// convert names from utf8 to unicode string
unewnameLength = ntfs_mbstoucs(newname, &unewname);
if (unewnameLength < 0) {
TRACE("NTFS:fs_rename - oldname:%s newname:%s\n", name, newname);
ino = ntfs_inode_lookup(_vol, parent, name);
if (ino == (u64)-1) {
result = EINVAL;
goto exit;
goto exit;
}
/* Check whether target is present */
xino = ntfs_inode_lookup(_vol, newparent, newname);
if (xino == (u64)-1) {
ntfschar *uname = NULL;
int uname_len;
uoldnameLength = ntfs_mbstoucs(oldname, &uoldname);
if (uoldnameLength < 0) {
result = get_vnode(_vol, ino, (void**)&file);
if (result != B_NO_ERROR)
goto exit;
ni = ntfs_inode_open(ns->ntvol, ino);
if (!ni) {
result = EINVAL;
goto exit;
}
uname_len = ntfs_mbstoucs(newname, &uname);
if (uname_len < 0) {
result = EINVAL;
goto exit;
}
dir_ni = ntfs_inode_open(ns->ntvol, newparent);
if (!dir_ni) {
result = EINVAL;
goto exit;
}
if (ntfs_link(ni, dir_ni, uname, uname_len)) {
result = EINVAL;
goto exit;
}
ntfs_inode_update_mbsname(dir_ni, newname, ni->mft_no);
ni->flags |= FILE_ATTR_ARCHIVE;
fs_ntfs_update_times(_vol, ni, NTFS_UPDATE_CTIME);
fs_ntfs_update_times(_vol, dir_ni, NTFS_UPDATE_MCTIME);
ntfs_inode_close(dir_ni);
ntfs_inode_close(ni);
free(uname);
ntfs_remove(_vol, parent, name);
file->parent_vnid = newparent;
put_vnode(_vol, file->vnid);
notify_entry_moved(ns->id, parent, name, newparent, newname, ino);
} else
result = EINVAL;
goto exit;
}
// open source directory inode
odi = ntfs_inode_open(ns->ntvol, odir->vnid);
if (odi == NULL) {
result = ENOENT;
goto exit;
}
ovnid = MREF(ntfs_inode_lookup_by_name(odi, uoldname, uoldnameLength));
if (ovnid == (u64) -1) {
result = EINVAL;
goto exit;
}
result = get_vnode(_vol, ovnid, (void**)&onode);
if (result != B_NO_ERROR)
goto exit;
if (odir != ndir) {
// moving
ndi = ntfs_inode_open(ns->ntvol, ndir->vnid);
if (ndi != NULL) {
nvnid = MREF(ntfs_inode_lookup_by_name(ndi, unewname,
unewnameLength));
if (nvnid != (u64) -1)
get_vnode(_vol, nvnid, (void**)&nnode);
}
if (nnode != NULL) {
result = EINVAL;
put_vnode(_vol, nnode->vnid);
goto exit;
}
oi = ntfs_inode_open(ns->ntvol, onode->vnid);
if (oi == NULL) {
result = EINVAL;
goto exit;
}
if (ntfs_link(oi, ndi, unewname, unewnameLength)) {
ntfs_inode_close(oi);
result = EINVAL;
goto exit;
}
if (oi->mrec->flags & MFT_RECORD_IS_DIRECTORY)
set_mime(onode, ".***");
else
set_mime(onode, newname);
ntfs_inode_close(oi);
oi = ntfs_inode_open(ns->ntvol, onode->vnid);
if (oi == NULL) {
result = EINVAL;
goto exit;
}
onode->parent_vnid = MREF(ndi->mft_no);
notify_entry_moved(ns->id, MREF(odi->mft_no), oldname, MREF(ndi->mft_no),
newname, onode->vnid);
if (utils_inode_get_name(oi, path, MAX_PATH) == 0) {
result = EINVAL;
goto exit;
}
ntfs_delete(ns->ntvol, path, oi, odi, uoldname, uoldnameLength);
oi = odi = NULL;
/* ntfs_delete() always closes ni and dir_ni */
put_vnode(_vol, onode->vnid);
} else {
// renaming
nvnid = MREF(ntfs_inode_lookup_by_name(odi, unewname, unewnameLength));
if (nvnid != (u64)-1)
get_vnode(_vol, nvnid, (void**)&nnode);
if (nnode != NULL) {
result = EINVAL;
put_vnode(_vol, nnode->vnid);
goto exit;
}
oi = ntfs_inode_open(ns->ntvol, onode->vnid);
if (oi == NULL) {
result = EINVAL;
goto exit;
}
if (ntfs_link(oi, odi, unewname, unewnameLength)) {
ntfs_inode_close(oi);
result = EINVAL;
goto exit;
}
if (oi->mrec->flags & MFT_RECORD_IS_DIRECTORY)
set_mime(onode, ".***");
else
set_mime(onode, newname);
ntfs_inode_close(oi);
oi = ntfs_inode_open(ns->ntvol, onode->vnid);
if (oi == NULL) {
result = EINVAL;
goto exit;
}
notify_entry_moved(ns->id, MREF(odi->mft_no), oldname,
MREF(odi->mft_no), newname, onode->vnid);
put_vnode(_vol, onode->vnid);
if (utils_inode_get_name(oi, path, MAX_PATH) == 0) {
result = EINVAL;
goto exit;
}
ntfs_delete(ns->ntvol, path, oi, odi, uoldname, uoldnameLength);
oi = odi = NULL;
/* ntfs_delete() always closes ni and dir_ni */
}
exit:
free(unewname);
free(uoldname);
if (odi)
ntfs_inode_close(odi);
if (ndi)
ntfs_inode_close(ndi);
TRACE("fs_rename - EXIT, result is %s\n", strerror(result));
UNLOCK_VOL(ns);
@@ -1703,97 +1784,6 @@ exit:
}
static status_t
do_unlink(fs_volume *_vol, vnode *dir, const char *name, bool isdir)
{
nspace *ns = (nspace*)_vol->private_volume;
ino_t vnid;
vnode *node = NULL;
ntfs_inode *ni = NULL;
ntfs_inode *bi = NULL;
ntfschar *uname = NULL;
int unameLength;
char path[MAX_PATH];
status_t result = B_NO_ERROR;
unameLength = ntfs_mbstoucs(name, &uname);
if (unameLength < 0) {
result = EINVAL;
goto exit1;
}
bi = ntfs_inode_open(ns->ntvol, dir->vnid);
if (bi == NULL) {
result = ENOENT;
goto exit1;
}
vnid = MREF(ntfs_inode_lookup_by_name(bi, uname, unameLength));
if ( vnid == (u64)-1 || vnid == FILE_root) {
result = EINVAL;
goto exit1;
}
result = get_vnode(_vol, vnid, (void**)&node);
if (result != B_NO_ERROR || node==NULL) {
result = ENOENT;
goto exit1;
}
ni = ntfs_inode_open(ns->ntvol, node->vnid);
if (ni == NULL) {
result = ENOENT;
goto exit2;
}
if (isdir) {
if (!(ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)) {
result = ENOTDIR;
goto exit2;
}
if (ntfs_check_empty_dir(ni)<0) {
result = ENOTEMPTY;
goto exit2;
}
} else if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) {
result = EISDIR;
goto exit2;
}
if (utils_inode_get_name(ni, path, MAX_PATH) == 0) {
result = EINVAL;
goto exit2;
}
// TODO: the file must not be deleted here, only unlinked!
if (ntfs_delete(ns->ntvol, path, ni, bi, uname, unameLength))
result = errno;
ni = bi = NULL;
node->parent_vnid = dir->vnid;
notify_entry_removed(ns->id, dir->vnid, name, vnid);
result = remove_vnode(_vol, vnid);
exit2:
put_vnode(_vol, vnid);
exit1:
free(uname);
if (ni)
ntfs_inode_close(ni);
if (bi)
ntfs_inode_close(bi);
return result;
}
status_t
fs_rmdir(fs_volume *_vol, fs_vnode *_dir, const char *name)
{
@@ -1872,4 +1862,3 @@ exit:
return result;
}