First implementation of attribute support on NTFS. Currently lists and reads named streams as such, but the name mapping is not yet correct.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@36178 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
e16c15a7e7
commit
4b19582754
@ -12,6 +12,7 @@
|
||||
|
||||
#include <SupportDefs.h>
|
||||
#include <KernelExport.h>
|
||||
#include <TypeConstants.h>
|
||||
|
||||
#include <dirent.h>
|
||||
#include <fs_attr.h>
|
||||
@ -22,6 +23,8 @@
|
||||
#include "attributes.h"
|
||||
#include "mime_table.h"
|
||||
|
||||
//TODO: notify*()
|
||||
|
||||
int32 kBeOSTypeCookie = 0x1234;
|
||||
|
||||
status_t set_mime(vnode *node, const char *filename)
|
||||
@ -57,24 +60,50 @@ status_t set_mime(vnode *node, const char *filename)
|
||||
status_t
|
||||
fs_open_attrib_dir(fs_volume *_vol, fs_vnode *_node, void **_cookie)
|
||||
{
|
||||
nspace *ns = (nspace *)_vol->private_volume;
|
||||
nspace *ns = (nspace*)_vol->private_volume;
|
||||
vnode *node = (vnode*)_node->private_node;
|
||||
attrdircookie *cookie = NULL;
|
||||
ntfs_inode *ni = NULL;
|
||||
ntfs_attr_search_ctx *ctx = NULL;
|
||||
|
||||
int result = B_NO_ERROR;
|
||||
status_t result = B_NO_ERROR;
|
||||
|
||||
ERRPRINT("fs_open_attrdir - ENTER\n");
|
||||
ERRPRINT("%s - ENTER\n", __FUNCTION__);
|
||||
|
||||
LOCK_VOL(ns);
|
||||
|
||||
if ((*_cookie = malloc(sizeof(uint32))) == NULL) {
|
||||
ni = ntfs_inode_open(ns->ntvol, node->vnid);
|
||||
if (ni == NULL) {
|
||||
result = errno;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ctx = ntfs_attr_get_search_ctx(ni, NULL);
|
||||
if (ctx == NULL) {
|
||||
result = errno;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
cookie = (attrdircookie*)ntfs_calloc(sizeof(attrdircookie));
|
||||
if (cookie == NULL) {
|
||||
result = ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
*(int32 *)(*_cookie) = 0;
|
||||
cookie->inode = ni;
|
||||
cookie->ctx = ctx;
|
||||
ni = NULL;
|
||||
ctx = NULL;
|
||||
*_cookie = cookie;
|
||||
|
||||
exit:
|
||||
|
||||
ERRPRINT("fs_open_attrdir - EXIT, result is %s\n", strerror(result));
|
||||
if (ctx)
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
if (ni)
|
||||
ntfs_inode_close(ni);
|
||||
|
||||
ERRPRINT("%s - EXIT, result is %s\n", __FUNCTION__, strerror(result));
|
||||
|
||||
UNLOCK_VOL(ns);
|
||||
|
||||
@ -84,17 +113,7 @@ exit:
|
||||
status_t
|
||||
fs_close_attrib_dir(fs_volume *_vol, fs_vnode *_node, void *_cookie)
|
||||
{
|
||||
nspace *ns = (nspace *)_vol->private_volume;
|
||||
|
||||
ERRPRINT("fs_close_attrdir - ENTER\n");
|
||||
|
||||
LOCK_VOL(ns);
|
||||
|
||||
*(int32 *)_cookie = 1;
|
||||
|
||||
ERRPRINT("fs_close_attrdir - EXIT\n");
|
||||
|
||||
UNLOCK_VOL(ns);
|
||||
|
||||
return B_NO_ERROR;
|
||||
}
|
||||
@ -103,53 +122,43 @@ status_t
|
||||
fs_free_attrib_dir_cookie(fs_volume *_vol, fs_vnode *_node, void *_cookie)
|
||||
{
|
||||
nspace *ns = (nspace *)_vol->private_volume;
|
||||
|
||||
int result = B_NO_ERROR;
|
||||
attrdircookie *cookie = (attrdircookie *)_cookie;
|
||||
|
||||
LOCK_VOL(ns);
|
||||
|
||||
ERRPRINT("fs_free_attrib_dir_cookie - ENTER\n");
|
||||
|
||||
if (_cookie == NULL) {
|
||||
ERRPRINT("fs_free_attrib_dir_cookie - error: called with null cookie\n");
|
||||
result = EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
*(int32 *)_cookie = 0x87654321;
|
||||
free(_cookie);
|
||||
|
||||
exit:
|
||||
|
||||
ERRPRINT("fs_free_attrib_dir_cookie - EXIT, result is %s\n", strerror(result));
|
||||
if (cookie->ctx)
|
||||
ntfs_attr_put_search_ctx(cookie->ctx);
|
||||
if (cookie->inode)
|
||||
ntfs_inode_close(cookie->inode);
|
||||
|
||||
UNLOCK_VOL(ns);
|
||||
|
||||
return result;
|
||||
free(cookie);
|
||||
return B_NO_ERROR;
|
||||
}
|
||||
|
||||
status_t
|
||||
fs_rewind_attrib_dir(fs_volume *_vol, fs_vnode *_node, void *_cookie)
|
||||
{
|
||||
nspace *ns = (nspace *)_vol->private_volume;
|
||||
nspace *ns = (nspace*)_vol->private_volume;
|
||||
attrdircookie *cookie = (attrdircookie *)_cookie;
|
||||
status_t result = B_NO_ERROR;
|
||||
|
||||
int result = B_NO_ERROR;
|
||||
ERRPRINT("%s - ENTER\n", __FUNCTION__);
|
||||
|
||||
LOCK_VOL(ns);
|
||||
|
||||
ERRPRINT("fs_rewind_attrcookie - ENTER\n");
|
||||
|
||||
if (_cookie == NULL) {
|
||||
ERRPRINT("fs_rewind_attrcookie - error: fs_rewind_attrcookie called with null cookie\n");
|
||||
result = EINVAL;
|
||||
goto exit;
|
||||
if (cookie->ctx)
|
||||
ntfs_attr_put_search_ctx(cookie->ctx);
|
||||
cookie->ctx = ntfs_attr_get_search_ctx(cookie->inode, NULL);
|
||||
if (cookie->ctx == NULL) {
|
||||
result = errno;
|
||||
//goto exit;
|
||||
}
|
||||
|
||||
*(uint32 *)_cookie = 0;
|
||||
//exit:
|
||||
|
||||
exit:
|
||||
|
||||
ERRPRINT("fs_rewind_attrcookie - EXIT, result is %s\n", strerror(result));
|
||||
ERRPRINT("%s - EXIT, result is %s\n", __FUNCTION__, strerror(result));
|
||||
|
||||
UNLOCK_VOL(ns);
|
||||
|
||||
@ -162,59 +171,138 @@ fs_read_attrib_dir(fs_volume *_vol, fs_vnode *_node, void *_cookie, struct diren
|
||||
{
|
||||
nspace *ns = (nspace *)_vol->private_volume;
|
||||
vnode *node = (vnode *)_node->private_node;
|
||||
attrdircookie *cookie = (attrdircookie *)_cookie;
|
||||
uint32 numEntries = 0;
|
||||
status_t result = B_NO_ERROR;
|
||||
|
||||
int32 *cookie = (int32 *)_cookie;
|
||||
if (cookie->ctx == NULL)
|
||||
panic("cookie->ctx == NULL");
|
||||
|
||||
LOCK_VOL(ns);
|
||||
|
||||
ERRPRINT("fs_read_attrdir - ENTER\n");
|
||||
ERRPRINT("%s - ENTER\n", __FUNCTION__);
|
||||
|
||||
*num = 0;
|
||||
|
||||
if ((*cookie == 0) && (node->mime)) {
|
||||
*num = 1;
|
||||
while (!(result = ntfs_attrs_walk(cookie->ctx))) {
|
||||
ATTR_RECORD *attr = cookie->ctx->attr;
|
||||
if (attr->type == AT_DATA) {
|
||||
// it's the actual file body
|
||||
if (attr->name_length == 0)
|
||||
continue;
|
||||
|
||||
char *name = ntfs_attr_name_get((const ntfschar *)(((char *)attr)
|
||||
+ attr->name_offset), attr->name_length);
|
||||
dprintf("found AT_DATA '%s'\n", name);
|
||||
bufsize = MIN(bufsize, sizeof(struct dirent) + strlen(name) + 1);
|
||||
entry->d_ino = node->vnid;
|
||||
entry->d_dev = ns->id;
|
||||
entry->d_reclen = 10;
|
||||
strcpy(entry->d_name, "BEOS:TYPE");
|
||||
entry->d_reclen = sizeof(struct dirent) + strlen(name);
|
||||
//XXX size
|
||||
strcpy(entry->d_name, name);
|
||||
ntfs_attr_name_free(&name);
|
||||
numEntries++;
|
||||
if (numEntries >= *num)
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (result && errno != ENOENT) {
|
||||
result = errno;
|
||||
goto exit;
|
||||
} else {
|
||||
result = B_OK;
|
||||
}
|
||||
|
||||
*cookie = 1;
|
||||
|
||||
ERRPRINT("fs_read_attrdir - EXIT\n");
|
||||
exit:
|
||||
|
||||
ERRPRINT("%s - EXIT, result is %s, *num %d\n", __FUNCTION__, strerror(result), *num);
|
||||
|
||||
UNLOCK_VOL(ns);
|
||||
|
||||
return B_NO_ERROR;
|
||||
if (result)
|
||||
*num = 0;
|
||||
else
|
||||
*num = numEntries;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
fs_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;
|
||||
nspace *ns = (nspace*)_vol->private_volume;
|
||||
vnode *node = (vnode*)_node->private_node;
|
||||
attrcookie *cookie = NULL;
|
||||
ntfschar *unicode = NULL;
|
||||
int ulen;
|
||||
ntfs_inode *ni = NULL;
|
||||
ntfs_attr *na = NULL;
|
||||
status_t result = B_NO_ERROR;
|
||||
|
||||
ERRPRINT("%s - ENTER\n", __FUNCTION__);
|
||||
|
||||
LOCK_VOL(ns);
|
||||
|
||||
ERRPRINT("fs_open_attrib - ENTER\n");
|
||||
|
||||
if (strcmp(name, "BEOS:TYPE")) {
|
||||
result = ENOENT;
|
||||
if (node == NULL) {
|
||||
result = EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (node->mime == NULL) {
|
||||
result = ENOENT;
|
||||
ni = ntfs_inode_open(ns->ntvol, node->vnid);
|
||||
if (ni == NULL) {
|
||||
result = errno;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
*_cookie = &kBeOSTypeCookie;
|
||||
// UXA demangling TODO
|
||||
|
||||
// check for EA first... TODO: WRITEME
|
||||
|
||||
|
||||
// check for a named stream
|
||||
if (true) {
|
||||
unicode = ntfs_calloc(MAX_PATH);
|
||||
ulen = ntfs_mbstoucs(name, &unicode);
|
||||
if (ulen < 0) {
|
||||
result = EILSEQ;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
na = ntfs_attr_open(ni, AT_DATA, unicode, ulen);
|
||||
if (na) {
|
||||
if (openMode & O_TRUNC) {
|
||||
if (ntfs_attr_truncate(na, 0))
|
||||
result = errno;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
cookie = (attrcookie*)ntfs_calloc(sizeof(attrcookie));
|
||||
|
||||
if (cookie != NULL) {
|
||||
cookie->omode = openMode;
|
||||
*_cookie = (void*)cookie;
|
||||
cookie->inode = ni;
|
||||
cookie->stream = na;
|
||||
ni = NULL;
|
||||
na = NULL;
|
||||
} else
|
||||
result = ENOMEM;
|
||||
|
||||
exit:
|
||||
if (unicode)
|
||||
free(unicode);
|
||||
|
||||
ERRPRINT("fs_open_attrib - EXIT, result is %s\n", strerror(result));
|
||||
if (na)
|
||||
ntfs_attr_close(na);
|
||||
|
||||
if (ni)
|
||||
ntfs_inode_close(ni);
|
||||
|
||||
ERRPRINT("%s - EXIT, result is %s\n", __FUNCTION__, strerror(result));
|
||||
|
||||
UNLOCK_VOL(ns);
|
||||
|
||||
@ -230,8 +318,21 @@ fs_close_attrib(fs_volume *_vol, fs_vnode *_node, void *cookie)
|
||||
|
||||
|
||||
status_t
|
||||
fs_free_attrib_cookie(fs_volume *_vol, fs_vnode *_node, void *cookie)
|
||||
fs_free_attrib_cookie(fs_volume *_vol, fs_vnode *_node, void *_cookie)
|
||||
{
|
||||
nspace *ns = (nspace*)_vol->private_volume;
|
||||
attrcookie *cookie = (attrcookie *)_cookie;
|
||||
|
||||
LOCK_VOL(ns);
|
||||
|
||||
if (cookie->stream)
|
||||
ntfs_attr_close(cookie->stream);
|
||||
if (cookie->inode)
|
||||
ntfs_inode_close(cookie->inode);
|
||||
|
||||
UNLOCK_VOL(ns);
|
||||
|
||||
free(cookie);
|
||||
return B_NO_ERROR;
|
||||
}
|
||||
|
||||
@ -240,29 +341,21 @@ status_t
|
||||
fs_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;
|
||||
//vnode *node = (vnode *)_node->private_node;
|
||||
attrcookie *cookie = (attrcookie *)_cookie;
|
||||
//ntfs_inode *ni = cookie->inode;
|
||||
ntfs_attr *na = cookie->stream;
|
||||
|
||||
//status_t result = B_NO_ERROR;
|
||||
|
||||
LOCK_VOL(ns);
|
||||
|
||||
ERRPRINT("fs_read_attr_stat - ENTER\n");
|
||||
//ERRPRINT("%s - ENTER\n", __FUNCTION__);
|
||||
|
||||
if (_cookie != &kBeOSTypeCookie) {
|
||||
result = ENOENT;
|
||||
goto exit;
|
||||
}
|
||||
stat->st_type = B_RAW_TYPE;
|
||||
stat->st_size = na ? na->data_size : 0;
|
||||
|
||||
if (node->mime == NULL) {
|
||||
result = ENOENT;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
stat->st_type = MIME_STRING_TYPE;
|
||||
stat->st_size = strlen(node->mime) + 1;
|
||||
|
||||
exit:
|
||||
|
||||
ERRPRINT("fs_read_attrib_stat - EXIT, result is %s\n", strerror(result));
|
||||
//exit:
|
||||
|
||||
UNLOCK_VOL(ns);
|
||||
|
||||
@ -271,39 +364,59 @@ exit:
|
||||
|
||||
|
||||
status_t
|
||||
fs_read_attrib(fs_volume *_vol, fs_vnode *_node, void *_cookie, off_t pos,void *buffer, size_t *_length)
|
||||
fs_read_attrib(fs_volume *_vol, fs_vnode *_node, void *_cookie, off_t pos, void *buffer, size_t *len)
|
||||
{
|
||||
nspace *ns = (nspace *)_vol->private_volume;
|
||||
vnode *node = (vnode *)_node->private_node;
|
||||
//vnode *node = (vnode *)_node->private_node;
|
||||
attrcookie *cookie = (attrcookie *)_cookie;
|
||||
ntfs_inode *ni = cookie->inode;
|
||||
ntfs_attr *na = cookie->stream;
|
||||
size_t size = *len;
|
||||
int total = 0;
|
||||
status_t result = B_NO_ERROR;
|
||||
|
||||
if (pos < 0) {
|
||||
*len = 0;
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
int result = B_NO_ERROR;
|
||||
|
||||
LOCK_VOL(ns);
|
||||
|
||||
ERRPRINT("fs_read_attr - ENTER\n");
|
||||
ERRPRINT("%s - ENTER\n", __FUNCTION__);
|
||||
|
||||
if (_cookie != &kBeOSTypeCookie) {
|
||||
result = ENOENT;
|
||||
goto exit;
|
||||
// it is a named stream
|
||||
if (na) {
|
||||
if (pos + size > na->data_size)
|
||||
size = na->data_size - pos;
|
||||
|
||||
while (size) {
|
||||
off_t bytesRead = ntfs_attr_pread(na, pos, size, buffer);
|
||||
if (bytesRead < (s64)size) {
|
||||
ntfs_log_error("ntfs_attr_pread returned less bytes than "
|
||||
"requested.\n");
|
||||
}
|
||||
|
||||
if (node->mime == NULL) {
|
||||
result = ENOENT;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if ((pos < 0) || (pos > strlen(node->mime))) {
|
||||
if (bytesRead <= 0) {
|
||||
*len = 0;
|
||||
result = EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
size -= bytesRead;
|
||||
pos += bytesRead;
|
||||
total += bytesRead;
|
||||
}
|
||||
|
||||
strncpy(buffer, node->mime + pos, *_length - 1);
|
||||
((char *)buffer)[*_length - 1] = 0;
|
||||
*_length = strlen(buffer) + 1;
|
||||
*len = total;
|
||||
} else {
|
||||
*len = 0;
|
||||
result = ENOENT; // TODO
|
||||
}
|
||||
|
||||
fs_ntfs_update_times(_vol, ni, NTFS_UPDATE_ATIME); // XXX needed ?
|
||||
|
||||
exit:
|
||||
|
||||
ERRPRINT("fs_read_attr - EXIT, result is %s\n", strerror(result));
|
||||
ERRPRINT("%s - EXIT, result is %s\n", __FUNCTION__, strerror(result));
|
||||
|
||||
UNLOCK_VOL(ns);
|
||||
|
||||
@ -315,20 +428,72 @@ status_t
|
||||
fs_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;
|
||||
//vnode *node = (vnode *)_node->private_node;
|
||||
attrcookie *cookie = (attrcookie *)_cookie;
|
||||
ntfs_inode *ni = cookie->inode;
|
||||
ntfs_attr *na = cookie->stream;
|
||||
size_t size = *_length;
|
||||
int total = 0;
|
||||
status_t result = B_NO_ERROR;
|
||||
|
||||
ERRPRINT("%s - ENTER!!\n", __FUNCTION__);
|
||||
if (ns->flags & B_FS_IS_READONLY) {
|
||||
ERRPRINT("ntfs is read-only\n");
|
||||
return EROFS;
|
||||
}
|
||||
|
||||
if (pos < 0) {
|
||||
*_length = 0;
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
int result = B_NO_ERROR;
|
||||
|
||||
LOCK_VOL(ns);
|
||||
|
||||
ERRPRINT("fs_write_attr - ENTER\n");
|
||||
ERRPRINT("%s - ENTER\n", __FUNCTION__);
|
||||
|
||||
*_length = 0;
|
||||
// it is a named stream
|
||||
if (na) {
|
||||
if (cookie->omode & O_APPEND)
|
||||
pos = na->data_size;
|
||||
|
||||
if (_cookie != &kBeOSTypeCookie) {
|
||||
result = ENOSYS;
|
||||
if (pos + size > na->data_size) {
|
||||
ntfs_mark_free_space_outdated(ns);
|
||||
if (ntfs_attr_truncate(na, pos + size))
|
||||
size = na->data_size - pos;
|
||||
else
|
||||
notify_stat_changed(ns->id, MREF(ni->mft_no), B_STAT_SIZE);
|
||||
}
|
||||
|
||||
ERRPRINT("fs_write_attrib - EXIT, result is %s\n", strerror(result));
|
||||
while (size) {
|
||||
off_t bytesWritten = ntfs_attr_pwrite(na, pos, size, buffer);
|
||||
if (bytesWritten < (s64)size)
|
||||
ERRPRINT("%s - ntfs_attr_pwrite returned less bytes than requested.\n",
|
||||
__FUNCTION__);
|
||||
if (bytesWritten <= 0) {
|
||||
ERRPRINT(("%s - ntfs_attr_pwrite()<=0\n", __FUNCTION__));
|
||||
*_length = 0;
|
||||
result = EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
size -= bytesWritten;
|
||||
pos += bytesWritten;
|
||||
total += bytesWritten;
|
||||
}
|
||||
|
||||
*_length = total;
|
||||
} else {
|
||||
*_length = 0;
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
|
||||
if (total > 0)
|
||||
fs_ntfs_update_times(_vol, ni, NTFS_UPDATE_ATIME); // XXX needed ?
|
||||
|
||||
exit:
|
||||
|
||||
ERRPRINT("%s - EXIT, result is %s\n", __FUNCTION__, strerror(result));
|
||||
|
||||
UNLOCK_VOL(ns);
|
||||
|
||||
|
@ -91,6 +91,20 @@ typedef struct filecookie
|
||||
off_t last_size;
|
||||
} filecookie;
|
||||
|
||||
typedef struct attrcookie
|
||||
{
|
||||
int omode;
|
||||
ntfs_inode *inode;
|
||||
ntfs_attr *stream;
|
||||
// MFT ref for EA ?
|
||||
} attrcookie;
|
||||
|
||||
typedef struct attrdircookie
|
||||
{
|
||||
ntfs_inode *inode;
|
||||
ntfs_attr_search_ctx *ctx;
|
||||
} attrdircookie;
|
||||
|
||||
#define ntfs_mark_free_space_outdated(ns) (ns->state |= (NF_FreeClustersOutdate | NF_FreeMFTOutdate));
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user