From c0c445f1f45fbdb79d65763f84d53f7eea98077c Mon Sep 17 00:00:00 2001 From: threedeyes <3dEyes@gmail.com> Date: Mon, 22 Oct 2012 10:13:02 +0000 Subject: [PATCH] NTFS:Critical fixes for renaming and creating nodes. The adaptation of some functions to the new version of the libntfs3g. --- .../kernel/file_systems/ntfs/fs_func.c | 505 +++++++++--------- 1 file changed, 247 insertions(+), 258 deletions(-) diff --git a/src/add-ons/kernel/file_systems/ntfs/fs_func.c b/src/add-ons/kernel/file_systems/ntfs/fs_func.c index 28c27c62ec..fd8c6e423c 100644 --- a/src/add-ons/kernel/file_systems/ntfs/fs_func.c +++ b/src/add-ons/kernel/file_systems/ntfs/fs_func.c @@ -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; } -