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:
François Revol 2010-04-12 00:07:52 +00:00
parent e16c15a7e7
commit 4b19582754
2 changed files with 363 additions and 184 deletions

View File

@ -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)
@ -54,170 +57,255 @@ status_t set_mime(vnode *node, const char *filename)
}
status_t
status_t
fs_open_attrib_dir(fs_volume *_vol, fs_vnode *_node, void **_cookie)
{
nspace *ns = (nspace *)_vol->private_volume;
int result = B_NO_ERROR;
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;
ERRPRINT("fs_open_attrdir - ENTER\n");
status_t result = B_NO_ERROR;
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);
return result;
}
status_t
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;
}
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;
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));
UNLOCK_VOL(ns);
return result;
}
status_t
fs_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);
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;
}
*(uint32 *)_cookie = 0;
exit:
ERRPRINT("fs_rewind_attrcookie - EXIT, result is %s\n", strerror(result));
UNLOCK_VOL(ns);
return result;
}
status_t
fs_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);
ERRPRINT("fs_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;
ERRPRINT("fs_read_attrdir - EXIT\n");
UNLOCK_VOL(ns);
return B_NO_ERROR;
}
status_t
fs_open_attrib(fs_volume *_vol, fs_vnode *_node, const char *name, int openMode, void **_cookie)
fs_free_attrib_dir_cookie(fs_volume *_vol, fs_vnode *_node, void *_cookie)
{
nspace *ns = (nspace *)_vol->private_volume;
vnode *node = (vnode *)_node->private_node;
int result = B_NO_ERROR;
attrdircookie *cookie = (attrdircookie *)_cookie;
LOCK_VOL(ns);
ERRPRINT("fs_open_attrib - ENTER\n");
if (strcmp(name, "BEOS:TYPE")) {
result = ENOENT;
goto exit;
}
if (node->mime == NULL) {
result = ENOENT;
goto exit;
}
*_cookie = &kBeOSTypeCookie;
exit:
ERRPRINT("fs_open_attrib - 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);
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;
attrdircookie *cookie = (attrdircookie *)_cookie;
status_t result = B_NO_ERROR;
ERRPRINT("%s - ENTER\n", __FUNCTION__);
LOCK_VOL(ns);
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;
}
//exit:
ERRPRINT("%s - EXIT, result is %s\n", __FUNCTION__, strerror(result));
UNLOCK_VOL(ns);
return result;
}
status_t
fs_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;
attrdircookie *cookie = (attrdircookie *)_cookie;
uint32 numEntries = 0;
status_t result = B_NO_ERROR;
if (cookie->ctx == NULL)
panic("cookie->ctx == NULL");
LOCK_VOL(ns);
ERRPRINT("%s - ENTER\n", __FUNCTION__);
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 = 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;
}
exit:
ERRPRINT("%s - EXIT, result is %s, *num %d\n", __FUNCTION__, strerror(result), *num);
UNLOCK_VOL(ns);
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;
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);
if (node == NULL) {
result = EINVAL;
goto exit;
}
ni = ntfs_inode_open(ns->ntvol, node->vnid);
if (ni == NULL) {
result = errno;
goto exit;
}
// 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);
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);
return result;
}
@ -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;
}
if (node->mime == NULL) {
result = ENOENT;
goto exit;
}
if ((pos < 0) || (pos > strlen(node->mime))) {
result = EINVAL;
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 (bytesRead <= 0) {
*len = 0;
result = EINVAL;
goto exit;
}
size -= bytesRead;
pos += bytesRead;
total += bytesRead;
}
*len = total;
} else {
*len = 0;
result = ENOENT; // TODO
}
strncpy(buffer, node->mime + pos, *_length - 1);
((char *)buffer)[*_length - 1] = 0;
*_length = strlen(buffer) + 1;
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,22 +428,74 @@ 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;
int result = B_NO_ERROR;
LOCK_VOL(ns);
ERRPRINT("fs_write_attr - ENTER\n");
*_length = 0;
if (_cookie != &kBeOSTypeCookie) {
result = ENOSYS;
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;
}
LOCK_VOL(ns);
ERRPRINT("%s - ENTER\n", __FUNCTION__);
// it is a named stream
if (na) {
if (cookie->omode & O_APPEND)
pos = na->data_size;
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);
}
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;
}
ERRPRINT("fs_write_attrib - EXIT, result is %s\n", strerror(result));
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);
return result;
}

View File

@ -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));