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:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user