Author: mmu_man Date: 2010-04-12 02:07:52 +0200 (Mon, 12 Apr 2010) New Revision: 36178 Changeset: http://dev.haiku-os.org/changeset/36178/haiku Modified: haiku/trunk/src/add-ons/kernel/file_systems/ntfs/attributes.c haiku/trunk/src/add-ons/kernel/file_systems/ntfs/ntfs.h Log: First implementation of attribute support on NTFS. Currently lists and reads named streams as such, but the name mapping is not yet correct. Modified: haiku/trunk/src/add-ons/kernel/file_systems/ntfs/attributes.c =================================================================== --- haiku/trunk/src/add-ons/kernel/file_systems/ntfs/attributes.c 2010-04-12 00:05:40 UTC (rev 36177) +++ haiku/trunk/src/add-ons/kernel/file_systems/ntfs/attributes.c 2010-04-12 00:07:52 UTC (rev 36178) @@ -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,102 +57,108 @@ } -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; } + + cookie->inode = ni; + cookie->ctx = ctx; + ni = NULL; + ctx = NULL; + *_cookie = cookie; - *(int32 *)(*_cookie) = 0; - 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 +status_t fs_free_attrib_dir_cookie(fs_volume *_vol, fs_vnode *_node, void *_cookie) { nspace *ns = (nspace *)_vol->private_volume; + attrdircookie *cookie = (attrdircookie *)_cookie; - 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); + if (cookie->ctx) + ntfs_attr_put_search_ctx(cookie->ctx); + if (cookie->inode) + ntfs_inode_close(cookie->inode); -exit: + UNLOCK_VOL(ns); - ERRPRINT("fs_free_attrib_dir_cookie - EXIT, result is %s\n", strerror(result)); - - UNLOCK_VOL(ns); - - return result; + free(cookie); + return B_NO_ERROR; } -status_t +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); @@ -157,67 +166,146 @@ } -status_t +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; - 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; - - entry->d_ino = node->vnid; - entry->d_dev = ns->id; - entry->d_reclen = 10; - strcpy(entry->d_name, "BEOS:TYPE"); + 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; + } - *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; - goto exit; + if (node == NULL) { + result = EINVAL; + goto exit; } - - if (node->mime == NULL) { - result = ENOENT; - goto exit; + + 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); - + return result; } @@ -230,8 +318,21 @@ 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,30 +341,22 @@ 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: -exit: - - ERRPRINT("fs_read_attrib_stat - EXIT, result is %s\n", strerror(result)); - UNLOCK_VOL(ns); return B_NO_ERROR; @@ -271,39 +364,59 @@ 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; - int result = B_NO_ERROR; + if (pos < 0) { + *len = 0; + return EINVAL; + } + 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 (bytesRead <= 0) { + *len = 0; + result = EINVAL; + goto exit; + } + size -= bytesRead; + pos += bytesRead; + total += bytesRead; + } + + *len = total; + } else { + *len = 0; + result = ENOENT; // TODO } - - 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; - + 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 @@ 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; - + 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("fs_write_attr - ENTER\n"); - *_length = 0; + ERRPRINT("%s - ENTER\n", __FUNCTION__); - if (_cookie != &kBeOSTypeCookie) { - result = ENOSYS; + // 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; } Modified: haiku/trunk/src/add-ons/kernel/file_systems/ntfs/ntfs.h =================================================================== --- haiku/trunk/src/add-ons/kernel/file_systems/ntfs/ntfs.h 2010-04-12 00:05:40 UTC (rev 36177) +++ haiku/trunk/src/add-ons/kernel/file_systems/ntfs/ntfs.h 2010-04-12 00:07:52 UTC (rev 36178) @@ -91,6 +91,20 @@ 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));