diff --git a/src/add-ons/kernel/file_systems/ntfs/Jamfile b/src/add-ons/kernel/file_systems/ntfs/Jamfile index afffa6e31c..1b61b11623 100644 --- a/src/add-ons/kernel/file_systems/ntfs/Jamfile +++ b/src/add-ons/kernel/file_systems/ntfs/Jamfile @@ -9,6 +9,7 @@ UsePrivateHeaders kernel ; KernelAddon ntfs : attributes.c + fake_attributes.c mime_table.c utils.c ntfsdir.c diff --git a/src/add-ons/kernel/file_systems/ntfs/attributes.c b/src/add-ons/kernel/file_systems/ntfs/attributes.c index c6fe2a56c8..bef6dcd11c 100644 --- a/src/add-ons/kernel/file_systems/ntfs/attributes.c +++ b/src/add-ons/kernel/file_systems/ntfs/attributes.c @@ -25,41 +25,6 @@ //TODO: notify*() - -int32 kBeOSTypeCookie = 0x1234; - - -status_t -set_mime(vnode *node, const char *filename) -{ - struct ext_mime *p; - int32 namelen, ext_len; - - TRACE("set_mime - for [%s]\n", filename); - - node->mime = NULL; - - namelen = strlen(filename); - - for (p = mimes; p->extension; p++) { - ext_len = strlen(p->extension); - - if (namelen <= ext_len) - continue; - - if (filename[namelen-ext_len-1] != '.') - continue; - - if (!strcasecmp(filename + namelen - ext_len, p->extension)) - break; - } - - node->mime = p->mime; - - return B_NO_ERROR; -} - - status_t fs_open_attrib_dir(fs_volume *_vol, fs_vnode *_node, void **_cookie) { diff --git a/src/add-ons/kernel/file_systems/ntfs/attributes.h b/src/add-ons/kernel/file_systems/ntfs/attributes.h index a485bd539a..a7d924ef81 100644 --- a/src/add-ons/kernel/file_systems/ntfs/attributes.h +++ b/src/add-ons/kernel/file_systems/ntfs/attributes.h @@ -14,9 +14,6 @@ #include "ntfs.h" - -status_t set_mime(vnode *node, const char *filename); - status_t fs_create_attrib(fs_volume *_vol, fs_vnode *_node, const char* name, uint32 type, int openMode, void** _cookie); status_t fs_open_attrib_dir(fs_volume *_vol, fs_vnode *_node, void **_cookie); diff --git a/src/add-ons/kernel/file_systems/ntfs/fake_attributes.c b/src/add-ons/kernel/file_systems/ntfs/fake_attributes.c new file mode 100644 index 0000000000..517add5d57 --- /dev/null +++ b/src/add-ons/kernel/file_systems/ntfs/fake_attributes.c @@ -0,0 +1,337 @@ +/* + Copyright 1999-2001, Be Incorporated. All Rights Reserved. + This file may be used under the terms of the Be Sample Code License. +*/ +/* fake_attributes.c + * handles mime type information for ntfs + * gets/sets mime information in vnode + */ + +#define MIME_STRING_TYPE 'MIMS' + +#include +#include + +#include +#include +#include +#include + +#include "ntfs.h" +#include "fake_attributes.h" +#include "mime_table.h" + +int32 kBeOSTypeCookie = 0x1234; + +status_t set_mime(vnode *node, const char *filename) +{ + struct ext_mime *p; + int32 namelen, ext_len; + node->mime = NULL; + namelen = strlen(filename); + + for (p=mimes; p->extension; p++) { + ext_len = strlen(p->extension); + + if (namelen <= ext_len) + continue; + + if (filename[namelen-ext_len-1] != '.') + continue; + + if (!strcasecmp(filename + namelen - ext_len, p->extension)) + break; + } + node->mime = p->mime; + return B_NO_ERROR; +} + + +status_t +fake_open_attrib_dir(fs_volume *_vol, fs_vnode *_node, void **_cookie) +{ + nspace *ns = (nspace *)_vol->private_volume; + + int result = B_NO_ERROR; + + TRACE("fake_open_attrdir - ENTER\n"); + + LOCK_VOL(ns); + + if ((*_cookie = malloc(sizeof(uint32))) == NULL) { + result = ENOMEM; + goto exit; + } + + *(int32 *)(*_cookie) = 0; + +exit: + + TRACE("fs_open_attrdir - EXIT, result is %s\n", strerror(result)); + + UNLOCK_VOL(ns); + + return result; +} + +status_t +fake_close_attrib_dir(fs_volume *_vol, fs_vnode *_node, void *_cookie) +{ + nspace *ns = (nspace *)_vol->private_volume; + + TRACE("fake_close_attrdir - ENTER\n"); + + LOCK_VOL(ns); + + *(int32 *)_cookie = 1; + + TRACE("fake_close_attrdir - EXIT\n"); + + UNLOCK_VOL(ns); + + return B_NO_ERROR; +} + +status_t +fake_free_attrib_dir_cookie(fs_volume *_vol, fs_vnode *_node, void *_cookie) +{ + nspace *ns = (nspace *)_vol->private_volume; + + int result = B_NO_ERROR; + + LOCK_VOL(ns); + + TRACE("fake_free_attrib_dir_cookie - ENTER\n"); + + if (_cookie == NULL) { + TRACE("fake_free_attrib_dir_cookie - error:called with null cookie\n"); + result = EINVAL; + goto exit; + } + + *(int32 *)_cookie = 0x87654321; + free(_cookie); + +exit: + + TRACE("fake_free_attrib_dir_cookie - EXIT, result is %s\n", + strerror(result)); + + UNLOCK_VOL(ns); + + return result; +} + +status_t +fake_rewind_attrib_dir(fs_volume *_vol, fs_vnode *_node, void *_cookie) +{ + nspace *ns = (nspace *)_vol->private_volume; + + int result = B_NO_ERROR; + + LOCK_VOL(ns); + + TRACE("fake_rewind_attrcookie - ENTER\n"); + + if (_cookie == NULL) { + TRACE("fake_rewind_attrcookie - error: fs_rewind_attrcookie" + "called with null cookie\n"); + result = EINVAL; + goto exit; + } + + *(uint32 *)_cookie = 0; + +exit: + + TRACE("fake_rewind_attrcookie - EXIT, result is %s\n", strerror(result)); + + UNLOCK_VOL(ns); + + return result; +} + + +status_t +fake_read_attrib_dir(fs_volume *_vol, fs_vnode *_node, void *_cookie, + struct dirent *entry, size_t bufsize, uint32 *num) +{ + nspace *ns = (nspace *)_vol->private_volume; + vnode *node = (vnode *)_node->private_node; + + int32 *cookie = (int32 *)_cookie; + + LOCK_VOL(ns); + + TRACE("fake_read_attrdir - ENTER\n"); + + *num = 0; + + if ((*cookie == 0) && (node->mime)) { + *num = 1; + + entry->d_ino = node->vnid; + entry->d_dev = ns->id; + entry->d_reclen = 10; + strcpy(entry->d_name, "BEOS:TYPE"); + } + + *cookie = 1; + + TRACE("fake_read_attrdir - EXIT\n"); + + UNLOCK_VOL(ns); + + return B_NO_ERROR; +} + +status_t +fake_open_attrib(fs_volume *_vol, fs_vnode *_node, const char *name, + int openMode, void **_cookie) +{ + nspace *ns = (nspace *)_vol->private_volume; + vnode *node = (vnode *)_node->private_node; + int result = B_NO_ERROR; + + LOCK_VOL(ns); + + TRACE("fake_open_attrib - ENTER\n"); + + if (strcmp(name, "BEOS:TYPE")) { + result = ENOENT; + goto exit; + } + + if (node->mime == NULL) { + result = ENOENT; + goto exit; + } + + *_cookie = &kBeOSTypeCookie; + +exit: + + TRACE("fake_open_attrib - EXIT, result is %s\n", strerror(result)); + + UNLOCK_VOL(ns); + + return result; +} + + +status_t +fake_close_attrib(fs_volume *_vol, fs_vnode *_node, void *cookie) +{ + return B_NO_ERROR; +} + + +status_t +fake_free_attrib_cookie(fs_volume *_vol, fs_vnode *_node, void *cookie) +{ + return B_NO_ERROR; +} + + +status_t +fake_read_attrib_stat(fs_volume *_vol, fs_vnode *_node, void *_cookie, + struct stat *stat) +{ + nspace *ns = (nspace *)_vol->private_volume; + vnode *node = (vnode *)_node->private_node; + int result = B_NO_ERROR; + + LOCK_VOL(ns); + + TRACE("fake_read_attr_stat - ENTER\n"); + + if (_cookie != &kBeOSTypeCookie) { + result = ENOENT; + goto exit; + } + + if (node->mime == NULL) { + result = ENOENT; + goto exit; + } + + stat->st_type = MIME_STRING_TYPE; + stat->st_size = strlen(node->mime) + 1; + +exit: + + TRACE("fake_read_attrib_stat - EXIT, result is %s\n", + strerror(result)); + + UNLOCK_VOL(ns); + + return B_NO_ERROR; +} + + +status_t +fake_read_attrib(fs_volume *_vol, fs_vnode *_node, void *_cookie, + off_t pos,void *buffer, size_t *_length) +{ + nspace *ns = (nspace *)_vol->private_volume; + vnode *node = (vnode *)_node->private_node; + + int result = B_NO_ERROR; + + LOCK_VOL(ns); + + TRACE("fake_read_attr - ENTER\n"); + + if (_cookie != &kBeOSTypeCookie) { + result = ENOENT; + goto exit; + } + + if (node->mime == NULL) { + result = ENOENT; + goto exit; + } + + if ((pos < 0) || (pos > strlen(node->mime))) { + result = EINVAL; + goto exit; + } + + strncpy(buffer, node->mime + pos, *_length - 1); + ((char *)buffer)[*_length - 1] = 0; + *_length = strlen(buffer) + 1; + +exit: + + TRACE("fake_read_attr - EXIT, result is %s\n", strerror(result)); + + UNLOCK_VOL(ns); + + return result; +} + + +status_t +fake_write_attrib(fs_volume *_vol, fs_vnode *_node, void *_cookie, off_t pos, + const void *buffer, size_t *_length) +{ + nspace *ns = (nspace *)_vol->private_volume; + + int result = B_NO_ERROR; + + LOCK_VOL(ns); + + TRACE("fake_write_attr - ENTER\n"); + + *_length = 0; + + if (_cookie != &kBeOSTypeCookie) { + result = ENOSYS; + } + + TRACE("fake_write_attrib - EXIT, result is %s\n", strerror(result)); + + UNLOCK_VOL(ns); + + return result; +} diff --git a/src/add-ons/kernel/file_systems/ntfs/fake_attributes.h b/src/add-ons/kernel/file_systems/ntfs/fake_attributes.h new file mode 100644 index 0000000000..c12749418a --- /dev/null +++ b/src/add-ons/kernel/file_systems/ntfs/fake_attributes.h @@ -0,0 +1,39 @@ +/* + Copyright 1999-2001, Be Incorporated. All Rights Reserved. + This file may be used under the terms of the Be Sample Code License. +*/ +/* fake_attributes.h + * handles mime type information for ntfs + * gets/sets mime information in vnode + */ + +#ifndef NTFS_FAKE_ATTR_H_ +#define NTFS_FAKE_ATTR_H_ + +#include + +status_t set_mime(vnode *node, const char *filename); + +status_t fake_open_attrib_dir(fs_volume *_vol, fs_vnode *_node, + void **_cookie); +status_t fake_close_attrib_dir(fs_volume *_vol, fs_vnode *_node, + void *_cookie); +status_t fake_free_attrib_dir_cookie(fs_volume *_vol, fs_vnode *_node, + void *_cookie); +status_t fake_rewind_attrib_dir(fs_volume *_vol, fs_vnode *_node, + void *_cookie); +status_t fake_read_attrib_dir(fs_volume *_vol, fs_vnode *_node, void *_cookie, + struct dirent *buf, size_t bufsize, uint32 *num); +status_t fake_open_attrib(fs_volume *_vol, fs_vnode *_node, const char *name, + int openMode, void **_cookie); +status_t fake_close_attrib(fs_volume *_vol, fs_vnode *_node, void *cookie); +status_t fake_free_attrib_cookie(fs_volume *_vol, fs_vnode *_node, + void *cookie); +status_t fake_read_attrib_stat(fs_volume *_vol, fs_vnode *_node, void *cookie, + struct stat *stat); +status_t fake_read_attrib(fs_volume *_vol, fs_vnode *_node, void *cookie, + off_t pos,void *buffer, size_t *_length); +status_t fake_write_attrib(fs_volume *_vol, fs_vnode *_node, void *cookie, + off_t pos, const void *buffer, size_t *_length); + +#endif //NTFS_FAKE_ATTR_H_ 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..3427e4b314 100644 --- a/src/add-ons/kernel/file_systems/ntfs/fs_func.c +++ b/src/add-ons/kernel/file_systems/ntfs/fs_func.c @@ -38,6 +38,7 @@ #include #include "attributes.h" +#include "fake_attributes.h" #include "lock.h" #include "ntfs.h" #include "volume_util.h" @@ -113,6 +114,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) @@ -234,6 +405,7 @@ fs_mount(fs_volume *_vol, const char *device, ulong flags, const char *args, .state = NF_FreeClustersOutdate | NF_FreeMFTOutdate, .show_sys_files = false, .ro = false, + .fake_attrib = false, .flags = 0 }; @@ -249,6 +421,8 @@ fs_mount(fs_volume *_vol, const char *device, ulong flags, const char *args, "false"), "false") != 0; ns->noatime = strcasecmp(get_driver_parameter(handle, "no_atime", "true", "true"), "true") == 0; + ns->fake_attrib = strcasecmp(get_driver_parameter(handle, "fake_attributes", + "false", "false"), "false") != 0; unload_driver_settings(handle); if (ns->ro || (flags & B_MOUNT_READ_ONLY) != 0 @@ -257,6 +431,21 @@ fs_mount(fs_volume *_vol, const char *device, ulong flags, const char *args, ns->flags |= B_FS_IS_READONLY; } + if (ns->fake_attrib) { + gNTFSVnodeOps.open_attr_dir = fake_open_attrib_dir; + gNTFSVnodeOps.close_attr_dir = fake_close_attrib_dir; + gNTFSVnodeOps.free_attr_dir_cookie = fake_free_attrib_dir_cookie; + gNTFSVnodeOps.read_attr_dir = fake_read_attrib_dir; + gNTFSVnodeOps.rewind_attr_dir = fake_rewind_attrib_dir; + gNTFSVnodeOps.create_attr = NULL; + gNTFSVnodeOps.open_attr = fake_open_attrib; + gNTFSVnodeOps.close_attr = fake_close_attrib; + gNTFSVnodeOps.free_attr_cookie = fake_free_attrib_cookie; + gNTFSVnodeOps.read_attr = fake_read_attrib; + gNTFSVnodeOps.read_attr_stat = fake_read_attrib_stat; + gNTFSVnodeOps.write_attr = fake_write_attrib; + } + ns->ntvol = utils_mount_volume(device, mountFlags | MS_RECOVER); if (ns->ntvol != NULL) result = B_NO_ERROR; @@ -531,18 +720,19 @@ fs_read_vnode(fs_volume *_vol, ino_t vnid, fs_vnode *_node, int *_type, newNode->vnid = vnid; newNode->parent_vnid = ntfs_mft_get_parent_ref(ni); - - if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) - set_mime(newNode, ".***"); - else { - name = (char*)malloc(MAX_PATH); - if (name != NULL) { - if (utils_inode_get_name(ni, name, MAX_PATH) == 1) - set_mime(newNode, name); - free(name); + + if (ns->fake_attrib) { + if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) + set_mime(newNode, ".***"); + else { + name = (char*)malloc(MAX_PATH); + if (name != NULL) { + if (utils_inode_get_name(ni, name, MAX_PATH) == 1) + set_mime(newNode, name); + free(name); + } } } - _node->private_node = newNode; } else result = ENOMEM; @@ -964,8 +1154,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)); @@ -981,15 +1169,20 @@ fs_create(fs_volume *_vol, fs_vnode *_dir, const char *name, int omode, newNode->vnid = *_vnid; newNode->parent_vnid = MREF(bi->mft_no); - set_mime(newNode, name); + + if (ns->fake_attrib) + 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; @@ -1340,7 +1533,7 @@ fs_create_symlink(fs_volume *_vol, fs_vnode *_dir, const char *name, int unameLength; int utargetLength; status_t result = B_NO_ERROR; - int fmode; + int fmode = FS_FILE_MODE; le32 securid = 0; LOCK_VOL(ns); @@ -1386,12 +1579,13 @@ fs_create_symlink(fs_volume *_vol, fs_vnode *_dir, const char *name, symnode->vnid = MREF(sym->mft_no); symnode->parent_vnid = MREF(bi->mft_no); - if (sym->mrec->flags & MFT_RECORD_IS_DIRECTORY) { - set_mime(symnode, ".***"); - fmode = FS_DIR_MODE; - } else { - set_mime(symnode, name); - fmode = FS_FILE_MODE; + if (ns->fake_attrib) { + if (sym->mrec->flags & MFT_RECORD_IS_DIRECTORY) { + set_mime(symnode, ".***"); + fmode = FS_DIR_MODE; + } else { + set_mime(symnode, name); + } } result = publish_vnode(_vol, MREF(sym->mft_no), symnode, &gNTFSVnodeOps, @@ -1470,8 +1664,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) { @@ -1486,7 +1678,13 @@ 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, ".***"); + + if (ns->fake_attrib) + 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 +1711,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 +1737,78 @@ 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); + + if (ns->fake_attrib) { + if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) + set_mime(file, ".***"); + else + set_mime(file, newname); + } + + 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 +1817,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 +1895,3 @@ exit: return result; } - diff --git a/src/add-ons/kernel/file_systems/ntfs/ntfs.h b/src/add-ons/kernel/file_systems/ntfs/ntfs.h index df87c89a9b..e26147d1e7 100644 --- a/src/add-ons/kernel/file_systems/ntfs/ntfs.h +++ b/src/add-ons/kernel/file_systems/ntfs/ntfs.h @@ -119,6 +119,7 @@ typedef struct nspace { long free_mft; BOOL ro; BOOL show_sys_files; + BOOL fake_attrib; BOOL silent; BOOL force; BOOL debug; diff --git a/src/add-ons/kernel/file_systems/ntfs/settings/ntfs b/src/add-ons/kernel/file_systems/ntfs/settings/ntfs index 3a8e574252..d3f182acf0 100644 --- a/src/add-ons/kernel/file_systems/ntfs/settings/ntfs +++ b/src/add-ons/kernel/file_systems/ntfs/settings/ntfs @@ -6,3 +6,4 @@ hide_sys_files true read_only false no_atime true +fake_attributes true diff --git a/src/add-ons/kernel/file_systems/udf/Icb.cpp b/src/add-ons/kernel/file_systems/udf/Icb.cpp index faf1f9c5f2..61a91357af 100644 --- a/src/add-ons/kernel/file_systems/udf/Icb.cpp +++ b/src/add-ons/kernel/file_systems/udf/Icb.cpp @@ -183,7 +183,7 @@ void Icb::GetAccessTime(struct timespec ×pec) const { timestamp ts; - if ((_Tag().id() == TAGID_EXTENDED_FILE_ENTRY)) + if (_Tag().id() == TAGID_EXTENDED_FILE_ENTRY) ts = _ExtendedEntry()->access_date_and_time(); else ts = _FileEntry()->access_date_and_time(); @@ -200,7 +200,7 @@ void Icb::GetModificationTime(struct timespec ×pec) const { timestamp ts; - if ((_Tag().id() == TAGID_EXTENDED_FILE_ENTRY)) + if (_Tag().id() == TAGID_EXTENDED_FILE_ENTRY) ts = _ExtendedEntry()->modification_date_and_time(); else ts = _FileEntry()->modification_date_and_time(); @@ -214,7 +214,7 @@ Icb::GetModificationTime(struct timespec ×pec) const status_t -Icb::FindBlock(uint32 logicalBlock, off_t &block) +Icb::FindBlock(uint32 logicalBlock, off_t &block, bool &recorded) { off_t pos = logicalBlock << fVolume->BlockShift(); if (uint64(pos) >= Length()) { @@ -227,9 +227,11 @@ Icb::FindBlock(uint32 logicalBlock, off_t &block) status_t status = B_OK; long_address extent; bool isEmpty = false; + recorded = false; switch (_IcbTag().descriptor_flags()) { - case ICB_DESCRIPTOR_TYPE_SHORT: { + case ICB_DESCRIPTOR_TYPE_SHORT: + { TRACE(("Icb::FindBlock: descriptor type -> short\n")); AllocationDescriptorList list(this, ShortDescriptorAccessor(fPartition)); @@ -241,7 +243,8 @@ Icb::FindBlock(uint32 logicalBlock, off_t &block) break; } - case ICB_DESCRIPTOR_TYPE_LONG: { + case ICB_DESCRIPTOR_TYPE_LONG: + { TRACE(("Icb::FindBlock: descriptor type -> long\n")); AllocationDescriptorList list(this); status = list.FindExtent(pos, &extent, &isEmpty); @@ -252,7 +255,8 @@ Icb::FindBlock(uint32 logicalBlock, off_t &block) break; } - case ICB_DESCRIPTOR_TYPE_EXTENDED: { + case ICB_DESCRIPTOR_TYPE_EXTENDED: + { TRACE(("Icb::FindBlock: descriptor type -> extended\n")); // AllocationDescriptorList list(this, ExtendedDescriptorAccessor(0)); // RETURN(_Read(list, pos, buffer, length, block)); @@ -260,7 +264,8 @@ Icb::FindBlock(uint32 logicalBlock, off_t &block) break; } - case ICB_DESCRIPTOR_TYPE_EMBEDDED: { + case ICB_DESCRIPTOR_TYPE_EMBEDDED: + { TRACE(("Icb::FindBlock: descriptor type: embedded\n")); RETURN(B_ERROR); break; @@ -275,6 +280,7 @@ Icb::FindBlock(uint32 logicalBlock, off_t &block) if (status == B_OK) { block = extent.block(); + recorded = extent.type() == EXTENT_TYPE_RECORDED; TRACE(("Icb::FindBlock: block %lld\n", block)); } return status; @@ -301,7 +307,8 @@ Icb::Read(off_t pos, void *buffer, size_t *length, uint32 *block) return file_cache_read(fFileCache, NULL, pos, buffer, length); switch (_IcbTag().descriptor_flags()) { - case ICB_DESCRIPTOR_TYPE_SHORT: { + case ICB_DESCRIPTOR_TYPE_SHORT: + { TRACE(("Icb::Read: descriptor type -> short\n")); AllocationDescriptorList list(this, ShortDescriptorAccessor(fPartition)); @@ -309,14 +316,16 @@ Icb::Read(off_t pos, void *buffer, size_t *length, uint32 *block) break; } - case ICB_DESCRIPTOR_TYPE_LONG: { + case ICB_DESCRIPTOR_TYPE_LONG: + { TRACE(("Icb::Read: descriptor type -> long\n")); AllocationDescriptorList list(this); RETURN(_Read(list, pos, buffer, length, block)); break; } - case ICB_DESCRIPTOR_TYPE_EXTENDED: { + case ICB_DESCRIPTOR_TYPE_EXTENDED: + { TRACE(("Icb::Read: descriptor type -> extended\n")); // AllocationDescriptorList list(this, ExtendedDescriptorAccessor(0)); // RETURN(_Read(list, pos, buffer, length, block)); @@ -324,7 +333,8 @@ Icb::Read(off_t pos, void *buffer, size_t *length, uint32 *block) break; } - case ICB_DESCRIPTOR_TYPE_EMBEDDED: { + case ICB_DESCRIPTOR_TYPE_EMBEDDED: + { TRACE(("Icb::Read: descriptor type: embedded\n")); RETURN(B_ERROR); break; diff --git a/src/add-ons/kernel/file_systems/udf/Icb.h b/src/add-ons/kernel/file_systems/udf/Icb.h index fd3893a40e..ab61ae71b0 100644 --- a/src/add-ons/kernel/file_systems/udf/Icb.h +++ b/src/add-ons/kernel/file_systems/udf/Icb.h @@ -105,7 +105,8 @@ public: uint32 AllocationDescriptorsSize() { return _AbstractEntry()->AllocationDescriptorsLength(); } - status_t FindBlock(uint32 logicalBlock, off_t &block); + status_t FindBlock(uint32 logicalBlock, off_t &block, + bool &recorded); status_t Read(off_t pos, void *buffer, size_t *length, uint32 *block = NULL); diff --git a/src/add-ons/kernel/file_systems/udf/MetadataPartition.cpp b/src/add-ons/kernel/file_systems/udf/MetadataPartition.cpp index 2c58a2c2a6..619a6b809c 100644 --- a/src/add-ons/kernel/file_systems/udf/MetadataPartition.cpp +++ b/src/add-ons/kernel/file_systems/udf/MetadataPartition.cpp @@ -31,8 +31,16 @@ MetadataPartition::MetadataPartition(Volume *volume, fMetadataIcb = new(nothrow) Icb(volume, address); if (fMetadataIcb == NULL || fMetadataIcb->InitCheck() != B_OK) fInitStatus = B_NO_MEMORY; + else + fInitStatus = B_OK; - fInitStatus = B_OK; + address.set_to(metadataMirrorFileLocation, fPartition); + + fMetadataMirrorIcb = new(nothrow) Icb(volume, address); + if (fMetadataMirrorIcb == NULL + || fMetadataMirrorIcb->InitCheck() != B_OK) { + fInitStatus = B_NO_MEMORY; + } } /*! \brief Destroys the MetadataPartition object. @@ -48,9 +56,17 @@ status_t MetadataPartition::MapBlock(uint32 logicalBlock, off_t &physicalBlock) { off_t block = 0; - status_t status = fMetadataIcb->FindBlock(logicalBlock, block); + bool isRecorded; + status_t status = fMetadataIcb->FindBlock(logicalBlock, block, isRecorded); if (status != B_OK) return status; + if (!isRecorded) { + status = fMetadataMirrorIcb->FindBlock(logicalBlock, block, isRecorded); + if (status != B_OK) + return status; + if (!isRecorded) + return B_BAD_DATA; + } return fParentPartition.MapBlock(block, physicalBlock); } diff --git a/src/add-ons/kernel/file_systems/udf/MetadataPartition.h b/src/add-ons/kernel/file_systems/udf/MetadataPartition.h index 0c97bf6d1c..030ca0db12 100644 --- a/src/add-ons/kernel/file_systems/udf/MetadataPartition.h +++ b/src/add-ons/kernel/file_systems/udf/MetadataPartition.h @@ -44,6 +44,7 @@ private: bool fMetadataIsDuplicated; status_t fInitStatus; Icb *fMetadataIcb; + Icb *fMetadataMirrorIcb; }; #endif // _UDF_METADATA_PARTITION_H diff --git a/src/libs/alm/Area.cpp b/src/libs/alm/Area.cpp index 3d0a79488f..cd80cd2c83 100644 --- a/src/libs/alm/Area.cpp +++ b/src/libs/alm/Area.cpp @@ -613,8 +613,10 @@ void Area::_UpdateMaxSizeConstraint(BSize max) { if (!fLayoutItem->IsVisible()) { - fMaxContentHeight->SetRightSide(B_SIZE_UNLIMITED); - fMaxContentWidth->SetRightSide(B_SIZE_UNLIMITED); + if (fMaxContentHeight != NULL) + fMaxContentHeight->SetRightSide(B_SIZE_UNLIMITED); + if (fMaxContentWidth != NULL) + fMaxContentWidth->SetRightSide(B_SIZE_UNLIMITED); return; } diff --git a/src/preferences/keymap/KeyboardLayoutView.cpp b/src/preferences/keymap/KeyboardLayoutView.cpp index bbe8506c47..467e6a303b 100644 --- a/src/preferences/keymap/KeyboardLayoutView.cpp +++ b/src/preferences/keymap/KeyboardLayoutView.cpp @@ -622,7 +622,8 @@ KeyboardLayoutView::_DrawKey(BView* view, BRect updateRect, const Key* key, + (key->frame.Width() - key->second_row) * fFactor - fGap - 2); topLeft.bottom = bottomLeft.top; - topLeft.right = bottomLeft.right; + topLeft.right = bottomLeft.right + 1; + // add one to make the borders meet topRight.bottom = topLeft.bottom; topRight.left = topLeft.right; @@ -630,28 +631,52 @@ KeyboardLayoutView::_DrawKey(BView* view, BRect updateRect, const Key* key, bottomRight.top = bottomLeft.top; bottomRight.left = bottomLeft.right; + // draw top left corner be_control_look->DrawButtonFrame(view, topLeft, updateRect, - 4.0f, 0.0f, 0.0f, 0.0f, base, background, + 4.0f, 0.0f, 4.0f, 0.0f, base, background, pressed ? BControlLook::B_ACTIVATED : 0, BControlLook::B_LEFT_BORDER | BControlLook::B_TOP_BORDER | BControlLook::B_BOTTOM_BORDER); + be_control_look->DrawButtonBackground(view, topLeft, updateRect, + 4.0f, 0.0f, 4.0f, 0.0f, base, + pressed ? BControlLook::B_ACTIVATED : 0, + BControlLook::B_LEFT_BORDER | BControlLook::B_TOP_BORDER + | BControlLook::B_BOTTOM_BORDER); + + // draw top right corner be_control_look->DrawButtonFrame(view, topRight, updateRect, 0.0f, 4.0f, 0.0f, 0.0f, base, background, pressed ? BControlLook::B_ACTIVATED : 0, BControlLook::B_TOP_BORDER | BControlLook::B_RIGHT_BORDER); + be_control_look->DrawButtonBackground(view, topRight, updateRect, + 0.0f, 4.0f, 0.0f, 0.0f, base, + pressed ? BControlLook::B_ACTIVATED : 0, + BControlLook::B_TOP_BORDER | BControlLook::B_RIGHT_BORDER); + + // draw bottom right corner be_control_look->DrawButtonFrame(view, bottomRight, updateRect, - 0.0f, 0.0f, 0.0f, 4.0f, base, background, + 0.0f, 0.0f, 4.0f, 4.0f, base, background, + pressed ? BControlLook::B_ACTIVATED : 0, + BControlLook::B_LEFT_BORDER | BControlLook::B_RIGHT_BORDER + | BControlLook::B_BOTTOM_BORDER); + be_control_look->DrawButtonBackground(view, bottomRight, updateRect, + 0.0f, 0.0f, 4.0f, 4.0f, base, pressed ? BControlLook::B_ACTIVATED : 0, BControlLook::B_LEFT_BORDER | BControlLook::B_RIGHT_BORDER | BControlLook::B_BOTTOM_BORDER); - // Clip out the bottom left corner + // clip out the bottom left corner bottomLeft.right += 1; bottomLeft.top -= 2; BRegion region(rect); region.Exclude(bottomLeft); view->ConstrainClippingRegion(®ion); + // Fill in the rect with the background color + SetHighColor(background); + FillRect(rect); + + // draw the button background BRect bgRect = rect.InsetByCopy(2, 2); be_control_look->DrawButtonBackground(view, bgRect, updateRect, 4.0f, 4.0f, 0.0f, 4.0f, base, @@ -660,9 +685,11 @@ KeyboardLayoutView::_DrawKey(BView* view, BRect updateRect, const Key* key, rect.left = bottomLeft.right; _GetAbbreviatedKeyLabelIfNeeded(view, rect, key, text, sizeof(text)); + // draw the button label be_control_look->DrawLabel(view, text, rect, updateRect, base, 0, BAlignment(B_ALIGN_CENTER, B_ALIGN_MIDDLE)); + // reset the clipping region view->ConstrainClippingRegion(NULL); } }