Update NTFS-3g Library to stable 2009.4.4 version. Clean up code. Now write support enabled by default.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@30944 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Gerasim Troeglazov
2009-06-02 12:21:10 +00:00
parent 4cf2271b57
commit 30bc84e971
51 changed files with 3202 additions and 2349 deletions
@@ -2,8 +2,6 @@ SubDir HAIKU_TOP src add-ons kernel file_systems ntfs ;
SubDirHdrs [ FDirName $(SUBDIR) libntfs ] ; SubDirHdrs [ FDirName $(SUBDIR) libntfs ] ;
SetSubDirSupportedPlatformsBeOSCompatible ;
SubDirCcFlags -DHAVE_CONFIG_H=1 ; SubDirCcFlags -DHAVE_CONFIG_H=1 ;
SubDirC++Flags -DHAVE_CONFIG_H=1 ; SubDirC++Flags -DHAVE_CONFIG_H=1 ;
@@ -54,17 +54,10 @@ status_t set_mime(vnode *node, const char *filename)
} }
#ifdef __HAIKU__
status_t status_t
fs_open_attrib_dir(fs_volume *_vol, fs_vnode *_node, void **_cookie) fs_open_attrib_dir(fs_volume *_vol, fs_vnode *_node, void **_cookie)
{ {
nspace *ns = (nspace *)_vol->private_volume; nspace *ns = (nspace *)_vol->private_volume;
#else
int
fs_open_attrib_dir(void *_ns, void *_node, void **_cookie)
{
nspace *ns = (nspace *)_ns;
#endif
int result = B_NO_ERROR; int result = B_NO_ERROR;
@@ -88,17 +81,10 @@ exit:
return result; return result;
} }
#ifdef __HAIKU__
status_t status_t
fs_close_attrib_dir(fs_volume *_vol, fs_vnode *_node, void *_cookie) fs_close_attrib_dir(fs_volume *_vol, fs_vnode *_node, void *_cookie)
{ {
nspace *ns = (nspace *)_vol->private_volume; nspace *ns = (nspace *)_vol->private_volume;
#else
int
fs_close_attrib_dir(void *_ns, void *_node, void *_cookie)
{
nspace *ns = (nspace *)_ns;
#endif
ERRPRINT("fs_close_attrdir - ENTER\n"); ERRPRINT("fs_close_attrdir - ENTER\n");
@@ -113,17 +99,10 @@ fs_close_attrib_dir(void *_ns, void *_node, void *_cookie)
return B_NO_ERROR; return B_NO_ERROR;
} }
#ifdef __HAIKU__
status_t status_t
fs_free_attrib_dir_cookie(fs_volume *_vol, fs_vnode *_node, void *_cookie) fs_free_attrib_dir_cookie(fs_volume *_vol, fs_vnode *_node, void *_cookie)
{ {
nspace *ns = (nspace *)_vol->private_volume; nspace *ns = (nspace *)_vol->private_volume;
#else
int
fs_free_attrib_dir_cookie(void *_ns, void *_node, void *_cookie)
{
nspace *ns = (nspace *)_ns;
#endif
int result = B_NO_ERROR; int result = B_NO_ERROR;
@@ -149,17 +128,11 @@ exit:
return result; return result;
} }
#ifdef __HAIKU__
status_t status_t
fs_rewind_attrib_dir(fs_volume *_vol, fs_vnode *_node, void *_cookie) fs_rewind_attrib_dir(fs_volume *_vol, fs_vnode *_node, void *_cookie)
{ {
nspace *ns = (nspace *)_vol->private_volume; nspace *ns = (nspace *)_vol->private_volume;
#else
int
fs_rewind_attrib_dir(void *_ns, void *_node, void *_cookie)
{
nspace *ns = (nspace *)_ns;
#endif
int result = B_NO_ERROR; int result = B_NO_ERROR;
LOCK_VOL(ns); LOCK_VOL(ns);
@@ -184,19 +157,12 @@ exit:
} }
#ifdef __HAIKU__
status_t status_t
fs_read_attrib_dir(fs_volume *_vol, fs_vnode *_node, void *_cookie, struct dirent *entry, size_t bufsize, uint32 *num) 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; nspace *ns = (nspace *)_vol->private_volume;
vnode *node = (vnode *)_node->private_node; vnode *node = (vnode *)_node->private_node;
#else
int
fs_read_attrib_dir(void *_ns, void *_node, void *_cookie, long *num, struct dirent *entry, size_t bufsize)
{
nspace *ns = (nspace *)_ns;
vnode *node = (vnode *)_node;
#endif
int32 *cookie = (int32 *)_cookie; int32 *cookie = (int32 *)_cookie;
LOCK_VOL(ns); LOCK_VOL(ns);
@@ -223,28 +189,6 @@ fs_read_attrib_dir(void *_ns, void *_node, void *_cookie, long *num, struct dire
return B_NO_ERROR; return B_NO_ERROR;
} }
#ifndef __HAIKU__
int
fs_read_attrib_stat(void *_ns, void *_node, const char *name, struct attr_info *buf)
{
nspace *ns = (nspace *)_ns;
vnode *node = (vnode *)_node;
if (strcmp(name, "BEOS:TYPE"))
return ENOENT;
if (node->mime == NULL) {
return ENOENT;
}
buf->type = MIME_STRING_TYPE;
buf->size = strlen(node->mime) + 1;
return 0;
}
#endif
#ifdef __HAIKU__
status_t status_t
fs_open_attrib(fs_volume *_vol, fs_vnode *_node, const char *name, int openMode, void **_cookie) fs_open_attrib(fs_volume *_vol, fs_vnode *_node, const char *name, int openMode, void **_cookie)
{ {
@@ -276,25 +220,22 @@ exit:
return result; return result;
} }
#endif
#ifdef __HAIKU__
status_t status_t
fs_close_attrib(fs_volume *_vol, fs_vnode *_node, void *cookie) fs_close_attrib(fs_volume *_vol, fs_vnode *_node, void *cookie)
{ {
return B_NO_ERROR; return B_NO_ERROR;
} }
#endif
#ifdef __HAIKU__
status_t 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)
{ {
return B_NO_ERROR; return B_NO_ERROR;
} }
#endif
#ifdef __HAIKU__
status_t status_t
fs_read_attrib_stat(fs_volume *_vol, fs_vnode *_node, void *_cookie,struct stat *stat) fs_read_attrib_stat(fs_volume *_vol, fs_vnode *_node, void *_cookie,struct stat *stat)
{ {
@@ -327,33 +268,24 @@ exit:
return B_NO_ERROR; return B_NO_ERROR;
} }
#endif
#ifdef __HAIKU__
status_t 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 *_length)
{ {
nspace *ns = (nspace *)_vol->private_volume; nspace *ns = (nspace *)_vol->private_volume;
vnode *node = (vnode *)_node->private_node; vnode *node = (vnode *)_node->private_node;
#else
int
fs_read_attrib(void *_ns, void *_node, const char *name, int type, void *buffer, size_t *_length, off_t pos)
{
nspace *ns = (nspace *)_ns;
vnode *node = (vnode *)_node;
#endif
int result = B_NO_ERROR; int result = B_NO_ERROR;
LOCK_VOL(ns); LOCK_VOL(ns);
ERRPRINT("fs_read_attr - ENTER\n"); ERRPRINT("fs_read_attr - ENTER\n");
#ifdef __HAIKU_
if (_cookie != &kBeOSTypeCookie) { if (_cookie != &kBeOSTypeCookie) {
result = ENOENT; result = ENOENT;
goto exit; goto exit;
} }
#endif
if (node->mime == NULL) { if (node->mime == NULL) {
result = ENOENT; result = ENOENT;
@@ -379,17 +311,11 @@ exit:
} }
#ifdef __HAIKU__
status_t status_t
fs_write_attrib(fs_volume *_vol, fs_vnode *_node, void *_cookie,off_t pos, const void *buffer, size_t *_length) 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; nspace *ns = (nspace *)_vol->private_volume;
#else
int
fs_write_attrib(void *_ns, void *_node, const char *name, int type, const void *buffer, size_t *_length, off_t pos)
{
nspace *ns = (nspace *)_ns;
#endif
int result = B_NO_ERROR; int result = B_NO_ERROR;
LOCK_VOL(ns); LOCK_VOL(ns);
@@ -397,11 +323,10 @@ fs_write_attrib(void *_ns, void *_node, const char *name, int type, const void *
ERRPRINT("fs_write_attr - ENTER\n"); ERRPRINT("fs_write_attr - ENTER\n");
*_length = 0; *_length = 0;
#ifdef __HAIKU_
if (_cookie != &kBeOSTypeCookie) { if (_cookie != &kBeOSTypeCookie) {
result = ENOSYS; result = ENOSYS;
} }
#endif
ERRPRINT("fs_write_attrib - EXIT, result is %s\n", strerror(result)); ERRPRINT("fs_write_attrib - EXIT, result is %s\n", strerror(result));
+20 -17
View File
@@ -123,7 +123,7 @@ fs_identify_partition(int fd, partition_data *partition, void **_cookie)
if(!ioctl(fd,B_GET_PATH_FOR_DEVICE,devpath)) if(!ioctl(fd,B_GET_PATH_FOR_DEVICE,devpath))
return -1; return -1;
//try mount //try mount
ntVolume = utils_mount_volume(devpath,MS_RDONLY|MS_NOATIME,true); ntVolume = utils_mount_volume(devpath,MS_RDONLY,true);
if(!ntVolume) if(!ntVolume)
return -1; return -1;
@@ -208,8 +208,8 @@ fs_mount(fs_volume *_vol, const char *device, ulong flags, const char *args, ino
mnt_flags |= MS_RDONLY; mnt_flags |= MS_RDONLY;
ns->flags |= B_MOUNT_READ_ONLY; ns->flags |= B_MOUNT_READ_ONLY;
} }
if (ns->noatime) // if (ns->noatime)
mnt_flags |= MS_NOATIME; // mnt_flags |= MS_NOATIME;
ns->ntvol=utils_mount_volume(device,mnt_flags,true); ns->ntvol=utils_mount_volume(device,mnt_flags,true);
if(ns->ntvol!=NULL) if(ns->ntvol!=NULL)
@@ -367,7 +367,7 @@ fs_walk(fs_volume *_vol, fs_vnode *_dir, const char *file, ino_t *vnid)
result = ENOENT; result = ENOENT;
} else { } else {
unicode = ntfs_calloc(MAX_PATH); unicode = ntfs_calloc(MAX_PATH);
len = ntfs_mbstoucs(file, &unicode, MAX_PATH); len = ntfs_mbstoucs(file, &unicode);
if (len < 0) { if (len < 0) {
result = EILSEQ; result = EILSEQ;
goto exit; goto exit;
@@ -882,7 +882,7 @@ fs_create(fs_volume *_vol, fs_vnode *_dir, const char *name, int omode, int perm
goto exit; goto exit;
} }
uname_len = ntfs_mbstoucs(name, &uname, 0); uname_len = ntfs_mbstoucs(name, &uname);
if (uname_len < 0) { if (uname_len < 0) {
result = EINVAL; result = EINVAL;
goto exit; goto exit;
@@ -1285,13 +1285,13 @@ fs_create_symlink(fs_volume *_vol, fs_vnode *_dir, const char *name, const char
goto exit; goto exit;
} }
uname_len = ntfs_mbstoucs(name, &uname, 0); uname_len = ntfs_mbstoucs(name, &uname);
if (uname_len < 0) { if (uname_len < 0) {
result = EINVAL; result = EINVAL;
goto exit; goto exit;
} }
utarget_len = ntfs_mbstoucs(target, &utarget, 0); utarget_len = ntfs_mbstoucs(target, &utarget);
if (utarget_len < 0) { if (utarget_len < 0) {
result = EINVAL; result = EINVAL;
goto exit; goto exit;
@@ -1380,7 +1380,7 @@ fs_mkdir(fs_volume *_vol, fs_vnode *_dir, const char *name, int perms)
goto exit; goto exit;
} }
uname_len = ntfs_mbstoucs(name, &uname, 0); uname_len = ntfs_mbstoucs(name, &uname);
if (uname_len < 0) { if (uname_len < 0) {
result = EINVAL; result = EINVAL;
goto exit; goto exit;
@@ -1475,13 +1475,13 @@ fs_rename(fs_volume *_vol, fs_vnode *_odir, const char *oldname, fs_vnode *_ndir
goto exit; goto exit;
//convert names from utf8 to unicode string //convert names from utf8 to unicode string
unewname_len = ntfs_mbstoucs(newname, &unewname, 0); unewname_len = ntfs_mbstoucs(newname, &unewname);
if (unewname_len < 0) { if (unewname_len < 0) {
result = EINVAL; result = EINVAL;
goto exit; goto exit;
} }
uoldname_len = ntfs_mbstoucs(oldname, &uoldname, 0); uoldname_len = ntfs_mbstoucs(oldname, &uoldname);
if (uoldname_len < 0) { if (uoldname_len < 0) {
result = EINVAL; result = EINVAL;
goto exit; goto exit;
@@ -1544,13 +1544,14 @@ fs_rename(fs_volume *_vol, fs_vnode *_odir, const char *oldname, fs_vnode *_ndir
goto exit; goto exit;
} }
ntfs_delete(oi, odi, uoldname, uoldname_len);
onode->parent_vnid = MREF( ndi->mft_no ); onode->parent_vnid = MREF( ndi->mft_no );
notify_entry_moved(ns->id, MREF( odi->mft_no ), oldname, MREF( ndi->mft_no ), newname, onode->vnid ); notify_entry_moved(ns->id, MREF( odi->mft_no ), oldname, MREF( ndi->mft_no ), newname, onode->vnid );
notify_attribute_changed(ns->id, onode->vnid, "BEOS:TYPE", B_ATTR_CHANGED); notify_attribute_changed(ns->id, onode->vnid, "BEOS:TYPE", B_ATTR_CHANGED);
ntfs_delete(oi, odi, uoldname, uoldname_len);
oi = odi = NULL; /* ntfs_delete() always closes ni and dir_ni */
put_vnode(_vol, onode->vnid ); put_vnode(_vol, onode->vnid );
} else { //renaming } else { //renaming
@@ -1590,10 +1591,12 @@ fs_rename(fs_volume *_vol, fs_vnode *_odir, const char *oldname, fs_vnode *_ndir
goto exit; goto exit;
} }
ntfs_delete(oi, odi, uoldname, uoldname_len);
notify_entry_moved(ns->id, MREF( odi->mft_no ), oldname, MREF( odi->mft_no ), newname, onode->vnid ); notify_entry_moved(ns->id, MREF( odi->mft_no ), oldname, MREF( odi->mft_no ), newname, onode->vnid );
notify_attribute_changed(ns->id, onode->vnid, "BEOS:TYPE", B_ATTR_CHANGED); notify_attribute_changed(ns->id, onode->vnid, "BEOS:TYPE", B_ATTR_CHANGED);
put_vnode(_vol, onode->vnid ); put_vnode(_vol, onode->vnid );
ntfs_delete(oi, odi, uoldname, uoldname_len);
oi = odi = NULL; /* ntfs_delete() always closes ni and dir_ni */
} }
@@ -1626,7 +1629,7 @@ do_unlink(fs_volume *_vol, vnode *dir, const char *name, bool isdir)
int uname_len; int uname_len;
status_t result = B_NO_ERROR; status_t result = B_NO_ERROR;
uname_len = ntfs_mbstoucs(name, &uname, 0); uname_len = ntfs_mbstoucs(name, &uname);
if (uname_len < 0) { if (uname_len < 0) {
result = EINVAL; result = EINVAL;
goto exit1; goto exit1;
@@ -1675,8 +1678,8 @@ do_unlink(fs_volume *_vol, vnode *dir, const char *name, bool isdir)
if(ntfs_delete(ni, bi, uname, uname_len)) if(ntfs_delete(ni, bi, uname, uname_len))
result = errno; result = errno;
else
ni = NULL; ni = bi = NULL;
node->parent_vnid = dir->vnid; node->parent_vnid = dir->vnid;
@@ -1760,7 +1763,7 @@ fs_unlink(fs_volume *_vol, fs_vnode *_dir, const char *name)
ERRPRINT("fs_unlink - ENTER: name %s\n", name==NULL?"NULL":name); ERRPRINT("fs_unlink - ENTER: name %s\n", name==NULL?"NULL":name);
if( ns == NULL || dir == NULL || name ==NULL) { if( ns == NULL || dir == NULL || name == NULL) {
result = EINVAL; result = EINVAL;
goto exit; goto exit;
} }
@@ -1,246 +0,0 @@
#ifndef _FSPROTO_H
#define _FSPROTO_H
//#include <sys/dirent.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <unistd.h>
#include <iovec.h>
#include <OS.h>
#include <fs_attr.h>
#include <fs_info.h>
#include <BeBuild.h>
typedef dev_t nspace_id;
/* UGLY UGLY UGLY */
#ifndef _DRIVERS_H
struct selectsync;
typedef struct selectsync selectsync;
#endif
/*
* PUBLIC PART OF THE FILE SYSTEM PROTOCOL
*/
#define WSTAT_MODE 0x0001
#define WSTAT_UID 0x0002
#define WSTAT_GID 0x0004
#define WSTAT_SIZE 0x0008
#define WSTAT_ATIME 0x0010
#define WSTAT_MTIME 0x0020
#define WSTAT_CRTIME 0x0040
#define WFSSTAT_NAME 0x0001
#define B_ENTRY_CREATED 1
#define B_ENTRY_REMOVED 2
#define B_ENTRY_MOVED 3
#define B_STAT_CHANGED 4
#define B_ATTR_CHANGED 5
#define B_DEVICE_MOUNTED 6
#define B_DEVICE_UNMOUNTED 7
#define B_STOP_WATCHING 0x0000
#define B_WATCH_NAME 0x0001
#define B_WATCH_STAT 0x0002
#define B_WATCH_ATTR 0x0004
#define B_WATCH_DIRECTORY 0x0008
#define SELECT_READ 1
#define SELECT_WRITE 2
#define SELECT_EXCEPTION 3
#define B_CUR_FS_API_VERSION 2
struct attr_info;
struct index_info;
typedef int op_read_vnode(void *ns, ino_t vnid, char r, void **node);
typedef int op_write_vnode(void *ns, void *node, char r);
typedef int op_remove_vnode(void *ns, void *node, char r);
typedef int op_secure_vnode(void *ns, void *node);
typedef int op_walk(void *ns, void *base, const char *file, char **newpath,
ino_t *vnid);
typedef int op_access(void *ns, void *node, int mode);
typedef int op_create(void *ns, void *dir, const char *name,
int omode, int perms, ino_t *vnid, void **cookie);
typedef int op_mkdir(void *ns, void *dir, const char *name, int perms);
typedef int op_symlink(void *ns, void *dir, const char *name,
const char *path);
typedef int op_link(void *ns, void *dir, const char *name, void *node);
typedef int op_rename(void *ns, void *olddir, const char *oldname,
void *newdir, const char *newname);
typedef int op_unlink(void *ns, void *dir, const char *name);
typedef int op_rmdir(void *ns, void *dir, const char *name);
typedef int op_readlink(void *ns, void *node, char *buf, size_t *bufsize);
typedef int op_opendir(void *ns, void *node, void **cookie);
typedef int op_closedir(void *ns, void *node, void *cookie);
typedef int op_rewinddir(void *ns, void *node, void *cookie);
typedef int op_readdir(void *ns, void *node, void *cookie, long *num,
struct dirent *buf, size_t bufsize);
typedef int op_open(void *ns, void *node, int omode, void **cookie);
typedef int op_close(void *ns, void *node, void *cookie);
typedef int op_free_cookie(void *ns, void *node, void *cookie);
typedef int op_read(void *ns, void *node, void *cookie, off_t pos, void *buf,
size_t *len);
typedef int op_write(void *ns, void *node, void *cookie, off_t pos,
const void *buf, size_t *len);
typedef int op_readv(void *ns, void *node, void *cookie, off_t pos, const iovec *vec,
size_t count, size_t *len);
typedef int op_writev(void *ns, void *node, void *cookie, off_t pos, const iovec *vec,
size_t count, size_t *len);
typedef int op_ioctl(void *ns, void *node, void *cookie, int cmd, void *buf,
size_t len);
typedef int op_setflags(void *ns, void *node, void *cookie, int flags);
typedef int op_rstat(void *ns, void *node, struct stat *);
typedef int op_wstat(void *ns, void *node, struct stat *, long mask);
typedef int op_fsync(void *ns, void *node);
typedef int op_select(void *ns, void *node, void *cookie, uint8 event,
uint32 ref, selectsync *sync);
typedef int op_deselect(void *ns, void *node, void *cookie, uint8 event,
selectsync *sync);
typedef int op_initialize(const char *devname, void *parms, size_t len);
typedef int op_mount(nspace_id nsid, const char *devname, ulong flags,
void *parms, size_t len, void **data, ino_t *vnid);
typedef int op_unmount(void *ns);
typedef int op_sync(void *ns);
typedef int op_rfsstat(void *ns, struct fs_info *);
typedef int op_wfsstat(void *ns, struct fs_info *, long mask);
typedef int op_open_attrdir(void *ns, void *node, void **cookie);
typedef int op_close_attrdir(void *ns, void *node, void *cookie);
typedef int op_rewind_attrdir(void *ns, void *node, void *cookie);
typedef int op_read_attrdir(void *ns, void *node, void *cookie, long *num,
struct dirent *buf, size_t bufsize);
typedef int op_remove_attr(void *ns, void *node, const char *name);
typedef int op_rename_attr(void *ns, void *node, const char *oldname,
const char *newname);
typedef int op_stat_attr(void *ns, void *node, const char *name,
struct attr_info *buf);
typedef int op_write_attr(void *ns, void *node, const char *name, int type,
const void *buf, size_t *len, off_t pos);
typedef int op_read_attr(void *ns, void *node, const char *name, int type,
void *buf, size_t *len, off_t pos);
typedef int op_open_indexdir(void *ns, void **cookie);
typedef int op_close_indexdir(void *ns, void *cookie);
typedef int op_rewind_indexdir(void *ns, void *cookie);
typedef int op_read_indexdir(void *ns, void *cookie, long *num,
struct dirent *buf, size_t bufsize);
typedef int op_create_index(void *ns, const char *name, int type, int flags);
typedef int op_remove_index(void *ns, const char *name);
typedef int op_rename_index(void *ns, const char *oldname,
const char *newname);
typedef int op_stat_index(void *ns, const char *name, struct index_info *buf);
typedef int op_open_query(void *ns, const char *query, ulong flags,
port_id port, long token, void **cookie);
typedef int op_close_query(void *ns, void *cookie);
typedef int op_read_query(void *ns, void *cookie, long *num,
struct dirent *buf, size_t bufsize);
typedef struct vnode_ops {
op_read_vnode (*read_vnode);
op_write_vnode (*write_vnode);
op_remove_vnode (*remove_vnode);
op_secure_vnode (*secure_vnode);
op_walk (*walk);
op_access (*access);
op_create (*create);
op_mkdir (*mkdir);
op_symlink (*symlink);
op_link (*link);
op_rename (*rename);
op_unlink (*unlink);
op_rmdir (*rmdir);
op_readlink (*readlink);
op_opendir (*opendir);
op_closedir (*closedir);
op_free_cookie (*free_dircookie);
op_rewinddir (*rewinddir);
op_readdir (*readdir);
op_open (*open);
op_close (*close);
op_free_cookie (*free_cookie);
op_read (*read);
op_write (*write);
op_readv (*readv);
op_writev (*writev);
op_ioctl (*ioctl);
op_setflags (*setflags);
op_rstat (*rstat);
op_wstat (*wstat);
op_fsync (*fsync);
op_initialize (*initialize);
op_mount (*mount);
op_unmount (*unmount);
op_sync (*sync);
op_rfsstat (*rfsstat);
op_wfsstat (*wfsstat);
op_select (*select);
op_deselect (*deselect);
op_open_indexdir (*open_indexdir);
op_close_indexdir (*close_indexdir);
op_free_cookie (*free_indexdircookie);
op_rewind_indexdir (*rewind_indexdir);
op_read_indexdir (*read_indexdir);
op_create_index (*create_index);
op_remove_index (*remove_index);
op_rename_index (*rename_index);
op_stat_index (*stat_index);
op_open_attrdir (*open_attrdir);
op_close_attrdir (*close_attrdir);
op_free_cookie (*free_attrdircookie);
op_rewind_attrdir (*rewind_attrdir);
op_read_attrdir (*read_attrdir);
op_write_attr (*write_attr);
op_read_attr (*read_attr);
op_remove_attr (*remove_attr);
op_rename_attr (*rename_attr);
op_stat_attr (*stat_attr);
op_open_query (*open_query);
op_close_query (*close_query);
op_free_cookie (*free_querycookie);
op_read_query (*read_query);
} vnode_ops;
extern int new_path(const char *path, char **copy);
extern void free_path(char *p);
extern int notify_listener(int op, nspace_id nsid,
ino_t vnida, ino_t vnidb,
ino_t vnidc, const char *name);
extern void notify_select_event(selectsync *sync, uint32 ref);
extern int send_notification(port_id port, long token,
ulong what, long op, nspace_id nsida,
nspace_id nsidb, ino_t vnida,
ino_t vnidb, ino_t vnidc,
const char *name);
extern int get_vnode(nspace_id nsid, ino_t vnid, void **data);
extern int put_vnode(nspace_id nsid, ino_t vnid);
extern int new_vnode(nspace_id nsid, ino_t vnid, void *data);
extern int remove_vnode(nspace_id nsid, ino_t vnid);
extern int unremove_vnode(nspace_id nsid, ino_t vnid);
extern int is_vnode_removed(nspace_id nsid, ino_t vnid);
extern _EXPORT vnode_ops fs_entry;
extern _EXPORT int32 api_version;
#endif
@@ -1,7 +1,5 @@
SubDir HAIKU_TOP src add-ons kernel file_systems ntfs libntfs ; SubDir HAIKU_TOP src add-ons kernel file_systems ntfs libntfs ;
SetSubDirSupportedPlatformsBeOSCompatible ;
SubDirCcFlags -Wall -Wno-multichar -DHAVE_CONFIG_H=1 ; SubDirCcFlags -Wall -Wno-multichar -DHAVE_CONFIG_H=1 ;
StaticLibrary libntfs.a : StaticLibrary libntfs.a :
@@ -27,7 +25,6 @@ StaticLibrary libntfs.a :
runlist.c runlist.c
security.c security.c
unistr.c unistr.c
version.c
volume.c volume.c
; ;
File diff suppressed because it is too large Load Diff
@@ -3,7 +3,7 @@
* *
* Copyright (c) 2000-2004 Anton Altaparmakov * Copyright (c) 2000-2004 Anton Altaparmakov
* Copyright (c) 2004-2005 Yura Pakhuchiy * Copyright (c) 2004-2005 Yura Pakhuchiy
* Copyright (c) 2006 Szabolcs Szakacsits * Copyright (c) 2006-2007 Szabolcs Szakacsits
* *
* This program/include file is free software; you can redistribute it and/or * This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published * modify it under the terms of the GNU General Public License as published
@@ -92,6 +92,8 @@ extern int ntfs_attr_lookup(const ATTR_TYPES type, const ntfschar *name,
const VCN lowest_vcn, const u8 *val, const u32 val_len, const VCN lowest_vcn, const u8 *val, const u32 val_len,
ntfs_attr_search_ctx *ctx); ntfs_attr_search_ctx *ctx);
extern int ntfs_attr_position(const ATTR_TYPES type, ntfs_attr_search_ctx *ctx);
extern ATTR_DEF *ntfs_attr_find_in_attrdef(const ntfs_volume *vol, extern ATTR_DEF *ntfs_attr_find_in_attrdef(const ntfs_volume *vol,
const ATTR_TYPES type); const ATTR_TYPES type);
@@ -185,7 +187,8 @@ struct _ntfs_attr {
}; };
/** /**
* enum ntfs_attr_state_bits - bits for the state field in the ntfs_attr structure * enum ntfs_attr_state_bits - bits for the state field in the ntfs_attr
* structure
*/ */
typedef enum { typedef enum {
NA_Initialized, /* 1: structure is initialized. */ NA_Initialized, /* 1: structure is initialized. */
@@ -204,30 +207,15 @@ typedef enum {
#define NAttrSetNonResident(na) set_nattr_flag(na, NonResident) #define NAttrSetNonResident(na) set_nattr_flag(na, NonResident)
#define NAttrClearNonResident(na) clear_nattr_flag(na, NonResident) #define NAttrClearNonResident(na) clear_nattr_flag(na, NonResident)
#define GenNAttrIno(func_name,flag) \ #define GenNAttrIno(func_name, flag) \
static inline int NAttr##func_name(ntfs_attr *na) \ extern int NAttr##func_name(ntfs_attr *na); \
{ \ extern void NAttrSet##func_name(ntfs_attr *na); \
if (na->type == AT_DATA && na->name == AT_UNNAMED) \ extern void NAttrClear##func_name(ntfs_attr *na);
return (na->ni->flags & FILE_ATTR_##flag); \
return 0; \
} \
static inline void NAttrSet##func_name(ntfs_attr *na) \
{ \
if (na->type == AT_DATA && na->name == AT_UNNAMED) \
na->ni->flags |= FILE_ATTR_##flag; \
else \
ntfs_log_trace("BUG! Should be called only for "\
"unnamed data attribute.\n"); \
} \
static inline void NAttrClear##func_name(ntfs_attr *na) \
{ \
if (na->type == AT_DATA && na->name == AT_UNNAMED) \
na->ni->flags &= ~FILE_ATTR_##flag; \
}
GenNAttrIno(Compressed, COMPRESSED) GenNAttrIno(Compressed, FILE_ATTR_COMPRESSED)
GenNAttrIno(Encrypted, ENCRYPTED) GenNAttrIno(Encrypted, FILE_ATTR_ENCRYPTED)
GenNAttrIno(Sparse, SPARSE_FILE) GenNAttrIno(Sparse, FILE_ATTR_SPARSE_FILE)
#undef GenNAttrIno
/** /**
* union attr_val - Union of all known attribute values * union attr_val - Union of all known attribute values
@@ -318,7 +306,6 @@ extern int ntfs_attr_update_mapping_pairs(ntfs_attr *na, VCN from_vcn);
extern int ntfs_attr_truncate(ntfs_attr *na, const s64 newsize); extern int ntfs_attr_truncate(ntfs_attr *na, const s64 newsize);
// FIXME / TODO: Above here the file is cleaned up. (AIA)
/** /**
* get_attribute_value_length - return the length of the value of an attribute * get_attribute_value_length - return the length of the value of an attribute
* @a: pointer to a buffer containing the attribute record * @a: pointer to a buffer containing the attribute record
@@ -355,6 +342,7 @@ extern int ntfs_attr_exist(ntfs_inode *ni, const ATTR_TYPES type,
ntfschar *name, u32 name_len); ntfschar *name, u32 name_len);
extern int ntfs_attr_remove(ntfs_inode *ni, const ATTR_TYPES type, extern int ntfs_attr_remove(ntfs_inode *ni, const ATTR_TYPES type,
ntfschar *name, u32 name_len); ntfschar *name, u32 name_len);
extern s64 ntfs_attr_get_free_bits(ntfs_attr *na);
#endif /* defined _NTFS_ATTRIB_H */ #endif /* defined _NTFS_ATTRIB_H */
@@ -145,7 +145,6 @@ int ntfs_attrlist_entry_add(ntfs_inode *ni, ATTR_RECORD *attr)
ctx = ntfs_attr_get_search_ctx(ni, NULL); ctx = ntfs_attr_get_search_ctx(ni, NULL);
if (!ctx) { if (!ctx) {
err = errno; err = errno;
ntfs_log_trace("Failed to obtain attribute search context.\n");
goto err_out; goto err_out;
} }
if (!ntfs_attr_lookup(attr->type, (attr->name_length) ? (ntfschar*) if (!ntfs_attr_lookup(attr->type, (attr->name_length) ? (ntfschar*)
@@ -3,7 +3,7 @@
* *
* Copyright (c) 2002-2006 Anton Altaparmakov * Copyright (c) 2002-2006 Anton Altaparmakov
* Copyright (c) 2004-2005 Richard Russon * Copyright (c) 2004-2005 Richard Russon
* Copyright (c) 2004-2006 Szabolcs Szakacsits * Copyright (c) 2004-2008 Szabolcs Szakacsits
* *
* This program/include file is free software; you can redistribute it and/or * This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published * modify it under the terms of the GNU General Public License as published
@@ -117,10 +117,12 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
{ {
s64 bufsize, br; s64 bufsize, br;
u8 *buf, *lastbyte_buf; u8 *buf, *lastbyte_buf;
int bit, firstbyte, lastbyte, lastbyte_pos, tmp, err; int bit, firstbyte, lastbyte, lastbyte_pos, tmp, ret = -1;
if (!na || start_bit < 0 || count < 0) { if (!na || start_bit < 0 || count < 0) {
errno = EINVAL; errno = EINVAL;
ntfs_log_perror("%s: Invalid argument (%p, %lld, %lld)",
__FUNCTION__, na, (long long)start_bit, (long long)count);
return -1; return -1;
} }
@@ -147,9 +149,9 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
/* read it in... */ /* read it in... */
br = ntfs_attr_pread(na, start_bit >> 3, 1, buf); br = ntfs_attr_pread(na, start_bit >> 3, 1, buf);
if (br != 1) { if (br != 1) {
free(buf); if (br >= 0)
errno = EIO; errno = EIO;
return -1; goto free_err_out;
} }
/* and set or clear the appropriate bits in it. */ /* and set or clear the appropriate bits in it. */
while ((bit & 7) && count--) { while ((bit & 7) && count--) {
@@ -172,9 +174,9 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
lastbyte_pos = ((count + 7) >> 3) + firstbyte; lastbyte_pos = ((count + 7) >> 3) + firstbyte;
if (!lastbyte_pos) { if (!lastbyte_pos) {
// FIXME: Eeek! BUG! // FIXME: Eeek! BUG!
ntfs_log_trace("Eeek! lastbyte is zero. Leaving " ntfs_log_error("Lastbyte is zero. Leaving "
"inconsistent metadata.\n"); "inconsistent metadata.\n");
err = EIO; errno = EIO;
goto free_err_out; goto free_err_out;
} }
/* and it is in the currently loaded bitmap window... */ /* and it is in the currently loaded bitmap window... */
@@ -186,10 +188,11 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
3, 1, lastbyte_buf); 3, 1, lastbyte_buf);
if (br != 1) { if (br != 1) {
// FIXME: Eeek! We need rollback! (AIA) // FIXME: Eeek! We need rollback! (AIA)
ntfs_log_trace("Eeek! Read of last byte " if (br >= 0)
"failed. Leaving " errno = EIO;
"inconsistent metadata.\n"); ntfs_log_perror("Reading of last byte "
err = EIO; "failed (%lld). Leaving inconsistent "
"metadata", (long long)br);
goto free_err_out; goto free_err_out;
} }
/* and set/clear the appropriate bits in it. */ /* and set/clear the appropriate bits in it. */
@@ -211,9 +214,11 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
br = ntfs_attr_pwrite(na, tmp, bufsize, buf); br = ntfs_attr_pwrite(na, tmp, bufsize, buf);
if (br != bufsize) { if (br != bufsize) {
// FIXME: Eeek! We need rollback! (AIA) // FIXME: Eeek! We need rollback! (AIA)
ntfs_log_trace("Eeek! Failed to write buffer to bitmap. " if (br >= 0)
"Leaving inconsistent metadata.\n"); errno = EIO;
err = EIO; ntfs_log_perror("Failed to write buffer to bitmap "
"(%lld != %lld). Leaving inconsistent metadata",
(long long)br, (long long)bufsize);
goto free_err_out; goto free_err_out;
} }
@@ -234,22 +239,19 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
if (lastbyte && count != 0) { if (lastbyte && count != 0) {
// FIXME: Eeek! BUG! // FIXME: Eeek! BUG!
ntfs_log_trace("Eeek! Last buffer but count is not zero (= " ntfs_log_error("Last buffer but count is not zero "
"%lli). Leaving inconsistent metadata.\n", "(%lld). Leaving inconsistent metadata.\n",
(long long)count); (long long)count);
err = EIO; errno = EIO;
goto free_err_out; goto free_err_out;
} }
} while (count > 0); } while (count > 0);
/* Done! */ ret = 0;
free(buf);
return 0;
free_err_out: free_err_out:
free(buf); free(buf);
errno = err; return ret;
return -1;
} }
/** /**
@@ -265,7 +267,13 @@ free_err_out:
*/ */
int ntfs_bitmap_set_run(ntfs_attr *na, s64 start_bit, s64 count) int ntfs_bitmap_set_run(ntfs_attr *na, s64 start_bit, s64 count)
{ {
return ntfs_bitmap_set_bits_in_run(na, start_bit, count, 1); int ret;
ntfs_log_enter("Set from bit %lld, count %lld\n",
(long long)start_bit, (long long)count);
ret = ntfs_bitmap_set_bits_in_run(na, start_bit, count, 1);
ntfs_log_leave("\n");
return ret;
} }
/** /**
@@ -281,9 +289,12 @@ int ntfs_bitmap_set_run(ntfs_attr *na, s64 start_bit, s64 count)
*/ */
int ntfs_bitmap_clear_run(ntfs_attr *na, s64 start_bit, s64 count) int ntfs_bitmap_clear_run(ntfs_attr *na, s64 start_bit, s64 count)
{ {
ntfs_log_trace("Dealloc from bit 0x%llx, count 0x%llx.\n", int ret;
(long long)start_bit, (long long)count);
return ntfs_bitmap_set_bits_in_run(na, start_bit, count, 0); ntfs_log_enter("Clear from bit %lld, count %lld\n",
(long long)start_bit, (long long)count);
ret = ntfs_bitmap_set_bits_in_run(na, start_bit, count, 0);
ntfs_log_leave("\n");
return ret;
} }
@@ -70,5 +70,27 @@ static __inline__ int ntfs_bitmap_clear_bit(ntfs_attr *na, s64 bit)
return ntfs_bitmap_clear_run(na, bit, 1); return ntfs_bitmap_clear_run(na, bit, 1);
} }
/*
* rol32 - rotate a 32-bit value left
*
* @word: value to rotate
* @shift: bits to roll
*/
static __inline__ u32 ntfs_rol32(u32 word, unsigned int shift)
{
return (word << shift) | (word >> (32 - shift));
}
/*
* ror32 - rotate a 32-bit value right
*
* @word: value to rotate
* @shift: bits to roll
*/
static __inline__ u32 ntfs_ror32(u32 word, unsigned int shift)
{
return (word >> shift) | (word << (32 - shift));
}
#endif /* defined _NTFS_BITMAP_H */ #endif /* defined _NTFS_BITMAP_H */
@@ -2,7 +2,7 @@
* bootsect.c - Boot sector handling code. Originated from the Linux-NTFS project. * bootsect.c - Boot sector handling code. Originated from the Linux-NTFS project.
* *
* Copyright (c) 2000-2006 Anton Altaparmakov * Copyright (c) 2000-2006 Anton Altaparmakov
* Copyright (c) 2003-2006 Szabolcs Szakacsits * Copyright (c) 2003-2008 Szabolcs Szakacsits
* Copyright (c) 2005 Yura Pakhuchiy * Copyright (c) 2005 Yura Pakhuchiy
* *
* This program/include file is free software; you can redistribute it and/or * This program/include file is free software; you can redistribute it and/or
@@ -151,6 +151,13 @@ not_ntfs:
return ret; return ret;
} }
static const char *last_sector_error =
"HINTS: Either the volume is a RAID/LDM but it wasn't setup yet,\n"
" or it was not setup correctly (e.g. by not using mdadm --build ...),\n"
" or a wrong device is tried to be mounted,\n"
" or the partition table is corrupt (partition is smaller than NTFS),\n"
" or the NTFS boot sector is corrupt (NTFS size is not valid).\n";
/** /**
* ntfs_boot_sector_parse - setup an ntfs volume from an ntfs boot sector * ntfs_boot_sector_parse - setup an ntfs volume from an ntfs boot sector
* @vol: ntfs_volume to setup * @vol: ntfs_volume to setup
@@ -188,7 +195,7 @@ int ntfs_boot_sector_parse(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs)
} }
sectors = sle64_to_cpu(bs->number_of_sectors); sectors = sle64_to_cpu(bs->number_of_sectors);
ntfs_log_debug("NumberOfSectors = %lld\n", sectors); ntfs_log_debug("NumberOfSectors = %lld\n", (long long)sectors);
if (!sectors) { if (!sectors) {
ntfs_log_error("Volume size is set to zero.\n"); ntfs_log_error("Volume size is set to zero.\n");
return -1; return -1;
@@ -198,9 +205,7 @@ int ntfs_boot_sector_parse(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs)
SEEK_SET) == -1) { SEEK_SET) == -1) {
ntfs_log_perror("Failed to read last sector (%lld)", ntfs_log_perror("Failed to read last sector (%lld)",
(long long)sectors); (long long)sectors);
ntfs_log_error("Perhaps the volume is a RAID/LDM but it wasn't " ntfs_log_error("%s", last_sector_error);
"setup yet, or the\nwrong device was used, "
"or the partition table is incorrect.\n" );
return -1; return -1;
} }
@@ -208,8 +213,8 @@ int ntfs_boot_sector_parse(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs)
vol->mft_lcn = sle64_to_cpu(bs->mft_lcn); vol->mft_lcn = sle64_to_cpu(bs->mft_lcn);
vol->mftmirr_lcn = sle64_to_cpu(bs->mftmirr_lcn); vol->mftmirr_lcn = sle64_to_cpu(bs->mftmirr_lcn);
ntfs_log_debug("MFT LCN = 0x%llx\n", vol->mft_lcn); ntfs_log_debug("MFT LCN = %lld\n", (long long)vol->mft_lcn);
ntfs_log_debug("MFTMirr LCN = 0x%llx\n", vol->mftmirr_lcn); ntfs_log_debug("MFTMirr LCN = %lld\n", (long long)vol->mftmirr_lcn);
if (vol->mft_lcn > vol->nr_clusters || if (vol->mft_lcn > vol->nr_clusters ||
vol->mftmirr_lcn > vol->nr_clusters) { vol->mftmirr_lcn > vol->nr_clusters) {
ntfs_log_error("$MFT LCN (%lld) or $MFTMirr LCN (%lld) is " ntfs_log_error("$MFT LCN (%lld) or $MFTMirr LCN (%lld) is "
@@ -20,16 +20,12 @@
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#if defined(WINDOWS) || defined(__BEOS__) || defined (__HAIKU__)
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif #endif
#include "compat.h" #include "compat.h"
/* TODO: Add check for FFS in the configure script... (AIA) */
#ifndef HAVE_FFS #ifndef HAVE_FFS
/** /**
* ffs - Find the first set bit in an int * ffs - Find the first set bit in an int
@@ -69,5 +65,186 @@ int ffs(int x)
} }
#endif /* HAVE_FFS */ #endif /* HAVE_FFS */
#endif /* defined(WINDOWS) || defined(__BEOS__) || defined (__HAIKU__) */ #ifndef HAVE_DAEMON
/* ************************************************************
* From: src.opensolaris.org
* src/lib/libresolv2/common/bsd/daemon.c
*/
/*
* Copyright (c) 1997-2000 by Sun Microsystems, Inc.
* All rights reserved.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static const char sccsid[] = "@(#)daemon.c 8.1 (Berkeley) 6/4/93";
static const char rcsid[] = "$Id: compat.c,v 1.2 2008/07/17 15:01:48 szaka Exp $";
#endif /* LIBC_SCCS and not lint */
/*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
int daemon(int nochdir, int noclose) {
int fd;
switch (fork()) {
case -1:
return (-1);
case 0:
break;
default:
_exit(0);
}
if (setsid() == -1)
return (-1);
if (!nochdir)
(void)chdir("/");
if (!noclose && (fd = open("/dev/null", O_RDWR, 0)) != -1) {
(void)dup2(fd, 0);
(void)dup2(fd, 1);
(void)dup2(fd, 2);
if (fd > 2)
(void)close (fd);
}
return (0);
}
/*
* End: src/lib/libresolv2/common/bsd/daemon.c
*************************************************************/
#endif /* HAVE_DAEMON */
#ifndef HAVE_STRSEP
/* ************************************************************
* From: src.opensolaris.org
* src/lib/libresolv2/common/bsd/strsep.c
*/
/*
* Copyright (c) 1997, by Sun Microsystems, Inc.
* All rights reserved.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static const char sccsid[] = "strsep.c 8.1 (Berkeley) 6/4/93";
static const char rcsid[] = "$Id: compat.c,v 1.2 2008/07/17 15:01:48 szaka Exp $";
#endif /* LIBC_SCCS and not lint */
/*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_STDIO_H
#include <stdio.h>
#endif
/*
* Get next token from string *stringp, where tokens are possibly-empty
* strings separated by characters from delim.
*
* Writes NULs into the string at *stringp to end tokens.
* delim need not remain constant from call to call.
* On return, *stringp points past the last NUL written (if there might
* be further tokens), or is NULL (if there are definitely no more tokens).
*
* If *stringp is NULL, strsep returns NULL.
*/
char *strsep(char **stringp, const char *delim) {
char *s;
const char *spanp;
int c, sc;
char *tok;
if ((s = *stringp) == NULL)
return (NULL);
for (tok = s;;) {
c = *s++;
spanp = delim;
do {
if ((sc = *spanp++) == c) {
if (c == 0)
s = NULL;
else
s[-1] = 0;
*stringp = s;
return (tok);
}
} while (sc != 0);
}
/* NOTREACHED */
}
/*
* End: src/lib/libresolv2/common/bsd/strsep.c
*************************************************************/
#endif /* HAVE_STRSEP */
@@ -3,6 +3,7 @@
* *
* Copyright (c) 2002 Richard Russon * Copyright (c) 2002 Richard Russon
* Copyright (c) 2002-2004 Anton Altaparmakov * Copyright (c) 2002-2004 Anton Altaparmakov
* Copyright (c) 2008-2009 Szabolcs Szakacsits
* *
* This program/include file is free software; you can redistribute it and/or * This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published * modify it under the terms of the GNU General Public License as published
@@ -26,14 +27,28 @@
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif #endif
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
#ifdef WINDOWS #ifndef PATH_MAX
#define PATH_MAX 4096
#endif
#ifndef HAVE_FFS #ifndef HAVE_FFS
#define HAVE_FFS
extern int ffs(int i); extern int ffs(int i);
#endif /* HAVE_FFS */ #endif /* HAVE_FFS */
#ifndef HAVE_DAEMON
extern int daemon(int nochdir, int noclose);
#endif /* HAVE_DAEMON */
#ifndef HAVE_STRSEP
extern char *strsep(char **stringp, const char *delim);
#endif /* HAVE_STRSEP */
#ifdef WINDOWS
#define HAVE_STDIO_H /* mimic config.h */ #define HAVE_STDIO_H /* mimic config.h */
#define HAVE_STDARG_H #define HAVE_STDARG_H
@@ -44,9 +59,11 @@ extern int ffs(int i);
#else /* !defined WINDOWS */ #else /* !defined WINDOWS */
#ifndef __HAIKU__
#ifndef O_BINARY #ifndef O_BINARY
#define O_BINARY 0 /* unix is binary by default */ #define O_BINARY 0 /* unix is binary by default */
#endif #endif
#endif
#endif /* defined WINDOWS */ #endif /* defined WINDOWS */
@@ -100,8 +100,8 @@ static int ntfs_decompress(u8 *dest, const u32 dest_size,
ntfs_log_trace("Entering, cb_size = 0x%x.\n", (unsigned)cb_size); ntfs_log_trace("Entering, cb_size = 0x%x.\n", (unsigned)cb_size);
do_next_sb: do_next_sb:
ntfs_log_debug("Beginning sub-block at offset = 0x%x in the cb.\n", ntfs_log_debug("Beginning sub-block at offset = %d in the cb.\n",
cb - cb_start); (int)(cb - cb_start));
/* /*
* Have we reached the end of the compression block or the end of the * Have we reached the end of the compression block or the end of the
* decompressed data? The latter can happen for example if the current * decompressed data? The latter can happen for example if the current
@@ -63,9 +63,15 @@ void ntfs_debug_runlist_dump(const runlist_element *rl)
if (idx > -LCN_EINVAL - 1) if (idx > -LCN_EINVAL - 1)
idx = 4; idx = 4;
ntfs_log_debug("%-16llx %s %-16llx%s\n", rl[i].vcn, lcn_str[idx], rl[i].length, rl[i].length ? "" : " (runlist end)"); ntfs_log_debug("%-16lld %s %-16lld%s\n",
(long long)rl[i].vcn, lcn_str[idx],
(long long)rl[i].length,
rl[i].length ? "" : " (runlist end)");
} else } else
ntfs_log_debug("%-16llx %-16llx %-16llx%s\n", rl[i].vcn, rl[i].lcn, rl[i].length, rl[i].length ? "" : " (runlist end)"); ntfs_log_debug("%-16lld %-16lld %-16lld%s\n",
(long long)rl[i].vcn, (long long)rl[i].lcn,
(long long)rl[i].length,
rl[i].length ? "" : " (runlist end)");
} while (rl[i++].length); } while (rl[i++].length);
} }
@@ -178,7 +178,7 @@ s64 ntfs_pread(struct ntfs_device *dev, const s64 pos, s64 count, void *b)
s64 br, total; s64 br, total;
struct ntfs_device_operations *dops; struct ntfs_device_operations *dops;
ntfs_log_trace("Entering for pos 0x%llx, count 0x%llx.\n", pos, count); ntfs_log_trace("pos %lld, count %lld\n",(long long)pos,(long long)count);
if (!b || count < 0 || pos < 0) { if (!b || count < 0 || pos < 0) {
errno = EINVAL; errno = EINVAL;
@@ -229,7 +229,8 @@ s64 ntfs_pwrite(struct ntfs_device *dev, const s64 pos, s64 count,
s64 written, total, ret = -1; s64 written, total, ret = -1;
struct ntfs_device_operations *dops; struct ntfs_device_operations *dops;
ntfs_log_trace("Entering for pos 0x%llx, count 0x%llx.\n", pos, count); ntfs_log_trace("pos %lld, count %lld\n",(long long)pos,(long long)count);
if (!b || count < 0 || pos < 0) { if (!b || count < 0 || pos < 0) {
errno = EINVAL; errno = EINVAL;
goto out; goto out;
@@ -3,8 +3,8 @@
* *
* Copyright (c) 2002-2005 Anton Altaparmakov * Copyright (c) 2002-2005 Anton Altaparmakov
* Copyright (c) 2004-2005 Richard Russon * Copyright (c) 2004-2005 Richard Russon
* Copyright (c) 2004-2006 Szabolcs Szakacsits * Copyright (c) 2004-2008 Szabolcs Szakacsits
* Copyright (c) 2005-2006 Yura Pakhuchiy * Copyright (c) 2005-2007 Yura Pakhuchiy
* *
* This program/include file is free software; you can redistribute it and/or * This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published * modify it under the terms of the GNU General Public License as published
@@ -134,7 +134,7 @@ u64 ntfs_inode_lookup_by_name(ntfs_inode *dir_ni, const ntfschar *uname,
if (ntfs_attr_lookup(AT_INDEX_ROOT, NTFS_INDEX_I30, 4, CASE_SENSITIVE, 0, NULL, if (ntfs_attr_lookup(AT_INDEX_ROOT, NTFS_INDEX_I30, 4, CASE_SENSITIVE, 0, NULL,
0, ctx)) { 0, ctx)) {
ntfs_log_perror("Index root attribute missing in directory inode " ntfs_log_perror("Index root attribute missing in directory inode "
"0x%llx", (unsigned long long)dir_ni->mft_no); "%lld", (unsigned long long)dir_ni->mft_no);
goto put_err_out; goto put_err_out;
} }
/* Get to the index root value. */ /* Get to the index root value. */
@@ -143,7 +143,7 @@ u64 ntfs_inode_lookup_by_name(ntfs_inode *dir_ni, const ntfschar *uname,
index_block_size = le32_to_cpu(ir->index_block_size); index_block_size = le32_to_cpu(ir->index_block_size);
if (index_block_size < NTFS_BLOCK_SIZE || if (index_block_size < NTFS_BLOCK_SIZE ||
index_block_size & (index_block_size - 1)) { index_block_size & (index_block_size - 1)) {
ntfs_log_debug("Index block size %u is invalid.\n", ntfs_log_error("Index block size %u is invalid.\n",
(unsigned)index_block_size); (unsigned)index_block_size);
goto put_err_out; goto put_err_out;
} }
@@ -160,14 +160,23 @@ u64 ntfs_inode_lookup_by_name(ntfs_inode *dir_ni, const ntfschar *uname,
if ((u8*)ie < (u8*)ctx->mrec || (u8*)ie + if ((u8*)ie < (u8*)ctx->mrec || (u8*)ie +
sizeof(INDEX_ENTRY_HEADER) > index_end || sizeof(INDEX_ENTRY_HEADER) > index_end ||
(u8*)ie + le16_to_cpu(ie->key_length) > (u8*)ie + le16_to_cpu(ie->key_length) >
index_end) index_end) {
ntfs_log_error("Index entry out of bounds in inode %lld"
"\n", (unsigned long long)dir_ni->mft_no);
goto put_err_out; goto put_err_out;
}
/* /*
* The last entry cannot contain a name. It can however contain * The last entry cannot contain a name. It can however contain
* a pointer to a child node in the B+tree so we just break out. * a pointer to a child node in the B+tree so we just break out.
*/ */
if (ie->ie_flags & INDEX_ENTRY_END) if (ie->ie_flags & INDEX_ENTRY_END)
break; break;
if (!le16_to_cpu(ie->length)) {
ntfs_log_error("Zero length index entry in inode %lld"
"\n", (unsigned long long)dir_ni->mft_no);
goto put_err_out;
}
/* /*
* Not a perfect match, need to do full blown collation so we * Not a perfect match, need to do full blown collation so we
* know which way in the B+tree we have to go. * know which way in the B+tree we have to go.
@@ -226,8 +235,7 @@ u64 ntfs_inode_lookup_by_name(ntfs_inode *dir_ni, const ntfschar *uname,
/* Open the index allocation attribute. */ /* Open the index allocation attribute. */
ia_na = ntfs_attr_open(dir_ni, AT_INDEX_ALLOCATION, NTFS_INDEX_I30, 4); ia_na = ntfs_attr_open(dir_ni, AT_INDEX_ALLOCATION, NTFS_INDEX_I30, 4);
if (!ia_na) { if (!ia_na) {
ntfs_log_perror("Failed to open index allocation attribute. Directory " ntfs_log_perror("Failed to open index allocation (inode %lld)",
"inode 0x%llx is corrupt or driver bug",
(unsigned long long)dir_ni->mft_no); (unsigned long long)dir_ni->mft_no);
goto put_err_out; goto put_err_out;
} }
@@ -265,7 +273,7 @@ descend_into_child_node:
} }
if (sle64_to_cpu(ia->index_block_vcn) != vcn) { if (sle64_to_cpu(ia->index_block_vcn) != vcn) {
ntfs_log_debug("Actual VCN (0x%llx) of index buffer is different " ntfs_log_error("Actual VCN (0x%llx) of index buffer is different "
"from expected VCN (0x%llx).\n", "from expected VCN (0x%llx).\n",
(long long)sle64_to_cpu(ia->index_block_vcn), (long long)sle64_to_cpu(ia->index_block_vcn),
(long long)vcn); (long long)vcn);
@@ -273,7 +281,7 @@ descend_into_child_node:
goto close_err_out; goto close_err_out;
} }
if (le32_to_cpu(ia->index.allocated_size) + 0x18 != index_block_size) { if (le32_to_cpu(ia->index.allocated_size) + 0x18 != index_block_size) {
ntfs_log_debug("Index buffer (VCN 0x%llx) of directory inode 0x%llx " ntfs_log_error("Index buffer (VCN 0x%llx) of directory inode 0x%llx "
"has a size (%u) differing from the directory " "has a size (%u) differing from the directory "
"specified size (%u).\n", (long long)vcn, "specified size (%u).\n", (long long)vcn,
(unsigned long long)dir_ni->mft_no, (unsigned long long)dir_ni->mft_no,
@@ -284,7 +292,7 @@ descend_into_child_node:
} }
index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length); index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length);
if (index_end > (u8*)ia + index_block_size) { if (index_end > (u8*)ia + index_block_size) {
ntfs_log_debug("Size of index buffer (VCN 0x%llx) of directory inode " ntfs_log_error("Size of index buffer (VCN 0x%llx) of directory inode "
"0x%llx exceeds maximum size.\n", "0x%llx exceeds maximum size.\n",
(long long)vcn, (unsigned long long)dir_ni->mft_no); (long long)vcn, (unsigned long long)dir_ni->mft_no);
errno = EIO; errno = EIO;
@@ -305,8 +313,8 @@ descend_into_child_node:
sizeof(INDEX_ENTRY_HEADER) > index_end || sizeof(INDEX_ENTRY_HEADER) > index_end ||
(u8*)ie + le16_to_cpu(ie->key_length) > (u8*)ie + le16_to_cpu(ie->key_length) >
index_end) { index_end) {
ntfs_log_debug("Index entry out of bounds in directory " ntfs_log_error("Index entry out of bounds in directory "
"inode 0x%llx.\n", "inode %lld.\n",
(unsigned long long)dir_ni->mft_no); (unsigned long long)dir_ni->mft_no);
errno = EIO; errno = EIO;
goto close_err_out; goto close_err_out;
@@ -317,6 +325,13 @@ descend_into_child_node:
*/ */
if (ie->ie_flags & INDEX_ENTRY_END) if (ie->ie_flags & INDEX_ENTRY_END)
break; break;
if (!le16_to_cpu(ie->length)) {
errno = EIO;
ntfs_log_error("Zero length index entry in inode %lld"
"\n", (unsigned long long)dir_ni->mft_no);
goto close_err_out;
}
/* /*
* Not a perfect match, need to do full blown collation so we * Not a perfect match, need to do full blown collation so we
* know which way in the B+tree we have to go. * know which way in the B+tree we have to go.
@@ -361,8 +376,8 @@ descend_into_child_node:
*/ */
if (ie->ie_flags & INDEX_ENTRY_NODE) { if (ie->ie_flags & INDEX_ENTRY_NODE) {
if ((ia->index.ih_flags & NODE_MASK) == LEAF_NODE) { if ((ia->index.ih_flags & NODE_MASK) == LEAF_NODE) {
ntfs_log_debug("Index entry with child node found in a leaf " ntfs_log_error("Index entry with child node found in a leaf "
"node in directory inode 0x%llx.\n", "node in directory inode %lld.\n",
(unsigned long long)dir_ni->mft_no); (unsigned long long)dir_ni->mft_no);
errno = EIO; errno = EIO;
goto close_err_out; goto close_err_out;
@@ -371,7 +386,7 @@ descend_into_child_node:
vcn = sle64_to_cpup((u8*)ie + le16_to_cpu(ie->length) - 8); vcn = sle64_to_cpup((u8*)ie + le16_to_cpu(ie->length) - 8);
if (vcn >= 0) if (vcn >= 0)
goto descend_into_child_node; goto descend_into_child_node;
ntfs_log_debug("Negative child node vcn in directory inode " ntfs_log_error("Negative child node vcn in directory inode "
"0x%llx.\n", (unsigned long long)dir_ni->mft_no); "0x%llx.\n", (unsigned long long)dir_ni->mft_no);
errno = EIO; errno = EIO;
goto close_err_out; goto close_err_out;
@@ -446,10 +461,9 @@ ntfs_inode *ntfs_pathname_to_inode(ntfs_volume *vol, ntfs_inode *parent,
} }
} }
unicode = ntfs_calloc(MAX_PATH);
ascii = strdup(pathname); ascii = strdup(pathname);
if (!unicode || !ascii) { if (!ascii) {
ntfs_log_debug("Out of memory.\n"); ntfs_log_error("Out of memory.\n");
err = ENOMEM; err = ENOMEM;
goto close; goto close;
} }
@@ -466,9 +480,10 @@ ntfs_inode *ntfs_pathname_to_inode(ntfs_volume *vol, ntfs_inode *parent,
q++; q++;
} }
len = ntfs_mbstoucs(p, &unicode, MAX_PATH); len = ntfs_mbstoucs(p, &unicode);
if (len < 0) { if (len < 0) {
ntfs_log_debug("Couldn't convert name to Unicode: %s.\n", p); ntfs_log_perror("Could not convert filename to Unicode:"
" '%s'", p);
err = errno; err = errno;
goto close; goto close;
} else if (len > NTFS_MAX_NAME_LEN) { } else if (len > NTFS_MAX_NAME_LEN) {
@@ -499,6 +514,9 @@ ntfs_inode *ntfs_pathname_to_inode(ntfs_volume *vol, ntfs_inode *parent,
goto close; goto close;
} }
free(unicode);
unicode = NULL;
p = q; p = q;
while (p && *p && *p == PATH_SEP) while (p && *p && *p == PATH_SEP)
p++; p++;
@@ -578,6 +596,8 @@ static int ntfs_filldir(ntfs_inode *dir_ni, s64 *pos, u8 ivcn_bits,
return 0; return 0;
if (ie->key.file_name.file_attributes & FILE_ATTR_I30_INDEX_PRESENT) if (ie->key.file_name.file_attributes & FILE_ATTR_I30_INDEX_PRESENT)
dt_type = NTFS_DT_DIR; dt_type = NTFS_DT_DIR;
else if (fn->file_attributes & FILE_ATTR_SYSTEM)
dt_type = NTFS_DT_UNKNOWN;
else else
dt_type = NTFS_DT_REG; dt_type = NTFS_DT_REG;
return filldir(dirent, fn->file_name, fn->file_name_length, return filldir(dirent, fn->file_name, fn->file_name_length,
@@ -621,20 +641,20 @@ static MFT_REF ntfs_mft_get_parent_ref(ntfs_inode *ni)
if (!ctx) if (!ctx)
return ERR_MREF(-1); return ERR_MREF(-1);
if (ntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0, 0, 0, NULL, 0, ctx)) { if (ntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0, 0, 0, NULL, 0, ctx)) {
ntfs_log_debug("No file name found in inode 0x%llx. Corrupt " ntfs_log_error("No file name found in inode %lld\n",
"inode.\n", (unsigned long long)ni->mft_no); (unsigned long long)ni->mft_no);
goto err_out; goto err_out;
} }
if (ctx->attr->non_resident) { if (ctx->attr->non_resident) {
ntfs_log_debug("File name attribute must be resident. Corrupt inode " ntfs_log_error("File name attribute must be resident (inode "
"0x%llx.\n", (unsigned long long)ni->mft_no); "%lld)\n", (unsigned long long)ni->mft_no);
goto io_err_out; goto io_err_out;
} }
fn = (FILE_NAME_ATTR*)((u8*)ctx->attr + fn = (FILE_NAME_ATTR*)((u8*)ctx->attr +
le16_to_cpu(ctx->attr->value_offset)); le16_to_cpu(ctx->attr->value_offset));
if ((u8*)fn + le32_to_cpu(ctx->attr->value_length) > if ((u8*)fn + le32_to_cpu(ctx->attr->value_length) >
(u8*)ctx->attr + le32_to_cpu(ctx->attr->length)) { (u8*)ctx->attr + le32_to_cpu(ctx->attr->length)) {
ntfs_log_debug("Corrupt file name attribute in inode 0x%llx.\n", ntfs_log_error("Corrupt file name attribute in inode %lld.\n",
(unsigned long long)ni->mft_no); (unsigned long long)ni->mft_no);
goto io_err_out; goto io_err_out;
} }
@@ -695,7 +715,7 @@ int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos,
vol = dir_ni->vol; vol = dir_ni->vol;
ntfs_log_trace("Entering for inode 0x%llx, *pos 0x%llx.\n", ntfs_log_trace("Entering for inode %lld, *pos 0x%llx.\n",
(unsigned long long)dir_ni->mft_no, (long long)*pos); (unsigned long long)dir_ni->mft_no, (long long)*pos);
/* Open the index allocation attribute. */ /* Open the index allocation attribute. */
@@ -703,7 +723,7 @@ int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos,
if (!ia_na) { if (!ia_na) {
if (errno != ENOENT) { if (errno != ENOENT) {
ntfs_log_perror("Failed to open index allocation attribute. " ntfs_log_perror("Failed to open index allocation attribute. "
"Directory inode 0x%llx is corrupt or bug", "Directory inode %lld is corrupt or bug",
(unsigned long long)dir_ni->mft_no); (unsigned long long)dir_ni->mft_no);
return -1; return -1;
} }
@@ -724,7 +744,7 @@ int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos,
le16_to_cpu(dir_ni->mrec->sequence_number)), le16_to_cpu(dir_ni->mrec->sequence_number)),
NTFS_DT_DIR); NTFS_DT_DIR);
if (rc) if (rc)
goto done; goto err_out;
++*pos; ++*pos;
} }
if (*pos == 1) { if (*pos == 1) {
@@ -739,7 +759,7 @@ int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos,
rc = filldir(dirent, dotdot, 2, FILE_NAME_POSIX, *pos, rc = filldir(dirent, dotdot, 2, FILE_NAME_POSIX, *pos,
parent_mref, NTFS_DT_DIR); parent_mref, NTFS_DT_DIR);
if (rc) if (rc)
goto done; goto err_out;
++*pos; ++*pos;
} }
@@ -752,8 +772,8 @@ int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos,
/* Find the index root attribute in the mft record. */ /* Find the index root attribute in the mft record. */
if (ntfs_attr_lookup(AT_INDEX_ROOT, NTFS_INDEX_I30, 4, CASE_SENSITIVE, 0, NULL, if (ntfs_attr_lookup(AT_INDEX_ROOT, NTFS_INDEX_I30, 4, CASE_SENSITIVE, 0, NULL,
0, ctx)) { 0, ctx)) {
ntfs_log_debug("Index root attribute missing in directory inode " ntfs_log_perror("Index root attribute missing in directory inode "
"0x%llx.\n", (unsigned long long)dir_ni->mft_no); "%lld", (unsigned long long)dir_ni->mft_no);
goto dir_err_out; goto dir_err_out;
} }
/* Get to the index root value. */ /* Get to the index root value. */
@@ -764,7 +784,7 @@ int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos,
index_block_size = le32_to_cpu(ir->index_block_size); index_block_size = le32_to_cpu(ir->index_block_size);
if (index_block_size < NTFS_BLOCK_SIZE || if (index_block_size < NTFS_BLOCK_SIZE ||
index_block_size & (index_block_size - 1)) { index_block_size & (index_block_size - 1)) {
ntfs_log_debug("Index block size %u is invalid.\n", ntfs_log_error("Index block size %u is invalid.\n",
(unsigned)index_block_size); (unsigned)index_block_size);
goto dir_err_out; goto dir_err_out;
} }
@@ -794,7 +814,7 @@ int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos,
* or signals an error (both covered by the rc test). * or signals an error (both covered by the rc test).
*/ */
for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) { for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) {
ntfs_log_debug("In index root, offset 0x%x.\n", (u8*)ie - (u8*)ir); ntfs_log_debug("In index root, offset %d.\n", (int)((u8*)ie - (u8*)ir));
/* Bounds checks. */ /* Bounds checks. */
if ((u8*)ie < (u8*)ctx->mrec || (u8*)ie + if ((u8*)ie < (u8*)ctx->mrec || (u8*)ie +
sizeof(INDEX_ENTRY_HEADER) > index_end || sizeof(INDEX_ENTRY_HEADER) > index_end ||
@@ -804,6 +824,10 @@ int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos,
/* The last entry cannot contain a name. */ /* The last entry cannot contain a name. */
if (ie->ie_flags & INDEX_ENTRY_END) if (ie->ie_flags & INDEX_ENTRY_END)
break; break;
if (!le16_to_cpu(ie->length))
goto dir_err_out;
/* Skip index root entry if continuing previous readdir. */ /* Skip index root entry if continuing previous readdir. */
if (ir_pos > (u8*)ie - (u8*)ir) if (ir_pos > (u8*)ie - (u8*)ir)
continue; continue;
@@ -816,7 +840,7 @@ int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos,
if (rc) { if (rc) {
ntfs_attr_put_search_ctx(ctx); ntfs_attr_put_search_ctx(ctx);
ctx = NULL; ctx = NULL;
goto done; goto err_out;
} }
} }
ntfs_attr_put_search_ctx(ctx); ntfs_attr_put_search_ctx(ctx);
@@ -850,7 +874,7 @@ skip_index_root:
bmp_pos = ia_pos >> index_block_size_bits; bmp_pos = ia_pos >> index_block_size_bits;
if (bmp_pos >> 3 >= bmp_na->data_size) { if (bmp_pos >> 3 >= bmp_na->data_size) {
ntfs_log_debug("Current index position exceeds index bitmap " ntfs_log_error("Current index position exceeds index bitmap "
"size.\n"); "size.\n");
goto dir_err_out; goto dir_err_out;
} }
@@ -881,6 +905,7 @@ find_next_index_buffer:
if (bmp_buf_pos >> 3 < bmp_buf_size) if (bmp_buf_pos >> 3 < bmp_buf_size)
continue; continue;
/* Read next chunk from the index bitmap. */ /* Read next chunk from the index bitmap. */
bmp_buf_pos = 0;
if ((bmp_pos >> 3) + bmp_buf_size > bmp_na->data_size) if ((bmp_pos >> 3) + bmp_buf_size > bmp_na->data_size)
bmp_buf_size = bmp_na->data_size - (bmp_pos >> 3); bmp_buf_size = bmp_na->data_size - (bmp_pos >> 3);
br = ntfs_attr_pread(bmp_na, bmp_pos >> 3, bmp_buf_size, bmp); br = ntfs_attr_pread(bmp_na, bmp_pos >> 3, bmp_buf_size, bmp);
@@ -907,7 +932,7 @@ find_next_index_buffer:
ia_start = ia_pos & ~(s64)(index_block_size - 1); ia_start = ia_pos & ~(s64)(index_block_size - 1);
if (sle64_to_cpu(ia->index_block_vcn) != ia_start >> if (sle64_to_cpu(ia->index_block_vcn) != ia_start >>
index_vcn_size_bits) { index_vcn_size_bits) {
ntfs_log_debug("Actual VCN (0x%llx) of index buffer is different " ntfs_log_error("Actual VCN (0x%llx) of index buffer is different "
"from expected VCN (0x%llx) in inode 0x%llx.\n", "from expected VCN (0x%llx) in inode 0x%llx.\n",
(long long)sle64_to_cpu(ia->index_block_vcn), (long long)sle64_to_cpu(ia->index_block_vcn),
(long long)ia_start >> index_vcn_size_bits, (long long)ia_start >> index_vcn_size_bits,
@@ -915,7 +940,7 @@ find_next_index_buffer:
goto dir_err_out; goto dir_err_out;
} }
if (le32_to_cpu(ia->index.allocated_size) + 0x18 != index_block_size) { if (le32_to_cpu(ia->index.allocated_size) + 0x18 != index_block_size) {
ntfs_log_debug("Index buffer (VCN 0x%llx) of directory inode 0x%llx " ntfs_log_error("Index buffer (VCN 0x%llx) of directory inode %lld "
"has a size (%u) differing from the directory " "has a size (%u) differing from the directory "
"specified size (%u).\n", (long long)ia_start >> "specified size (%u).\n", (long long)ia_start >>
index_vcn_size_bits, index_vcn_size_bits,
@@ -926,8 +951,8 @@ find_next_index_buffer:
} }
index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length); index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length);
if (index_end > (u8*)ia + index_block_size) { if (index_end > (u8*)ia + index_block_size) {
ntfs_log_debug("Size of index buffer (VCN 0x%llx) of directory inode " ntfs_log_error("Size of index buffer (VCN 0x%llx) of directory inode "
"0x%llx exceeds maximum size.\n", "%lld exceeds maximum size.\n",
(long long)ia_start >> index_vcn_size_bits, (long long)ia_start >> index_vcn_size_bits,
(unsigned long long)dir_ni->mft_no); (unsigned long long)dir_ni->mft_no);
goto dir_err_out; goto dir_err_out;
@@ -948,13 +973,17 @@ find_next_index_buffer:
sizeof(INDEX_ENTRY_HEADER) > index_end || sizeof(INDEX_ENTRY_HEADER) > index_end ||
(u8*)ie + le16_to_cpu(ie->key_length) > (u8*)ie + le16_to_cpu(ie->key_length) >
index_end) { index_end) {
ntfs_log_debug("Index entry out of bounds in directory inode " ntfs_log_error("Index entry out of bounds in directory inode "
"0x%llx.\n", (unsigned long long)dir_ni->mft_no); "%lld.\n", (unsigned long long)dir_ni->mft_no);
goto dir_err_out; goto dir_err_out;
} }
/* The last entry cannot contain a name. */ /* The last entry cannot contain a name. */
if (ie->ie_flags & INDEX_ENTRY_END) if (ie->ie_flags & INDEX_ENTRY_END)
break; break;
if (!le16_to_cpu(ie->length))
goto dir_err_out;
/* Skip index entry if continuing previous readdir. */ /* Skip index entry if continuing previous readdir. */
if (ia_pos - ia_start > (u8*)ie - (u8*)ia) if (ia_pos - ia_start > (u8*)ie - (u8*)ia)
continue; continue;
@@ -965,7 +994,7 @@ find_next_index_buffer:
rc = ntfs_filldir(dir_ni, pos, index_vcn_size_bits, rc = ntfs_filldir(dir_ni, pos, index_vcn_size_bits,
INDEX_TYPE_ALLOCATION, ia, ie, dirent, filldir); INDEX_TYPE_ALLOCATION, ia, ie, dirent, filldir);
if (rc) if (rc)
goto done; goto err_out;
} }
goto find_next_index_buffer; goto find_next_index_buffer;
EOD: EOD:
@@ -978,13 +1007,7 @@ done:
ntfs_attr_close(bmp_na); ntfs_attr_close(bmp_na);
if (ia_na) if (ia_na)
ntfs_attr_close(ia_na); ntfs_attr_close(ia_na);
#ifdef DEBUG
if (!rc)
ntfs_log_debug("EOD, *pos 0x%llx, returning 0.\n", (long long)*pos); ntfs_log_debug("EOD, *pos 0x%llx, returning 0.\n", (long long)*pos);
else
ntfs_log_debug("filldir returned %i, *pos 0x%llx, returning 0.\n",
rc, (long long)*pos);
#endif
return 0; return 0;
dir_err_out: dir_err_out:
errno = EIO; errno = EIO;
@@ -1037,7 +1060,7 @@ err_out:
*/ */
static ntfs_inode *__ntfs_create(ntfs_inode *dir_ni, static ntfs_inode *__ntfs_create(ntfs_inode *dir_ni,
ntfschar *name, u8 name_len, dev_t type, dev_t dev, ntfschar *name, u8 name_len, dev_t type, dev_t dev,
ntfschar *target, u8 target_len) ntfschar *target, int target_len)
{ {
ntfs_inode *ni; ntfs_inode *ni;
int rollback_data = 0, rollback_sd = 0; int rollback_data = 0, rollback_sd = 0;
@@ -1206,6 +1229,8 @@ static ntfs_inode *__ntfs_create(ntfs_inode *dir_ni,
fn->last_data_change_time = utc2ntfs(ni->last_data_change_time); fn->last_data_change_time = utc2ntfs(ni->last_data_change_time);
fn->last_mft_change_time = utc2ntfs(ni->last_mft_change_time); fn->last_mft_change_time = utc2ntfs(ni->last_mft_change_time);
fn->last_access_time = utc2ntfs(ni->last_access_time); fn->last_access_time = utc2ntfs(ni->last_access_time);
fn->data_size = cpu_to_sle64(ni->data_size);
fn->allocated_size = cpu_to_sle64(ni->allocated_size);
memcpy(fn->file_name, name, name_len * sizeof(ntfschar)); memcpy(fn->file_name, name, name_len * sizeof(ntfschar));
/* Add FILE_NAME attribute to inode. */ /* Add FILE_NAME attribute to inode. */
if (ntfs_attr_add(ni, AT_FILE_NAME, AT_UNNAMED, 0, (u8*)fn, fn_len)) { if (ntfs_attr_add(ni, AT_FILE_NAME, AT_UNNAMED, 0, (u8*)fn, fn_len)) {
@@ -1284,10 +1309,11 @@ ntfs_inode *ntfs_create_device(ntfs_inode *dir_ni, ntfschar *name, u8 name_len,
} }
ntfs_inode *ntfs_create_symlink(ntfs_inode *dir_ni, ntfschar *name, u8 name_len, ntfs_inode *ntfs_create_symlink(ntfs_inode *dir_ni, ntfschar *name, u8 name_len,
ntfschar *target, u8 target_len) ntfschar *target, int target_len)
{ {
if (!target || !target_len) { if (!target || !target_len) {
ntfs_log_error("Invalid arguments.\n"); ntfs_log_error("%s: Invalid argument (%p, %d)\n", __FUNCTION__,
target, target_len);
return NULL; return NULL;
} }
return __ntfs_create(dir_ni, name, name_len, S_IFLNK, 0, return __ntfs_create(dir_ni, name, name_len, S_IFLNK, 0,
@@ -1312,7 +1338,7 @@ int ntfs_check_empty_dir(ntfs_inode *ni)
/* Non-empty directory? */ /* Non-empty directory? */
if ((na->data_size != sizeof(INDEX_ROOT) + sizeof(INDEX_ENTRY_HEADER))){ if ((na->data_size != sizeof(INDEX_ROOT) + sizeof(INDEX_ENTRY_HEADER))){
/* Both ENOTEMPTY and EEXIST are ok. We use the more common. */ /* Both ENOTEMPTY and EEXIST are ok. We use the more common. */
errno = EEXIST; errno = ENOTEMPTY;
ntfs_log_debug("Directory is not empty\n"); ntfs_log_debug("Directory is not empty\n");
ret = -1; ret = -1;
} }
@@ -1327,7 +1353,7 @@ static int ntfs_check_unlinkable_dir(ntfs_inode *ni, FILE_NAME_ATTR *fn)
int ret; int ret;
ret = ntfs_check_empty_dir(ni); ret = ntfs_check_empty_dir(ni);
if (!ret || errno != EEXIST) if (!ret || errno != ENOTEMPTY)
return ret; return ret;
/* /*
* Directory is non-empty, so we can unlink only if there is more than * Directory is non-empty, so we can unlink only if there is more than
@@ -1335,7 +1361,7 @@ static int ntfs_check_unlinkable_dir(ntfs_inode *ni, FILE_NAME_ATTR *fn)
*/ */
if ((link_count == 1) || if ((link_count == 1) ||
(link_count == 2 && fn->file_name_type == FILE_NAME_DOS)) { (link_count == 2 && fn->file_name_type == FILE_NAME_DOS)) {
errno = EEXIST; errno = ENOTEMPTY;
ntfs_log_debug("Non-empty directory without hard links\n"); ntfs_log_debug("Non-empty directory without hard links\n");
goto no_hardlink; goto no_hardlink;
} }
@@ -1360,7 +1386,6 @@ no_hardlink:
int ntfs_delete(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name, u8 name_len) int ntfs_delete(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name, u8 name_len)
{ {
ntfs_attr_search_ctx *actx = NULL; ntfs_attr_search_ctx *actx = NULL;
ntfs_index_context *ictx = NULL;
FILE_NAME_ATTR *fn = NULL; FILE_NAME_ATTR *fn = NULL;
BOOL looking_for_dos_name = FALSE, looking_for_win32_name = FALSE; BOOL looking_for_dos_name = FALSE, looking_for_win32_name = FALSE;
BOOL case_sensitive_match = TRUE; BOOL case_sensitive_match = TRUE;
@@ -1417,8 +1442,9 @@ search:
/* Ignore hard links from other directories */ /* Ignore hard links from other directories */
if (dir_ni->mft_no != MREF_LE(fn->parent_directory)) { if (dir_ni->mft_no != MREF_LE(fn->parent_directory)) {
ntfs_log_debug("MFT record numbers don't match " ntfs_log_debug("MFT record numbers don't match "
"(%llu != %llu)\n", dir_ni->mft_no, "(%llu != %llu)\n",
MREF_LE(fn->parent_directory)); (long long unsigned)dir_ni->mft_no,
(long long unsigned)MREF_LE(fn->parent_directory));
continue; continue;
} }
@@ -1455,19 +1481,7 @@ search:
if (ntfs_check_unlinkable_dir(ni, fn) < 0) if (ntfs_check_unlinkable_dir(ni, fn) < 0)
goto err_out; goto err_out;
ictx = ntfs_index_ctx_get(dir_ni, NTFS_INDEX_I30, 4); if (ntfs_index_remove(dir_ni, fn, le32_to_cpu(actx->attr->value_length)))
if (!ictx)
goto err_out;
if (ntfs_index_lookup(fn, le32_to_cpu(actx->attr->value_length), ictx))
goto err_out;
if (((FILE_NAME_ATTR*)ictx->data)->file_attributes &
FILE_ATTR_REPARSE_POINT) {
errno = EOPNOTSUPP;
goto err_out;
}
if (ntfs_index_rm(ictx))
goto err_out; goto err_out;
if (ntfs_attr_record_rm(actx)) if (ntfs_attr_record_rm(actx))
@@ -1489,8 +1503,10 @@ search:
* case there are no reference to this inode left, so we should free all * case there are no reference to this inode left, so we should free all
* non-resident attributes and mark all MFT record as not in use. * non-resident attributes and mark all MFT record as not in use.
*/ */
if (ni->mrec->link_count) if (ni->mrec->link_count) {
goto out; ntfs_inode_update_times(ni, NTFS_UPDATE_CTIME);
goto ok;
}
ntfs_attr_reinit_search_ctx(actx); ntfs_attr_reinit_search_ctx(actx);
while (!ntfs_attrs_walk(actx)) { while (!ntfs_attrs_walk(actx)) {
if (actx->attr->non_resident) { if (actx->attr->non_resident) {
@@ -1531,12 +1547,14 @@ search:
"Leaving inconsistent metadata.\n"); "Leaving inconsistent metadata.\n");
} }
ni = NULL; ni = NULL;
ok:
ntfs_inode_update_times(dir_ni, NTFS_UPDATE_MCTIME);
out: out:
if (actx) if (actx)
ntfs_attr_put_search_ctx(actx); ntfs_attr_put_search_ctx(actx);
if (ictx) if (ntfs_inode_close(dir_ni) && !err)
ntfs_index_ctx_put(ictx); err = errno;
if (ni && ntfs_inode_close(ni) && !err) if (ntfs_inode_close(ni) && !err)
err = errno; err = errno;
if (err) { if (err) {
errno = err; errno = err;
@@ -1614,22 +1632,11 @@ int ntfs_link(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name, u8 name_len)
} }
/* Add FILE_NAME attribute to inode. */ /* Add FILE_NAME attribute to inode. */
if (ntfs_attr_add(ni, AT_FILE_NAME, AT_UNNAMED, 0, (u8*)fn, fn_len)) { if (ntfs_attr_add(ni, AT_FILE_NAME, AT_UNNAMED, 0, (u8*)fn, fn_len)) {
ntfs_index_context *ictx;
err = errno;
ntfs_log_error("Failed to add FILE_NAME attribute.\n"); ntfs_log_error("Failed to add FILE_NAME attribute.\n");
err = errno;
/* Try to remove just added attribute from index. */ /* Try to remove just added attribute from index. */
ictx = ntfs_index_ctx_get(dir_ni, NTFS_INDEX_I30, 4); if (ntfs_index_remove(dir_ni, fn, fn_len))
if (!ictx)
goto rollback_failed; goto rollback_failed;
if (ntfs_index_lookup(fn, fn_len, ictx)) {
ntfs_index_ctx_put(ictx);
goto rollback_failed;
}
if (ntfs_index_rm(ictx)) {
ntfs_index_ctx_put(ictx);
goto rollback_failed;
}
goto err_out; goto err_out;
} }
/* Increment hard links count. */ /* Increment hard links count. */
@@ -4,6 +4,7 @@
* Copyright (c) 2002 Anton Altaparmakov * Copyright (c) 2002 Anton Altaparmakov
* Copyright (c) 2005-2006 Yura Pakhuchiy * Copyright (c) 2005-2006 Yura Pakhuchiy
* Copyright (c) 2004-2005 Richard Russon * Copyright (c) 2004-2005 Richard Russon
* Copyright (c) 2005-2008 Szabolcs Szakacsits
* *
* This program/include file is free software; you can redistribute it and/or * This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published * modify it under the terms of the GNU General Public License as published
@@ -28,17 +29,10 @@
#define PATH_SEP '/' #define PATH_SEP '/'
#ifdef __HAIKU__
#ifndef MAX_PATH #ifndef MAX_PATH
#define MAX_PATH 1024 #define MAX_PATH 1024
#endif #endif
/*
* We do not have S_IFSOCK under BeOS/Haiku
*/
#if defined(__BEOS__) || defined(__HAIKU__)
#ifndef S_IFSOCK
#define S_IFSOCK 0140000
#endif
#endif #endif
/* /*
@@ -82,7 +76,7 @@ extern ntfs_inode *ntfs_create(ntfs_inode *dir_ni, ntfschar *name, u8 name_len,
extern ntfs_inode *ntfs_create_device(ntfs_inode *dir_ni, extern ntfs_inode *ntfs_create_device(ntfs_inode *dir_ni,
ntfschar *name, u8 name_len, dev_t type, dev_t dev); ntfschar *name, u8 name_len, dev_t type, dev_t dev);
extern ntfs_inode *ntfs_create_symlink(ntfs_inode *dir_ni, extern ntfs_inode *ntfs_create_symlink(ntfs_inode *dir_ni,
ntfschar *name, u8 name_len, ntfschar *target, u8 target_len); ntfschar *name, u8 name_len, ntfschar *target, int target_len);
extern int ntfs_check_empty_dir(ntfs_inode *ni); extern int ntfs_check_empty_dir(ntfs_inode *ni);
extern int ntfs_delete(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name, extern int ntfs_delete(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name,
u8 name_len); u8 name_len);
@@ -48,9 +48,6 @@
#ifdef HAVE_SYS_BYTEORDER_H #ifdef HAVE_SYS_BYTEORDER_H
#include <sys/byteorder.h> #include <sys/byteorder.h>
#endif #endif
#ifdef HAVE_BYTEORDER_H
#include <byteorder.h>
#endif
#ifdef HAVE_SYS_PARAM_H #ifdef HAVE_SYS_PARAM_H
#include <sys/param.h> #include <sys/param.h>
#endif #endif
@@ -4,7 +4,7 @@
* Copyright (c) 2004-2005 Anton Altaparmakov * Copyright (c) 2004-2005 Anton Altaparmakov
* Copyright (c) 2004-2005 Richard Russon * Copyright (c) 2004-2005 Richard Russon
* Copyright (c) 2005-2006 Yura Pakhuchiy * Copyright (c) 2005-2006 Yura Pakhuchiy
* Copyright (c) 2005-2006 Szabolcs Szakacsits * Copyright (c) 2005-2008 Szabolcs Szakacsits
* *
* This program/include file is free software; you can redistribute it and/or * This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published * modify it under the terms of the GNU General Public License as published
@@ -78,18 +78,17 @@ static VCN ntfs_ib_pos_to_vcn(ntfs_index_context *icx, s64 pos)
return pos >> icx->vcn_size_bits; return pos >> icx->vcn_size_bits;
} }
static int ntfs_ib_write(ntfs_index_context *icx, VCN vcn, void *buf) static int ntfs_ib_write(ntfs_index_context *icx, INDEX_BLOCK *ib)
{ {
s64 ret; s64 ret, vcn = sle64_to_cpu(ib->index_block_vcn);
ntfs_log_trace("vcn: %lld\n", vcn); ntfs_log_trace("vcn: %lld\n", (long long)vcn);
ret = ntfs_attr_mst_pwrite(icx->ia_na, ntfs_ib_vcn_to_pos(icx, vcn), ret = ntfs_attr_mst_pwrite(icx->ia_na, ntfs_ib_vcn_to_pos(icx, vcn),
1, icx->block_size, buf); 1, icx->block_size, ib);
if (ret != 1) { if (ret != 1) {
ntfs_log_perror("Failed to write index block %lld of inode " ntfs_log_perror("Failed to write index block %lld, inode %llu",
"%llu", (long long)vcn, (long long)vcn, (unsigned long long)icx->ni->mft_no);
(unsigned long long)icx->ni->mft_no);
return STATUS_ERROR; return STATUS_ERROR;
} }
@@ -98,7 +97,7 @@ static int ntfs_ib_write(ntfs_index_context *icx, VCN vcn, void *buf)
static int ntfs_icx_ib_write(ntfs_index_context *icx) static int ntfs_icx_ib_write(ntfs_index_context *icx)
{ {
if (ntfs_ib_write(icx, icx->ib_vcn, icx->ib)) if (ntfs_ib_write(icx, icx->ib))
return STATUS_ERROR; return STATUS_ERROR;
icx->ib_dirty = FALSE; icx->ib_dirty = FALSE;
@@ -148,18 +147,14 @@ static void ntfs_index_ctx_free(ntfs_index_context *icx)
if (icx->actx) if (icx->actx)
ntfs_attr_put_search_ctx(icx->actx); ntfs_attr_put_search_ctx(icx->actx);
if (icx->is_in_root) { if (!icx->is_in_root) {
if (icx->ia_na)
ntfs_attr_close(icx->ia_na);
return;
}
if (icx->ib_dirty) { if (icx->ib_dirty) {
/* FIXME: Error handling!!! */ /* FIXME: Error handling!!! */
ntfs_ib_write(icx, icx->ib_vcn, icx->ib); ntfs_ib_write(icx, icx->ib);
}
free(icx->ib);
} }
free(icx->ib);
ntfs_attr_close(icx->ia_na); ntfs_attr_close(icx->ia_na);
} }
@@ -225,7 +220,7 @@ static u8 *ntfs_ie_get_end(INDEX_HEADER *ih)
static int ntfs_ie_end(INDEX_ENTRY *ie) static int ntfs_ie_end(INDEX_ENTRY *ie)
{ {
return ie->ie_flags & INDEX_ENTRY_END; return ie->ie_flags & INDEX_ENTRY_END || !ie->length;
} }
/** /**
@@ -306,11 +301,13 @@ static int ntfs_ih_numof_entries(INDEX_HEADER *ih)
{ {
int n; int n;
INDEX_ENTRY *ie; INDEX_ENTRY *ie;
u8 *end;
ntfs_log_trace("Entering\n"); ntfs_log_trace("Entering\n");
end = ntfs_ie_get_end(ih);
ie = ntfs_ie_get_first(ih); ie = ntfs_ie_get_first(ih);
for (n = 0; !ntfs_ie_end(ie); n++) for (n = 0; !ntfs_ie_end(ie) && (u8 *)ie < end; n++)
ie = ntfs_ie_get_next(ie); ie = ntfs_ie_get_next(ie);
return n; return n;
} }
@@ -434,10 +431,8 @@ static INDEX_ROOT *ntfs_ir_lookup(ntfs_inode *ni, ntfschar *name,
ntfs_log_trace("Entering\n"); ntfs_log_trace("Entering\n");
*ctx = ntfs_attr_get_search_ctx(ni, NULL); *ctx = ntfs_attr_get_search_ctx(ni, NULL);
if (!*ctx) { if (!*ctx)
ntfs_log_perror("Failed to get $INDEX_ROOT search context");
return NULL; return NULL;
}
if (ntfs_attr_lookup(AT_INDEX_ROOT, name, name_len, CASE_SENSITIVE, if (ntfs_attr_lookup(AT_INDEX_ROOT, name, name_len, CASE_SENSITIVE,
0, NULL, 0, *ctx)) { 0, NULL, 0, *ctx)) {
@@ -454,8 +449,21 @@ static INDEX_ROOT *ntfs_ir_lookup(ntfs_inode *ni, ntfschar *name,
ir = (INDEX_ROOT *)((char *)a + le16_to_cpu(a->value_offset)); ir = (INDEX_ROOT *)((char *)a + le16_to_cpu(a->value_offset));
err_out: err_out:
if (!ir) if (!ir) {
ntfs_attr_put_search_ctx(*ctx); ntfs_attr_put_search_ctx(*ctx);
*ctx = NULL;
}
return ir;
}
static INDEX_ROOT *ntfs_ir_lookup2(ntfs_inode *ni, ntfschar *name, u32 len)
{
ntfs_attr_search_ctx *ctx;
INDEX_ROOT *ir;
ir = ntfs_ir_lookup(ni, name, len, &ctx);
if (ir)
ntfs_attr_put_search_ctx(ctx);
return ir; return ir;
} }
@@ -577,7 +585,7 @@ static int ntfs_ib_read(ntfs_index_context *icx, VCN vcn, INDEX_BLOCK *dst)
{ {
s64 pos, ret; s64 pos, ret;
ntfs_log_trace("vcn: %lld\n", vcn); ntfs_log_trace("vcn: %lld\n", (long long)vcn);
pos = ntfs_ib_vcn_to_pos(icx, vcn); pos = ntfs_ib_vcn_to_pos(icx, vcn);
@@ -651,15 +659,13 @@ static int ntfs_icx_parent_dec(ntfs_index_context *icx)
* the call to ntfs_index_ctx_put() to ensure that the changes are written * the call to ntfs_index_ctx_put() to ensure that the changes are written
* to disk. * to disk.
*/ */
int ntfs_index_lookup(const void *key, const int key_len, int ntfs_index_lookup(const void *key, const int key_len, ntfs_index_context *icx)
ntfs_index_context *icx)
{ {
VCN old_vcn, vcn; VCN old_vcn, vcn;
ntfs_inode *ni = icx->ni; ntfs_inode *ni = icx->ni;
INDEX_ROOT *ir; INDEX_ROOT *ir;
INDEX_ENTRY *ie; INDEX_ENTRY *ie;
INDEX_BLOCK *ib = NULL; INDEX_BLOCK *ib = NULL;
ntfs_attr_search_ctx *actx;
int ret, err = 0; int ret, err = 0;
ntfs_log_trace("Entering\n"); ntfs_log_trace("Entering\n");
@@ -670,7 +676,7 @@ int ntfs_index_lookup(const void *key, const int key_len,
return -1; return -1;
} }
ir = ntfs_ir_lookup(ni, icx->name, icx->name_len, &actx); ir = ntfs_ir_lookup(ni, icx->name, icx->name_len, &icx->actx);
if (!ir) { if (!ir) {
if (errno == ENOENT) if (errno == ENOENT)
errno = EIO; errno = EIO;
@@ -682,7 +688,7 @@ int ntfs_index_lookup(const void *key, const int key_len,
errno = EINVAL; errno = EINVAL;
ntfs_log_perror("Index block size (%d) is smaller than the " ntfs_log_perror("Index block size (%d) is smaller than the "
"sector size (%d)", icx->block_size, NTFS_BLOCK_SIZE); "sector size (%d)", icx->block_size, NTFS_BLOCK_SIZE);
return -1; goto err_out;
} }
if (ni->vol->cluster_size <= icx->block_size) if (ni->vol->cluster_size <= icx->block_size)
@@ -709,7 +715,6 @@ int ntfs_index_lookup(const void *key, const int key_len,
goto err_out; goto err_out;
} }
icx->actx = actx;
icx->ir = ir; icx->ir = ir;
if (ret != STATUS_KEEP_SEARCHING) { if (ret != STATUS_KEEP_SEARCHING) {
@@ -741,7 +746,7 @@ descend_into_child_node:
} }
old_vcn = vcn; old_vcn = vcn;
ntfs_log_debug("Descend into node with VCN %lld.\n", vcn); ntfs_log_debug("Descend into node with VCN %lld\n", (long long)vcn);
if (ntfs_ib_read(icx, vcn, ib)) if (ntfs_ib_read(icx, vcn, ib))
goto err_out; goto err_out;
@@ -755,7 +760,7 @@ descend_into_child_node:
/* STATUS_OK or STATUS_NOT_FOUND */ /* STATUS_OK or STATUS_NOT_FOUND */
icx->is_in_root = FALSE; icx->is_in_root = FALSE;
icx->ib = ib; icx->ib = ib;
icx->parent_vcn[icx->pindex] = icx->ib_vcn = vcn; icx->parent_vcn[icx->pindex] = vcn;
goto done; goto done;
} }
@@ -768,20 +773,15 @@ descend_into_child_node:
goto descend_into_child_node; goto descend_into_child_node;
err_out: err_out:
if (icx->ia_na)
ntfs_attr_close(icx->ia_na);
free(ib); free(ib);
if (!err) if (!err)
err = EIO; err = EIO;
if (actx)
ntfs_attr_put_search_ctx(actx);
errno = err; errno = err;
return -1; return -1;
done: done:
icx->entry = ie; icx->entry = ie;
icx->data = (u8 *)ie + offsetof(INDEX_ENTRY, key); icx->data = (u8 *)ie + offsetof(INDEX_ENTRY, key);
icx->data_len = le16_to_cpu(ie->key_length); icx->data_len = le16_to_cpu(ie->key_length);
icx->max_depth = icx->pindex;
ntfs_log_trace("Done.\n"); ntfs_log_trace("Done.\n");
if (err) { if (err) {
errno = err; errno = err;
@@ -797,7 +797,7 @@ static INDEX_BLOCK *ntfs_ib_alloc(VCN ib_vcn, u32 ib_size,
INDEX_BLOCK *ib; INDEX_BLOCK *ib;
int ih_size = sizeof(INDEX_HEADER); int ih_size = sizeof(INDEX_HEADER);
ntfs_log_trace("Entering ib_vcn = %lld ib_size = %u\n", ib_vcn, ib_size); ntfs_log_trace("ib_vcn: %lld ib_size: %u\n", (long long)ib_vcn, ib_size);
ib = ntfs_calloc(ib_size); ib = ntfs_calloc(ib_size);
if (!ib) if (!ib)
@@ -893,7 +893,7 @@ static int ntfs_ibm_modify(ntfs_index_context *icx, VCN vcn, int set)
ntfs_attr *na; ntfs_attr *na;
int ret = STATUS_ERROR; int ret = STATUS_ERROR;
ntfs_log_trace("%s vcn: %lld\n", set ? "set" : "clear", vcn); ntfs_log_trace("%s vcn: %lld\n", set ? "set" : "clear", (long long)vcn);
na = ntfs_attr_open(icx->ni, AT_BITMAP, icx->name, icx->name_len); na = ntfs_attr_open(icx->ni, AT_BITMAP, icx->name, icx->name_len);
if (!na) { if (!na) {
@@ -970,7 +970,7 @@ static VCN ntfs_ibm_get_free(ntfs_index_context *icx)
vcn = ntfs_ibm_pos_to_vcn(icx, size * 8); vcn = ntfs_ibm_pos_to_vcn(icx, size * 8);
out: out:
ntfs_log_trace("allocated vcn: %lld\n", vcn); ntfs_log_trace("allocated vcn: %lld\n", (long long)vcn);
if (ntfs_ibm_set(icx, vcn)) if (ntfs_ibm_set(icx, vcn))
vcn = (VCN)-1; vcn = (VCN)-1;
@@ -1052,13 +1052,13 @@ static int ntfs_ib_copy_tail(ntfs_index_context *icx, INDEX_BLOCK *src,
dst->index.index_length = cpu_to_le32(tail_size + dst->index.index_length = cpu_to_le32(tail_size +
le32_to_cpu(dst->index.entries_offset)); le32_to_cpu(dst->index.entries_offset));
ret = ntfs_ib_write(icx, new_vcn, dst); ret = ntfs_ib_write(icx, dst);
free(dst); free(dst);
return ret; return ret;
} }
static int ntfs_ib_cut_tail(ntfs_index_context *icx, INDEX_BLOCK *src, static int ntfs_ib_cut_tail(ntfs_index_context *icx, INDEX_BLOCK *ib,
INDEX_ENTRY *ie) INDEX_ENTRY *ie)
{ {
char *ies_start, *ies_end; char *ies_start, *ies_end;
@@ -1066,8 +1066,8 @@ static int ntfs_ib_cut_tail(ntfs_index_context *icx, INDEX_BLOCK *src,
ntfs_log_trace("Entering\n"); ntfs_log_trace("Entering\n");
ies_start = (char *)ntfs_ie_get_first(&src->index); ies_start = (char *)ntfs_ie_get_first(&ib->index);
ies_end = (char *)ntfs_ie_get_end(&src->index); ies_end = (char *)ntfs_ie_get_end(&ib->index);
ie_last = ntfs_ie_get_last((INDEX_ENTRY *)ies_start, ies_end); ie_last = ntfs_ie_get_last((INDEX_ENTRY *)ies_start, ies_end);
if (ie_last->ie_flags & INDEX_ENTRY_NODE) if (ie_last->ie_flags & INDEX_ENTRY_NODE)
@@ -1075,10 +1075,10 @@ static int ntfs_ib_cut_tail(ntfs_index_context *icx, INDEX_BLOCK *src,
memcpy(ie, ie_last, le16_to_cpu(ie_last->length)); memcpy(ie, ie_last, le16_to_cpu(ie_last->length));
src->index.index_length = cpu_to_le32(((char *)ie - ies_start) + ib->index.index_length = cpu_to_le32(((char *)ie - ies_start) +
le16_to_cpu(ie->length) + le32_to_cpu(src->index.entries_offset)); le16_to_cpu(ie->length) + le32_to_cpu(ib->index.entries_offset));
if (ntfs_ib_write(icx, icx->parent_vcn[icx->pindex + 1], src)) if (ntfs_ib_write(icx, ib))
return STATUS_ERROR; return STATUS_ERROR;
return STATUS_OK; return STATUS_OK;
@@ -1109,7 +1109,7 @@ static int ntfs_ia_add(ntfs_index_context *icx)
static int ntfs_ir_reparent(ntfs_index_context *icx) static int ntfs_ir_reparent(ntfs_index_context *icx)
{ {
ntfs_attr_search_ctx *ctx; ntfs_attr_search_ctx *ctx = NULL;
INDEX_ROOT *ir; INDEX_ROOT *ir;
INDEX_ENTRY *ie; INDEX_ENTRY *ie;
INDEX_BLOCK *ib = NULL; INDEX_BLOCK *ib = NULL;
@@ -1118,17 +1118,21 @@ static int ntfs_ir_reparent(ntfs_index_context *icx)
ntfs_log_trace("Entering\n"); ntfs_log_trace("Entering\n");
ir = ntfs_ir_lookup(icx->ni, icx->name, icx->name_len, &ctx); ir = ntfs_ir_lookup2(icx->ni, icx->name, icx->name_len);
if (!ir) if (!ir)
return -1; goto out;
if ((ir->index.ih_flags & NODE_MASK) == SMALL_INDEX) if ((ir->index.ih_flags & NODE_MASK) == SMALL_INDEX)
if (ntfs_ia_add(icx)) if (ntfs_ia_add(icx))
goto err_out; goto out;
new_ib_vcn = ntfs_ibm_get_free(icx); new_ib_vcn = ntfs_ibm_get_free(icx);
if (new_ib_vcn == -1) if (new_ib_vcn == -1)
goto err_out; goto out;
ir = ntfs_ir_lookup2(icx->ni, icx->name, icx->name_len);
if (!ir)
goto clear_bmp;
ib = ntfs_ir_to_ib(ir, new_ib_vcn); ib = ntfs_ir_to_ib(ir, new_ib_vcn);
if (ib == NULL) { if (ib == NULL) {
@@ -1136,7 +1140,11 @@ static int ntfs_ir_reparent(ntfs_index_context *icx)
goto clear_bmp; goto clear_bmp;
} }
if (ntfs_ib_write(icx, new_ib_vcn, ib)) if (ntfs_ib_write(icx, ib))
goto clear_bmp;
ir = ntfs_ir_lookup(icx->ni, icx->name, icx->name_len, &ctx);
if (!ir)
goto clear_bmp; goto clear_bmp;
ntfs_ir_nill(ir); ntfs_ir_nill(ir);
@@ -1153,8 +1161,8 @@ static int ntfs_ir_reparent(ntfs_index_context *icx)
if (ntfs_resident_attr_value_resize(ctx->mrec, ctx->attr, if (ntfs_resident_attr_value_resize(ctx->mrec, ctx->attr,
sizeof(INDEX_ROOT) - sizeof(INDEX_HEADER) + sizeof(INDEX_ROOT) - sizeof(INDEX_HEADER) +
le32_to_cpu(ir->index.allocated_size))) le32_to_cpu(ir->index.allocated_size)))
/* FIXME: revert bitmap, index root */ /* FIXME: revert index root */
goto err_out; goto clear_bmp;
/* /*
* FIXME: do it earlier if we have enough space in IR (should always), * FIXME: do it earlier if we have enough space in IR (should always),
* so in error case we wouldn't lose the IB. * so in error case we wouldn't lose the IB.
@@ -1165,6 +1173,7 @@ static int ntfs_ir_reparent(ntfs_index_context *icx)
err_out: err_out:
free(ib); free(ib);
ntfs_attr_put_search_ctx(ctx); ntfs_attr_put_search_ctx(ctx);
out:
return ret; return ret;
clear_bmp: clear_bmp:
ntfs_ibm_clear(icx, new_ib_vcn); ntfs_ibm_clear(icx, new_ib_vcn);
@@ -1195,18 +1204,14 @@ static int ntfs_ir_truncate(ntfs_index_context *icx, int data_size)
ret = ntfs_attr_truncate(na, data_size + offsetof(INDEX_ROOT, index)); ret = ntfs_attr_truncate(na, data_size + offsetof(INDEX_ROOT, index));
if (ret == STATUS_OK) { if (ret == STATUS_OK) {
ntfs_attr_search_ctx *ctx; icx->ir = ntfs_ir_lookup2(icx->ni, icx->name, icx->name_len);
icx->ir = ntfs_ir_lookup(icx->ni, icx->name, icx->name_len, &ctx);
if (!icx->ir) if (!icx->ir)
return STATUS_ERROR; return STATUS_ERROR;
icx->ir->index.allocated_size = cpu_to_le32(data_size); icx->ir->index.allocated_size = cpu_to_le32(data_size);
ntfs_attr_put_search_ctx(ctx); } else if (ret == STATUS_ERROR)
ntfs_log_perror("Failed to truncate INDEX_ROOT");
} else if (errno != ENOSPC)
ntfs_log_trace("Failed to truncate INDEX_ROOT");
ntfs_attr_close(na); ntfs_attr_close(na);
return ret; return ret;
@@ -1304,6 +1309,10 @@ static int ntfs_ir_insert_median(ntfs_index_context *icx, INDEX_ENTRY *median,
ntfs_log_trace("Entering\n"); ntfs_log_trace("Entering\n");
icx->ir = ntfs_ir_lookup2(icx->ni, icx->name, icx->name_len);
if (!icx->ir)
return STATUS_ERROR;
new_size = le32_to_cpu(icx->ir->index.index_length) + new_size = le32_to_cpu(icx->ir->index.index_length) +
le16_to_cpu(median->length); le16_to_cpu(median->length);
if (!(median->ie_flags & INDEX_ENTRY_NODE)) if (!(median->ie_flags & INDEX_ENTRY_NODE))
@@ -1313,6 +1322,10 @@ static int ntfs_ir_insert_median(ntfs_index_context *icx, INDEX_ENTRY *median,
if (ret != STATUS_OK) if (ret != STATUS_OK)
return ret; return ret;
icx->ir = ntfs_ir_lookup2(icx->ni, icx->name, icx->name_len);
if (!icx->ir)
return STATUS_ERROR;
return ntfs_ih_insert(&icx->ir->index, median, new_vcn, return ntfs_ih_insert(&icx->ir->index, median, new_vcn,
ntfs_icx_parent_pos(icx)); ntfs_icx_parent_pos(icx));
} }
@@ -1354,7 +1367,7 @@ static int ntfs_ib_insert(ntfs_index_context *icx, INDEX_ENTRY *ie, VCN new_vcn)
if (ntfs_ih_insert(&ib->index, ie, new_vcn, ntfs_icx_parent_pos(icx))) if (ntfs_ih_insert(&ib->index, ie, new_vcn, ntfs_icx_parent_pos(icx)))
goto err_out; goto err_out;
if (ntfs_ib_write(icx, old_vcn, ib)) if (ntfs_ib_write(icx, ib))
goto err_out; goto err_out;
err = STATUS_OK; err = STATUS_OK;
@@ -1364,7 +1377,7 @@ err_out:
} }
/** /**
* ntfs_ib_split - Split index allocation attribute * ntfs_ib_split - Split an index block
* *
* On success return STATUS_OK or STATUS_KEEP_SEARCHING. * On success return STATUS_OK or STATUS_KEEP_SEARCHING.
* On error return is STATUS_ERROR. * On error return is STATUS_ERROR.
@@ -1395,8 +1408,6 @@ static int ntfs_ib_split(ntfs_index_context *icx, INDEX_BLOCK *ib)
else else
ret = ntfs_ib_insert(icx, median, new_vcn); ret = ntfs_ib_insert(icx, median, new_vcn);
ntfs_inode_mark_dirty(icx->actx->ntfs_ino);
if (ret != STATUS_OK) { if (ret != STATUS_OK) {
ntfs_ibm_clear(icx, new_vcn); ntfs_ibm_clear(icx, new_vcn);
return ret; return ret;
@@ -1410,14 +1421,16 @@ static int ntfs_ib_split(ntfs_index_context *icx, INDEX_BLOCK *ib)
static int ntfs_ie_add(ntfs_index_context *icx, INDEX_ENTRY *ie) static int ntfs_ie_add(ntfs_index_context *icx, INDEX_ENTRY *ie)
{ {
char *fn;
INDEX_HEADER *ih; INDEX_HEADER *ih;
int allocated_size, new_size; int allocated_size, new_size;
int ret = STATUS_ERROR; int ret = STATUS_ERROR;
#ifdef DEBUG
char *fn;
fn = ntfs_ie_filename_get(ie); fn = ntfs_ie_filename_get(ie);
ntfs_log_trace("file: '%s'\n", fn); ntfs_log_trace("file: '%s'\n", fn);
ntfs_attr_name_free(&fn); ntfs_attr_name_free(&fn);
#endif
while (1) { while (1) {
@@ -1478,7 +1491,7 @@ int ntfs_index_add_filename(ntfs_inode *ni, FILE_NAME_ATTR *fn, MFT_REF mref)
{ {
INDEX_ENTRY *ie; INDEX_ENTRY *ie;
ntfs_index_context *icx; ntfs_index_context *icx;
int fn_size, ie_size, ret = -1; int fn_size, ie_size, err, ret = -1;
ntfs_log_trace("Entering\n"); ntfs_log_trace("Entering\n");
@@ -1506,8 +1519,9 @@ int ntfs_index_add_filename(ntfs_inode *ni, FILE_NAME_ATTR *fn, MFT_REF mref)
goto out; goto out;
ret = ntfs_ie_add(icx, ie); ret = ntfs_ie_add(icx, ie);
err = errno;
ntfs_index_ctx_put(icx); ntfs_index_ctx_put(icx);
errno = err;
out: out:
free(ie); free(ie);
return ret; return ret;
@@ -1530,7 +1544,7 @@ static int ntfs_ih_takeout(ntfs_index_context *icx, INDEX_HEADER *ih,
if (ntfs_icx_parent_vcn(icx) == VCN_INDEX_ROOT_PARENT) if (ntfs_icx_parent_vcn(icx) == VCN_INDEX_ROOT_PARENT)
ntfs_inode_mark_dirty(icx->actx->ntfs_ino); ntfs_inode_mark_dirty(icx->actx->ntfs_ino);
else else
if (ntfs_ib_write(icx, ntfs_icx_parent_vcn(icx), ib)) if (ntfs_ib_write(icx, ib))
goto out; goto out;
ntfs_index_ctx_reinit(icx); ntfs_index_ctx_reinit(icx);
@@ -1560,9 +1574,6 @@ static void ntfs_ir_leafify(ntfs_index_context *icx, INDEX_HEADER *ih)
/* Not fatal error */ /* Not fatal error */
ntfs_ir_truncate(icx, le32_to_cpu(ih->index_length)); ntfs_ir_truncate(icx, le32_to_cpu(ih->index_length));
ntfs_inode_mark_dirty(icx->actx->ntfs_ino);
ntfs_index_ctx_reinit(icx);
} }
/** /**
@@ -1640,7 +1651,7 @@ out:
static int ntfs_index_rm_node(ntfs_index_context *icx) static int ntfs_index_rm_node(ntfs_index_context *icx)
{ {
int entry_pos; int entry_pos, pindex;
VCN vcn; VCN vcn;
INDEX_BLOCK *ib = NULL; INDEX_BLOCK *ib = NULL;
INDEX_ENTRY *ie_succ, *ie, *entry = icx->entry; INDEX_ENTRY *ie_succ, *ie, *entry = icx->entry;
@@ -1662,6 +1673,7 @@ static int ntfs_index_rm_node(ntfs_index_context *icx)
ie_succ = ntfs_ie_get_next(icx->entry); ie_succ = ntfs_ie_get_next(icx->entry);
entry_pos = icx->parent_pos[icx->pindex]++; entry_pos = icx->parent_pos[icx->pindex]++;
pindex = icx->pindex;
descend: descend:
vcn = ntfs_ie_get_vcn(ie_succ); vcn = ntfs_ie_get_vcn(ie_succ);
if (ntfs_ib_read(icx, vcn, ib)) if (ntfs_ib_read(icx, vcn, ib))
@@ -1679,9 +1691,8 @@ descend:
goto descend; goto descend;
if (ntfs_ih_zero_entry(&ib->index)) { if (ntfs_ih_zero_entry(&ib->index)) {
errno = EOPNOTSUPP; errno = EIO;
ntfs_log_perror("Failed to find any entry in an index block. " ntfs_log_perror("Empty index block");
"Please run chkdsk.");
goto out; goto out;
} }
@@ -1703,18 +1714,18 @@ descend:
new_size = le32_to_cpu(ih->index_length) + delta; new_size = le32_to_cpu(ih->index_length) + delta;
if (delta > 0) { if (delta > 0) {
if (icx->is_in_root) { if (icx->is_in_root) {
if (ntfs_ir_truncate(icx, new_size)) { ret = ntfs_ir_make_space(icx, new_size);
errno = EOPNOTSUPP; if (ret != STATUS_OK)
ntfs_log_perror("Denied to truncate INDEX ROOT during entry removal");
goto out2; goto out2;
}
ih = &icx->ir->index; ih = &icx->ir->index;
entry = ntfs_ie_get_by_pos(ih, entry_pos); entry = ntfs_ie_get_by_pos(ih, entry_pos);
} else if (new_size > le32_to_cpu(ih->allocated_size)) { } else if (new_size > le32_to_cpu(ih->allocated_size)) {
errno = EOPNOTSUPP; icx->pindex = pindex;
ntfs_log_perror("Denied to split INDEX BLOCK during entry removal"); ret = ntfs_ib_split(icx, icx->ib);
if (ret == STATUS_OK)
ret = STATUS_KEEP_SEARCHING;
goto out2; goto out2;
} }
} }
@@ -1725,7 +1736,6 @@ descend:
if (icx->is_in_root) { if (icx->is_in_root) {
if (ntfs_ir_truncate(icx, new_size)) if (ntfs_ir_truncate(icx, new_size))
goto out2; goto out2;
ntfs_inode_mark_dirty(icx->actx->ntfs_ino);
} else } else
if (ntfs_icx_ib_write(icx)) if (ntfs_icx_ib_write(icx))
goto out2; goto out2;
@@ -1736,7 +1746,7 @@ descend:
if (ntfs_index_rm_leaf(icx)) if (ntfs_index_rm_leaf(icx))
goto out2; goto out2;
} else } else
if (ntfs_ib_write(icx, vcn, ib)) if (ntfs_ib_write(icx, ib))
goto out2; goto out2;
ret = STATUS_OK; ret = STATUS_OK;
@@ -1757,10 +1767,10 @@ out:
* *
* Return 0 on success or -1 on error with errno set to the error code. * Return 0 on success or -1 on error with errno set to the error code.
*/ */
int ntfs_index_rm(ntfs_index_context *icx) static int ntfs_index_rm(ntfs_index_context *icx)
{ {
INDEX_HEADER *ih; INDEX_HEADER *ih;
int err; int err, ret = STATUS_OK;
ntfs_log_trace("Entering\n"); ntfs_log_trace("Entering\n");
@@ -1776,8 +1786,7 @@ int ntfs_index_rm(ntfs_index_context *icx)
if (icx->entry->ie_flags & INDEX_ENTRY_NODE) { if (icx->entry->ie_flags & INDEX_ENTRY_NODE) {
if (ntfs_index_rm_node(icx)) ret = ntfs_index_rm_node(icx);
goto err_out;
} else if (icx->is_in_root || !ntfs_ih_one_entry(ih)) { } else if (icx->is_in_root || !ntfs_ih_one_entry(ih)) {
@@ -1794,16 +1803,51 @@ int ntfs_index_rm(ntfs_index_context *icx)
if (ntfs_index_rm_leaf(icx)) if (ntfs_index_rm_leaf(icx))
goto err_out; goto err_out;
} }
out:
ntfs_index_ctx_reinit(icx); return ret;
ntfs_log_trace("Done.\n");
return 0;
err_out: err_out:
err = errno; ret = STATUS_ERROR;
ntfs_index_ctx_reinit(icx); goto out;
errno = err; }
ntfs_log_trace("Failed.\n");
int ntfs_index_remove(ntfs_inode *ni, const void *key, const int keylen)
{
int ret = STATUS_ERROR;
ntfs_index_context *icx;
icx = ntfs_index_ctx_get(ni, NTFS_INDEX_I30, 4);
if (!icx)
return -1; return -1;
while (1) {
if (ntfs_index_lookup(key, keylen, icx))
goto err_out;
if (((FILE_NAME_ATTR *)icx->data)->file_attributes &
FILE_ATTR_REPARSE_POINT) {
errno = EOPNOTSUPP;
goto err_out;
}
ret = ntfs_index_rm(icx);
if (ret == STATUS_ERROR)
goto err_out;
else if (ret == STATUS_OK)
break;
ntfs_inode_mark_dirty(icx->actx->ntfs_ino);
ntfs_index_ctx_reinit(icx);
}
ntfs_inode_mark_dirty(icx->actx->ntfs_ino);
out:
ntfs_index_ctx_put(icx);
return ret;
err_out:
ret = STATUS_ERROR;
ntfs_log_perror("Delete failed");
goto out;
} }
/** /**
@@ -4,7 +4,7 @@
* Copyright (c) 2004 Anton Altaparmakov * Copyright (c) 2004 Anton Altaparmakov
* Copyright (c) 2004-2005 Richard Russon * Copyright (c) 2004-2005 Richard Russon
* Copyright (c) 2005 Yura Pakhuchiy * Copyright (c) 2005 Yura Pakhuchiy
* Copyright (c) 2006 Szabolcs Szakacsits * Copyright (c) 2006-2008 Szabolcs Szakacsits
* *
* This program/include file is free software; you can redistribute it and/or * This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published * modify it under the terms of the GNU General Public License as published
@@ -48,7 +48,6 @@
* @actx: attribute search context if in root or NULL otherwise * @actx: attribute search context if in root or NULL otherwise
* @ia: index block if @is_in_root is FALSE or NULL otherwise * @ia: index block if @is_in_root is FALSE or NULL otherwise
* @ia_na: opened INDEX_ALLOCATION attribute * @ia_na: opened INDEX_ALLOCATION attribute
* @ib_vcn: VCN from which @ia where read from
* @parent_pos: parent entries' positions in the index block * @parent_pos: parent entries' positions in the index block
* @parent_vcn: entry's parent node or VCN_INDEX_ROOT_PARENT * @parent_vcn: entry's parent node or VCN_INDEX_ROOT_PARENT
* @new_vcn: new VCN if we need to create a new index block * @new_vcn: new VCN if we need to create a new index block
@@ -64,11 +63,11 @@
* simply points into @entry. This is probably what the user is interested in. * simply points into @entry. This is probably what the user is interested in.
* *
* If @is_in_root is TRUE, @entry is in the index root attribute @ir described * If @is_in_root is TRUE, @entry is in the index root attribute @ir described
* by the attribute search context @actx and inode @ni. @ia, @ib_vcn and * by the attribute search context @actx and inode @ni. @ia and
* @ib_dirty are undefined in this case. * @ib_dirty are undefined in this case.
* *
* If @is_in_root is FALSE, @entry is in the index allocation attribute and @ia * If @is_in_root is FALSE, @entry is in the index allocation attribute and @ia
* and @ib_vcn point to the index allocation block and VCN where it's placed, * point to the index allocation block and VCN where it's placed,
* respectively. @ir and @actx are NULL in this case. @ia_na is opened * respectively. @ir and @actx are NULL in this case. @ia_na is opened
* INDEX_ALLOCATION attribute. @ib_dirty is TRUE if index block was changed and * INDEX_ALLOCATION attribute. @ib_dirty is TRUE if index block was changed and
* FALSE otherwise. * FALSE otherwise.
@@ -96,9 +95,7 @@ typedef struct {
INDEX_BLOCK *ib; INDEX_BLOCK *ib;
ntfs_attr *ia_na; ntfs_attr *ia_na;
int parent_pos[MAX_PARENT_VCN]; /* parent entries' positions */ int parent_pos[MAX_PARENT_VCN]; /* parent entries' positions */
VCN ib_vcn;
VCN parent_vcn[MAX_PARENT_VCN]; /* entry's parent nodes */ VCN parent_vcn[MAX_PARENT_VCN]; /* entry's parent nodes */
int max_depth; /* number of the parent nodes */
int pindex; /* maximum it's the number of the parent nodes */ int pindex; /* maximum it's the number of the parent nodes */
BOOL ib_dirty; BOOL ib_dirty;
u32 block_size; u32 block_size;
@@ -115,7 +112,7 @@ extern int ntfs_index_lookup(const void *key, const int key_len,
extern int ntfs_index_add_filename(ntfs_inode *ni, FILE_NAME_ATTR *fn, extern int ntfs_index_add_filename(ntfs_inode *ni, FILE_NAME_ATTR *fn,
MFT_REF mref); MFT_REF mref);
extern int ntfs_index_rm(ntfs_index_context *ictx); extern int ntfs_index_remove(ntfs_inode *ni, const void *key, const int keylen);
extern INDEX_ROOT *ntfs_index_root_get(ntfs_inode *ni, ATTR_RECORD *attr); extern INDEX_ROOT *ntfs_index_root_get(ntfs_inode *ni, ATTR_RECORD *attr);
@@ -2,8 +2,8 @@
* inode.c - Inode handling code. Originated from the Linux-NTFS project. * inode.c - Inode handling code. Originated from the Linux-NTFS project.
* *
* Copyright (c) 2002-2005 Anton Altaparmakov * Copyright (c) 2002-2005 Anton Altaparmakov
* Copyright (c) 2002-2006 Szabolcs Szakacsits * Copyright (c) 2002-2008 Szabolcs Szakacsits
* Copyright (c) 2004-2005 Yura Pakhuchiy * Copyright (c) 2004-2007 Yura Pakhuchiy
* Copyright (c) 2004-2005 Richard Russon * Copyright (c) 2004-2005 Richard Russon
* *
* This program/include file is free software; you can redistribute it and/or * This program/include file is free software; you can redistribute it and/or
@@ -51,6 +51,13 @@
#include "logging.h" #include "logging.h"
#include "misc.h" #include "misc.h"
ntfs_inode *ntfs_inode_base(ntfs_inode *ni)
{
if (ni->nr_extents == -1)
return ni->base_ni;
return ni;
}
/** /**
* ntfs_inode_mark_dirty - set the inode (and its base inode if it exists) dirty * ntfs_inode_mark_dirty - set the inode (and its base inode if it exists) dirty
* @ni: ntfs inode to set dirty * @ni: ntfs inode to set dirty
@@ -80,7 +87,7 @@ static ntfs_inode *__ntfs_inode_allocate(ntfs_volume *vol)
{ {
ntfs_inode *ni; ntfs_inode *ni;
ni = (ntfs_inode*)calloc(1, sizeof(ntfs_inode)); ni = (ntfs_inode*)ntfs_calloc(sizeof(ntfs_inode));
if (ni) if (ni)
ni->vol = vol; ni->vol = vol;
return ni; return ni;
@@ -145,23 +152,22 @@ static void __ntfs_inode_release(ntfs_inode *ni)
ntfs_inode *ntfs_inode_open(ntfs_volume *vol, const MFT_REF mref) ntfs_inode *ntfs_inode_open(ntfs_volume *vol, const MFT_REF mref)
{ {
s64 l; s64 l;
ntfs_inode *ni; ntfs_inode *ni = NULL;
ntfs_attr_search_ctx *ctx; ntfs_attr_search_ctx *ctx;
int err = 0;
STANDARD_INFORMATION *std_info; STANDARD_INFORMATION *std_info;
ntfs_log_trace("Entering for inode 0x%llx.\n", MREF(mref)); ntfs_log_enter("Entering for inode %lld\n", (long long)MREF(mref));
if (!vol) { if (!vol) {
errno = EINVAL; errno = EINVAL;
return NULL; goto out;
} }
ni = __ntfs_inode_allocate(vol); ni = __ntfs_inode_allocate(vol);
if (!ni) if (!ni)
return NULL; goto out;
if (ntfs_file_record_read(vol, mref, &ni->mrec, NULL)) if (ntfs_file_record_read(vol, mref, &ni->mrec, NULL))
goto err_out; goto err_out;
if (!(ni->mrec->flags & MFT_RECORD_IN_USE)) { if (!(ni->mrec->flags & MFT_RECORD_IN_USE)) {
err = ENOENT; errno = ENOENT;
goto err_out; goto err_out;
} }
ni->mft_no = MREF(mref); ni->mft_no = MREF(mref);
@@ -171,9 +177,7 @@ ntfs_inode *ntfs_inode_open(ntfs_volume *vol, const MFT_REF mref)
/* Receive some basic information about inode. */ /* Receive some basic information about inode. */
if (ntfs_attr_lookup(AT_STANDARD_INFORMATION, AT_UNNAMED, if (ntfs_attr_lookup(AT_STANDARD_INFORMATION, AT_UNNAMED,
0, CASE_SENSITIVE, 0, NULL, 0, ctx)) { 0, CASE_SENSITIVE, 0, NULL, 0, ctx)) {
err = errno; ntfs_log_perror("No STANDARD_INFORMATION in base record\n");
ntfs_log_trace("Failed to receive STANDARD_INFORMATION "
"attribute.\n");
goto put_err_out; goto put_err_out;
} }
std_info = (STANDARD_INFORMATION *)((u8 *)ctx->attr + std_info = (STANDARD_INFORMATION *)((u8 *)ctx->attr +
@@ -196,7 +200,8 @@ ntfs_inode *ntfs_inode_open(ntfs_volume *vol, const MFT_REF mref)
if (!l) if (!l)
goto put_err_out; goto put_err_out;
if (l > 0x40000) { if (l > 0x40000) {
err = EIO; errno = EIO;
ntfs_log_perror("Too large attrlist (%lld)\n", (long long)l);
goto put_err_out; goto put_err_out;
} }
ni->attr_list_size = l; ni->attr_list_size = l;
@@ -207,7 +212,9 @@ ntfs_inode *ntfs_inode_open(ntfs_volume *vol, const MFT_REF mref)
if (!l) if (!l)
goto put_err_out; goto put_err_out;
if (l != ni->attr_list_size) { if (l != ni->attr_list_size) {
err = EIO; errno = EIO;
ntfs_log_perror("Unexpected attrlist size (%lld <> %u)\n",
(long long)l, ni->attr_list_size);
goto put_err_out; goto put_err_out;
} }
get_size: get_size:
@@ -232,17 +239,16 @@ get_size:
} }
} }
ntfs_attr_put_search_ctx(ctx); ntfs_attr_put_search_ctx(ctx);
out:
ntfs_log_leave("\n");
return ni; return ni;
put_err_out: put_err_out:
if (!err)
err = errno;
ntfs_attr_put_search_ctx(ctx); ntfs_attr_put_search_ctx(ctx);
err_out: err_out:
if (!err)
err = errno;
__ntfs_inode_release(ni); __ntfs_inode_release(ni);
errno = err; ni = NULL;
return NULL; goto out;
} }
/** /**
@@ -258,6 +264,8 @@ err_out:
* If it is an extent inode, we disconnect it from its base inode before we * If it is an extent inode, we disconnect it from its base inode before we
* destroy it. * destroy it.
* *
* It is OK to pass NULL to this function, it is just noop in this case.
*
* Return 0 on success or -1 on error with errno set to the error code. On * Return 0 on success or -1 on error with errno set to the error code. On
* error, @ni has not been freed. The user should attempt to handle the error * error, @ni has not been freed. The user should attempt to handle the error
* and call ntfs_inode_close() again. The following error codes are defined: * and call ntfs_inode_close() again. The following error codes are defined:
@@ -269,17 +277,19 @@ err_out:
*/ */
int ntfs_inode_close(ntfs_inode *ni) int ntfs_inode_close(ntfs_inode *ni)
{ {
int ret = -1;
if (!ni) if (!ni)
return 0; return 0;
ntfs_log_trace("Entering for inode 0x%llx.\n", (long long)ni->mft_no); ntfs_log_enter("Entering for inode %lld\n", (long long)ni->mft_no);
/* If we have dirty metadata, write it out. */ /* If we have dirty metadata, write it out. */
if (NInoDirty(ni) || NInoAttrListDirty(ni)) { if (NInoDirty(ni) || NInoAttrListDirty(ni)) {
if (ntfs_inode_sync(ni)) { if (ntfs_inode_sync(ni)) {
if (errno != EIO) if (errno != EIO)
errno = EBUSY; errno = EBUSY;
return -1; goto err;
} }
} }
/* Is this a base inode with mapped extent inodes? */ /* Is this a base inode with mapped extent inodes? */
@@ -288,7 +298,7 @@ int ntfs_inode_close(ntfs_inode *ni)
if (ntfs_inode_close(ni->extent_nis[0])) { if (ntfs_inode_close(ni->extent_nis[0])) {
if (errno != EIO) if (errno != EIO)
errno = EBUSY; errno = EBUSY;
return -1; goto err;
} }
} }
} else if (ni->nr_extents == -1) { } else if (ni->nr_extents == -1) {
@@ -342,7 +352,10 @@ int ntfs_inode_close(ntfs_inode *ni)
} }
__ntfs_inode_release(ni); __ntfs_inode_release(ni);
return 0; ret = 0;
err:
ntfs_log_leave("\n");
return ret;
} }
/** /**
@@ -373,17 +386,20 @@ int ntfs_inode_close(ntfs_inode *ni)
ntfs_inode *ntfs_extent_inode_open(ntfs_inode *base_ni, const MFT_REF mref) ntfs_inode *ntfs_extent_inode_open(ntfs_inode *base_ni, const MFT_REF mref)
{ {
u64 mft_no = MREF_LE(mref); u64 mft_no = MREF_LE(mref);
ntfs_inode *ni; ntfs_inode *ni = NULL;
ntfs_inode **extent_nis; ntfs_inode **extent_nis;
int i; int i;
if (!base_ni) { if (!base_ni) {
errno = EINVAL; errno = EINVAL;
ntfs_log_perror("%s", __FUNCTION__);
return NULL; return NULL;
} }
ntfs_log_trace("Opening extent inode 0x%llx (base mft record 0x%llx).\n",
ntfs_log_enter("Opening extent inode %lld (base mft record %lld).\n",
(unsigned long long)mft_no, (unsigned long long)mft_no,
(unsigned long long)base_ni->mft_no); (unsigned long long)base_ni->mft_no);
/* Is the extent inode already open and attached to the base inode? */ /* Is the extent inode already open and attached to the base inode? */
if (base_ni->nr_extents > 0) { if (base_ni->nr_extents > 0) {
extent_nis = base_ni->extent_nis; extent_nis = base_ni->extent_nis;
@@ -397,21 +413,20 @@ ntfs_inode *ntfs_extent_inode_open(ntfs_inode *base_ni, const MFT_REF mref)
seq_no = MSEQNO_LE(mref); seq_no = MSEQNO_LE(mref);
if (seq_no && seq_no != le16_to_cpu( if (seq_no && seq_no != le16_to_cpu(
ni->mrec->sequence_number)) { ni->mrec->sequence_number)) {
ntfs_log_debug("Found stale extent mft reference! "
"Corrupt file system. Run chkdsk.\n");
errno = EIO; errno = EIO;
return NULL; ntfs_log_perror("Found stale extent mft "
"reference mft=%lld",
(long long)ni->mft_no);
goto out;
} }
/* We are done, return the extent inode. */ goto out;
return ni;
} }
} }
/* Wasn't there, we need to load the extent inode. */ /* Wasn't there, we need to load the extent inode. */
ni = __ntfs_inode_allocate(base_ni->vol); ni = __ntfs_inode_allocate(base_ni->vol);
if (!ni) if (!ni)
return NULL; goto out;
if (ntfs_file_record_read(base_ni->vol, le64_to_cpu(mref), &ni->mrec, if (ntfs_file_record_read(base_ni->vol, le64_to_cpu(mref), &ni->mrec, NULL))
NULL))
goto err_out; goto err_out;
ni->mft_no = mft_no; ni->mft_no = mft_no;
ni->nr_extents = -1; ni->nr_extents = -1;
@@ -431,11 +446,13 @@ ntfs_inode *ntfs_extent_inode_open(ntfs_inode *base_ni, const MFT_REF mref)
base_ni->extent_nis = extent_nis; base_ni->extent_nis = extent_nis;
} }
base_ni->extent_nis[base_ni->nr_extents++] = ni; base_ni->extent_nis[base_ni->nr_extents++] = ni;
out:
ntfs_log_leave("\n");
return ni; return ni;
err_out: err_out:
__ntfs_inode_release(ni); __ntfs_inode_release(ni);
ntfs_log_perror("Failed to open extent inode"); ni = NULL;
return NULL; goto out;
} }
/** /**
@@ -476,8 +493,7 @@ int ntfs_inode_attach_all_extents(ntfs_inode *ni)
while ((u8*)ale < ni->attr_list + ni->attr_list_size) { while ((u8*)ale < ni->attr_list + ni->attr_list_size) {
if (ni->mft_no != MREF_LE(ale->mft_reference) && if (ni->mft_no != MREF_LE(ale->mft_reference) &&
prev_attached != MREF_LE(ale->mft_reference)) { prev_attached != MREF_LE(ale->mft_reference)) {
if (!ntfs_extent_inode_open(ni, if (!ntfs_extent_inode_open(ni, ale->mft_reference)) {
MREF_LE(ale->mft_reference))) {
ntfs_log_trace("Couldn't attach extent inode.\n"); ntfs_log_trace("Couldn't attach extent inode.\n");
return -1; return -1;
} }
@@ -498,20 +514,17 @@ static int ntfs_inode_sync_standard_information(ntfs_inode *ni)
{ {
ntfs_attr_search_ctx *ctx; ntfs_attr_search_ctx *ctx;
STANDARD_INFORMATION *std_info; STANDARD_INFORMATION *std_info;
int err;
ntfs_log_trace("Entering for inode 0x%llx.\n", (long long) ni->mft_no); ntfs_log_trace("Entering for inode %lld\n", (long long)ni->mft_no);
ctx = ntfs_attr_get_search_ctx(ni, NULL); ctx = ntfs_attr_get_search_ctx(ni, NULL);
if (!ctx) if (!ctx)
return -1; return -1;
if (ntfs_attr_lookup(AT_STANDARD_INFORMATION, AT_UNNAMED, if (ntfs_attr_lookup(AT_STANDARD_INFORMATION, AT_UNNAMED,
0, CASE_SENSITIVE, 0, NULL, 0, ctx)) { 0, CASE_SENSITIVE, 0, NULL, 0, ctx)) {
err = errno; ntfs_log_perror("Failed to sync standard info (inode %lld)",
ntfs_log_trace("Failed to receive STANDARD_INFORMATION " (long long)ni->mft_no);
"attribute.\n");
ntfs_attr_put_search_ctx(ctx); ntfs_attr_put_search_ctx(ctx);
errno = err;
return -1; return -1;
} }
std_info = (STANDARD_INFORMATION *)((u8 *)ctx->attr + std_info = (STANDARD_INFORMATION *)((u8 *)ctx->attr +
@@ -569,7 +582,7 @@ static int ntfs_inode_sync_file_name(ntfs_inode *ni)
if (!err) if (!err)
err = errno; err = errno;
ntfs_log_perror("Failed to open inode %lld with index", ntfs_log_perror("Failed to open inode %lld with index",
le64_to_cpu(fn->parent_directory)); (long long)le64_to_cpu(fn->parent_directory));
continue; continue;
} }
ictx = ntfs_index_ctx_get(index_ni, NTFS_INDEX_I30, 4); ictx = ntfs_index_ctx_get(index_ni, NTFS_INDEX_I30, 4);
@@ -578,7 +591,8 @@ static int ntfs_inode_sync_file_name(ntfs_inode *ni)
err = errno; err = errno;
ntfs_log_perror("Failed to get index ctx, inode %lld", ntfs_log_perror("Failed to get index ctx, inode %lld",
(long long)index_ni->mft_no); (long long)index_ni->mft_no);
ntfs_inode_close(index_ni); if (ni != index_ni && ntfs_inode_close(index_ni) && !err)
err = errno;
continue; continue;
} }
if (ntfs_index_lookup(fn, sizeof(FILE_NAME_ATTR), ictx)) { if (ntfs_index_lookup(fn, sizeof(FILE_NAME_ATTR), ictx)) {
@@ -591,7 +605,8 @@ static int ntfs_inode_sync_file_name(ntfs_inode *ni)
ntfs_log_perror("Index lookup failed, inode %lld", ntfs_log_perror("Index lookup failed, inode %lld",
(long long)index_ni->mft_no); (long long)index_ni->mft_no);
ntfs_index_ctx_put(ictx); ntfs_index_ctx_put(ictx);
ntfs_inode_close(index_ni); if (ni != index_ni && ntfs_inode_close(index_ni) && !err)
err = errno;
continue; continue;
} }
/* Update flags and file size. */ /* Update flags and file size. */
@@ -651,6 +666,7 @@ err_out:
*/ */
int ntfs_inode_sync(ntfs_inode *ni) int ntfs_inode_sync(ntfs_inode *ni)
{ {
int ret = 0;
int err = 0; int err = 0;
if (!ni) { if (!ni) {
@@ -659,7 +675,7 @@ int ntfs_inode_sync(ntfs_inode *ni)
return -1; return -1;
} }
ntfs_log_trace("Entering for inode %lld\n", (long long)ni->mft_no); ntfs_log_enter("Entering for inode %lld\n", (long long)ni->mft_no);
/* Update STANDARD_INFORMATION. */ /* Update STANDARD_INFORMATION. */
if ((ni->mrec->flags & MFT_RECORD_IN_USE) && ni->nr_extents != -1 && if ((ni->mrec->flags & MFT_RECORD_IN_USE) && ni->nr_extents != -1 &&
@@ -669,8 +685,6 @@ int ntfs_inode_sync(ntfs_inode *ni)
if (err != EIO) if (err != EIO)
err = EBUSY; err = EBUSY;
} }
ntfs_log_perror("Failed to sync standard info (inode %lld)",
(long long)ni->mft_no);
} }
/* Update FILE_NAME's in the index. */ /* Update FILE_NAME's in the index. */
@@ -770,10 +784,13 @@ sync_inode:
} }
} }
if (!err) if (err) {
return 0;
errno = err; errno = err;
return -1; ret = -1;
}
ntfs_log_leave("\n");
return ret;
} }
/** /**
@@ -797,16 +814,16 @@ int ntfs_inode_add_attrlist(ntfs_inode *ni)
ntfs_attr *na; ntfs_attr *na;
if (!ni) { if (!ni) {
ntfs_log_trace("Invalid arguments.\n");
errno = EINVAL; errno = EINVAL;
ntfs_log_perror("%s", __FUNCTION__);
return -1; return -1;
} }
ntfs_log_trace("Entering for inode 0x%llx.\n", (long long) ni->mft_no); ntfs_log_trace("inode %llu\n", (unsigned long long) ni->mft_no);
if (NInoAttrList(ni) || ni->nr_extents) { if (NInoAttrList(ni) || ni->nr_extents) {
ntfs_log_trace("Inode already has got attribute list.\n");
errno = EEXIST; errno = EEXIST;
ntfs_log_perror("Inode already has attribute list");
return -1; return -1;
} }
@@ -814,7 +831,6 @@ int ntfs_inode_add_attrlist(ntfs_inode *ni)
ctx = ntfs_attr_get_search_ctx(ni, NULL); ctx = ntfs_attr_get_search_ctx(ni, NULL);
if (!ctx) { if (!ctx) {
err = errno; err = errno;
ntfs_log_trace("Couldn't get search context.\n");
goto err_out; goto err_out;
} }
/* Walk through all attributes. */ /* Walk through all attributes. */
@@ -824,7 +840,7 @@ int ntfs_inode_add_attrlist(ntfs_inode *ni)
if (ctx->attr->type == AT_ATTRIBUTE_LIST) { if (ctx->attr->type == AT_ATTRIBUTE_LIST) {
err = EIO; err = EIO;
ntfs_log_trace("Eeek! Attribute list already present.\n"); ntfs_log_perror("Attribute list already present");
goto put_err_out; goto put_err_out;
} }
@@ -864,7 +880,8 @@ int ntfs_inode_add_attrlist(ntfs_inode *ni)
/* Check for real error occurred. */ /* Check for real error occurred. */
if (errno != ENOENT) { if (errno != ENOENT) {
err = errno; err = errno;
ntfs_log_trace("Attribute lookup failed.\n"); ntfs_log_perror("%s: Attribute lookup failed, inode %lld",
__FUNCTION__, (long long)ni->mft_no);
goto put_err_out; goto put_err_out;
} }
@@ -882,8 +899,7 @@ int ntfs_inode_add_attrlist(ntfs_inode *ni)
offsetof(ATTR_RECORD, resident_end))) { offsetof(ATTR_RECORD, resident_end))) {
/* Failed to free space. */ /* Failed to free space. */
err = errno; err = errno;
ntfs_log_trace("Failed to free space for " ntfs_log_perror("Failed to free space for attrlist");
"$ATTRIBUTE_LIST.\n");
goto rollback; goto rollback;
} }
} }
@@ -892,7 +908,7 @@ int ntfs_inode_add_attrlist(ntfs_inode *ni)
if (ntfs_resident_attr_record_add(ni, if (ntfs_resident_attr_record_add(ni,
AT_ATTRIBUTE_LIST, NULL, 0, NULL, 0, 0) < 0) { AT_ATTRIBUTE_LIST, NULL, 0, NULL, 0, 0) < 0) {
err = errno; err = errno;
ntfs_log_trace("Couldn't add $ATTRIBUTE_LIST to MFT record.\n"); ntfs_log_perror("Couldn't add $ATTRIBUTE_LIST to MFT");
goto rollback; goto rollback;
} }
@@ -900,12 +916,12 @@ int ntfs_inode_add_attrlist(ntfs_inode *ni)
na = ntfs_attr_open(ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0); na = ntfs_attr_open(ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0);
if (!na) { if (!na) {
err = errno; err = errno;
ntfs_log_trace("Failed to open just added $ATTRIBUTE_LIST.\n"); ntfs_log_perror("Failed to open just added $ATTRIBUTE_LIST");
goto remove_attrlist_record; goto remove_attrlist_record;
} }
if (ntfs_attr_truncate(na, al_len)) { if (ntfs_attr_truncate(na, al_len)) {
err = errno; err = errno;
ntfs_log_trace("Failed to resize just added $ATTRIBUTE_LIST.\n"); ntfs_log_perror("Failed to resize just added $ATTRIBUTE_LIST");
ntfs_attr_close(na); ntfs_attr_close(na);
goto remove_attrlist_record;; goto remove_attrlist_record;;
} }
@@ -923,11 +939,9 @@ remove_attrlist_record:
if (!ntfs_attr_lookup(AT_ATTRIBUTE_LIST, NULL, 0, if (!ntfs_attr_lookup(AT_ATTRIBUTE_LIST, NULL, 0,
CASE_SENSITIVE, 0, NULL, 0, ctx)) { CASE_SENSITIVE, 0, NULL, 0, ctx)) {
if (ntfs_attr_record_rm(ctx)) if (ntfs_attr_record_rm(ctx))
ntfs_log_trace("Rollback failed. Failed to remove attribute " ntfs_log_perror("Rollback failed to remove attrlist");
"list record.\n");
} else } else
ntfs_log_trace("Rollback failed. Couldn't find attribute list " ntfs_log_perror("Rollback failed to find attrlist");
"record.\n");
/* Setup back in-memory runlist. */ /* Setup back in-memory runlist. */
ni->attr_list = al; ni->attr_list = al;
ni->attr_list_size = al_len; ni->attr_list_size = al_len;
@@ -947,11 +961,10 @@ rollback:
sle64_to_cpu(ale->lowest_vcn), sle64_to_cpu(ale->lowest_vcn),
NULL, 0, ctx)) { NULL, 0, ctx)) {
if (ntfs_attr_record_move_to(ctx, ni)) if (ntfs_attr_record_move_to(ctx, ni))
ntfs_log_trace("Rollback failed. Couldn't " ntfs_log_perror("Rollback failed to "
"back attribute to base MFT record.\n"); "move attribute");
} else } else
ntfs_log_trace("Rollback failed. ntfs_attr_lookup " ntfs_log_perror("Rollback failed to find attr");
"failed.\n");
ntfs_attr_reinit_search_ctx(ctx); ntfs_attr_reinit_search_ctx(ctx);
} }
ale = (ATTR_LIST_ENTRY*)((u8*)ale + le16_to_cpu(ale->length)); ale = (ATTR_LIST_ENTRY*)((u8*)ale + le16_to_cpu(ale->length));
@@ -970,8 +983,8 @@ err_out:
} }
/** /**
* ntfs_inode_free_space - free space in the MFT record of inode * ntfs_inode_free_space - free space in the MFT record of an inode
* @ni: ntfs inode in which MFT record free space * @ni: ntfs inode in which MFT record needs more free space
* @size: amount of space needed to free * @size: amount of space needed to free
* *
* Return 0 on success or -1 on error with errno set to the error code. * Return 0 on success or -1 on error with errno set to the error code.
@@ -979,16 +992,16 @@ err_out:
int ntfs_inode_free_space(ntfs_inode *ni, int size) int ntfs_inode_free_space(ntfs_inode *ni, int size)
{ {
ntfs_attr_search_ctx *ctx; ntfs_attr_search_ctx *ctx;
int freed, err; int freed;
if (!ni || size < 0) { if (!ni || size < 0) {
ntfs_log_trace("Invalid arguments.\n");
errno = EINVAL; errno = EINVAL;
ntfs_log_perror("%s: ni=%p size=%d", __FUNCTION__, ni, size);
return -1; return -1;
} }
ntfs_log_trace("Entering for inode 0x%llx, size %d.\n", ntfs_log_trace("Entering for inode %lld, size %d\n",
(long long) ni->mft_no, size); (unsigned long long)ni->mft_no, size);
freed = (le32_to_cpu(ni->mrec->bytes_allocated) - freed = (le32_to_cpu(ni->mrec->bytes_allocated) -
le32_to_cpu(ni->mrec->bytes_in_use)); le32_to_cpu(ni->mrec->bytes_in_use));
@@ -997,138 +1010,96 @@ int ntfs_inode_free_space(ntfs_inode *ni, int size)
return 0; return 0;
ctx = ntfs_attr_get_search_ctx(ni, NULL); ctx = ntfs_attr_get_search_ctx(ni, NULL);
if (!ctx) { if (!ctx)
err = errno;
ntfs_log_trace("Failed to get attribute search context.\n");
errno = err;
return -1; return -1;
}
/* /*
* Chkdsk complain if $STANDARD_INFORMATION is not in the base MFT * $STANDARD_INFORMATION and $ATTRIBUTE_LIST must stay in the base MFT
* record. FIXME: I'm not sure in this, need to recheck. For now simply * record, so position search context on the first attribute after them.
* do not move $STANDARD_INFORMATION at all.
*
* Also we can't move $ATTRIBUTE_LIST from base MFT_RECORD, so position
* search context on first attribute after $STANDARD_INFORMATION and
* $ATTRIBUTE_LIST.
*
* Why we reposition instead of simply skip this attributes during
* enumeration? Because in case we have got only in-memory attribute
* list ntfs_attr_lookup will fail when it will try to find
* $ATTRIBUTE_LIST.
*/ */
if (ntfs_attr_lookup(AT_FILE_NAME, NULL, 0, CASE_SENSITIVE, 0, NULL, if (ntfs_attr_position(AT_FILE_NAME, ctx))
0, ctx)) {
if (errno != ENOENT) {
err = errno;
ntfs_log_trace("Attribute lookup failed.\n");
goto put_err_out; goto put_err_out;
}
if (ctx->attr->type == AT_END) {
err = ENOSPC;
goto put_err_out;
}
}
while (1) { while (1) {
int record_size; int record_size;
/* /*
* Check whether attribute is from different MFT record. If so, * Check whether attribute is from different MFT record. If so,
* find next, because we don't need such. * find next, because we don't need such.
*/ */
while (ctx->ntfs_ino->mft_no != ni->mft_no) { while (ctx->ntfs_ino->mft_no != ni->mft_no) {
if (ntfs_attr_lookup(AT_UNUSED, NULL, 0, CASE_SENSITIVE, retry:
0, NULL, 0, ctx)) { if (ntfs_attr_position(AT_UNUSED, ctx))
err = errno;
if (errno != ENOENT) {
ntfs_log_trace("Attribute lookup failed.\n");
} else
err = ENOSPC;
goto put_err_out; goto put_err_out;
} }
}
if (ntfs_inode_base(ctx->ntfs_ino)->mft_no == FILE_MFT &&
ctx->attr->type == AT_DATA)
goto retry;
if (ctx->attr->type == AT_INDEX_ROOT)
goto retry;
record_size = le32_to_cpu(ctx->attr->length); record_size = le32_to_cpu(ctx->attr->length);
/* Move away attribute. */
if (ntfs_attr_record_move_away(ctx, 0)) { if (ntfs_attr_record_move_away(ctx, 0)) {
err = errno; ntfs_log_perror("Failed to move out attribute #2");
ntfs_log_trace("Failed to move out attribute.\n");
break; break;
} }
freed += record_size; freed += record_size;
/* Check whether we done. */ /* Check whether we are done. */
if (size <= freed) { if (size <= freed) {
ntfs_attr_put_search_ctx(ctx); ntfs_attr_put_search_ctx(ctx);
return 0; return 0;
} }
/* /*
* Reposition to first attribute after $STANDARD_INFORMATION and * Reposition to first attribute after $STANDARD_INFORMATION
* $ATTRIBUTE_LIST (see comments upwards). * and $ATTRIBUTE_LIST instead of simply skipping this attribute
* because in the case when we have got only in-memory attribute
* list then ntfs_attr_lookup will fail when it tries to find
* $ATTRIBUTE_LIST.
*/ */
ntfs_attr_reinit_search_ctx(ctx); ntfs_attr_reinit_search_ctx(ctx);
if (ntfs_attr_lookup(AT_FILE_NAME, NULL, 0, CASE_SENSITIVE, 0, if (ntfs_attr_position(AT_FILE_NAME, ctx))
NULL, 0, ctx)) {
if (errno != ENOENT) {
err = errno;
ntfs_log_trace("Attribute lookup failed.\n");
break; break;
} }
if (ctx->attr->type == AT_END) {
err = ENOSPC;
break;
}
}
}
put_err_out: put_err_out:
ntfs_attr_put_search_ctx(ctx); ntfs_attr_put_search_ctx(ctx);
if (err == ENOSPC) if (errno == ENOSPC)
ntfs_log_trace("No attributes left that can be moved out.\n"); ntfs_log_trace("No attributes left that could be moved out.\n");
errno = err;
return -1; return -1;
} }
/** /**
* ntfs_inode_update_atime - update access time for ntfs inode * ntfs_inode_update_times - update selected time fields for ntfs inode
* @ni: ntfs inode for which update access time * @ni: ntfs inode for which update time fields
* @mask: select which time fields should be updated
* *
* This function usually get called when user read not metadata from inode. * This function updates time fields to current time. Fields to update are
* Do not update time for system files. * selected using @mask (see enum @ntfs_time_update_flags for posssible values).
*/ */
void ntfs_inode_update_atime(ntfs_inode *ni) void ntfs_inode_update_times(ntfs_inode *ni, ntfs_time_update_flags mask)
{ {
if (!NVolReadOnly(ni->vol) && !NVolNoATime(ni->vol) && (ni->mft_no >=
FILE_first_user || ni->mft_no == FILE_root)) {
ni->last_access_time = time(NULL);
NInoFileNameSetDirty(ni);
NInoSetDirty(ni);
}
}
/**
* ntfs_inode_update_time - update all times for ntfs inode
* @ni: ntfs inode for which update times
*
* This function updates last access, mft and data change times. Usually
* get called when user write not metadata to inode. Do not update time for
* system files.
*/
void ntfs_inode_update_time(ntfs_inode *ni)
{
if (!NVolReadOnly(ni->vol) &&
(ni->mft_no >= FILE_first_user || ni->mft_no == FILE_root)) {
time_t now; time_t now;
if (!ni) {
ntfs_log_error("%s(): Invalid arguments.\n", __FUNCTION__);
return;
}
if ((ni->mft_no < FILE_first_user && ni->mft_no != FILE_root) ||
NVolReadOnly(ni->vol) || !mask)
return;
now = time(NULL); now = time(NULL);
if (mask & NTFS_UPDATE_ATIME)
ni->last_access_time = now;
if (mask & NTFS_UPDATE_MTIME)
ni->last_data_change_time = now; ni->last_data_change_time = now;
if (mask & NTFS_UPDATE_CTIME)
ni->last_mft_change_time = now; ni->last_mft_change_time = now;
NInoFileNameSetDirty(ni); NInoFileNameSetDirty(ni);
NInoSetDirty(ni); NInoSetDirty(ni);
}
} }
/** /**
@@ -1,10 +1,10 @@
/* /*
* inode.h - Defines for NTFS inode handling. Originated from the Linux-NTFS project. * inode.h - Defines for NTFS inode handling. Originated from the Linux-NTFS project.
* *
* Copyright (c) 2001,2002 Anton Altaparmakov * Copyright (c) 2001-2004 Anton Altaparmakov
* Copyright (c) 2004-2005 Yura Pakhuchiy * Copyright (c) 2004-2007 Yura Pakhuchiy
* Copyright (c) 2004-2005 Richard Russon * Copyright (c) 2004-2005 Richard Russon
* Copyright (c) 2006 Szabolcs Szakacsits * Copyright (c) 2006-2008 Szabolcs Szakacsits
* *
* This program/include file is free software; you can redistribute it and/or * This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published * modify it under the terms of the GNU General Public License as published
@@ -85,12 +85,9 @@ typedef enum {
#define NInoAttrListTestAndSetDirty(ni) test_and_set_nino_al_flag(ni, Dirty) #define NInoAttrListTestAndSetDirty(ni) test_and_set_nino_al_flag(ni, Dirty)
#define NInoAttrListTestAndClearDirty(ni) test_and_clear_nino_al_flag(ni, Dirty) #define NInoAttrListTestAndClearDirty(ni) test_and_clear_nino_al_flag(ni, Dirty)
#define NInoFileNameDirty(ni) \ #define NInoFileNameDirty(ni) test_nino_flag(ni, FileNameDirty)
test_nino_flag(ni, FileNameDirty) #define NInoFileNameSetDirty(ni) set_nino_flag(ni, FileNameDirty)
#define NInoFileNameSetDirty(ni) \ #define NInoFileNameClearDirty(ni) clear_nino_flag(ni, FileNameDirty)
set_nino_flag(ni, FileNameDirty)
#define NInoFileNameClearDirty(ni) \
clear_nino_flag(ni, FileNameDirty)
#define NInoFileNameTestAndSetDirty(ni) \ #define NInoFileNameTestAndSetDirty(ni) \
test_and_set_nino_flag(ni, FileNameDirty) test_and_set_nino_flag(ni, FileNameDirty)
#define NInoFileNameTestAndClearDirty(ni) \ #define NInoFileNameTestAndClearDirty(ni) \
@@ -130,12 +127,14 @@ struct _ntfs_inode {
inode of the base mft record. */ inode of the base mft record. */
}; };
/* Temp: for directory handling */
void *private_data; /* ntfs_dt containing this inode */
int ref_count;
/* Below fields are valid only for base inode. */ /* Below fields are valid only for base inode. */
s64 data_size; /* Data size stored in the filename index. */
/*
* These two fields are used to sync filename index and guaranteed to be
* correct, however value in index itself maybe wrong (windows itself
* do not update them properly).
*/
s64 data_size; /* Data size of unnamed DATA attribute. */
s64 allocated_size; /* Allocated size stored in the filename s64 allocated_size; /* Allocated size stored in the filename
index. (NOTE: Equal to allocated size of index. (NOTE: Equal to allocated size of
the unnamed data attribute for normal or the unnamed data attribute for normal or
@@ -143,12 +142,28 @@ struct _ntfs_inode {
of the unnamed data attribute for sparse or of the unnamed data attribute for sparse or
compressed files.) */ compressed files.) */
/*
* These four fields are copy of relevant fields from
* STANDARD_INFORMATION attribute and used to sync it and FILE_NAME
* attribute in the index.
*/
time_t creation_time; time_t creation_time;
time_t last_data_change_time; time_t last_data_change_time;
time_t last_mft_change_time; time_t last_mft_change_time;
time_t last_access_time; time_t last_access_time;
}; };
typedef enum {
NTFS_UPDATE_ATIME = 1 << 0,
NTFS_UPDATE_MTIME = 1 << 1,
NTFS_UPDATE_CTIME = 1 << 2,
} ntfs_time_update_flags;
#define NTFS_UPDATE_MCTIME (NTFS_UPDATE_MTIME | NTFS_UPDATE_CTIME)
#define NTFS_UPDATE_AMCTIME (NTFS_UPDATE_ATIME | NTFS_UPDATE_MCTIME)
extern ntfs_inode *ntfs_inode_base(ntfs_inode *ni);
extern ntfs_inode *ntfs_inode_allocate(ntfs_volume *vol); extern ntfs_inode *ntfs_inode_allocate(ntfs_volume *vol);
extern ntfs_inode *ntfs_inode_open(ntfs_volume *vol, const MFT_REF mref); extern ntfs_inode *ntfs_inode_open(ntfs_volume *vol, const MFT_REF mref);
@@ -162,8 +177,7 @@ extern int ntfs_inode_attach_all_extents(ntfs_inode *ni);
extern void ntfs_inode_mark_dirty(ntfs_inode *ni); extern void ntfs_inode_mark_dirty(ntfs_inode *ni);
extern void ntfs_inode_update_atime(ntfs_inode *ni); extern void ntfs_inode_update_times(ntfs_inode *ni, ntfs_time_update_flags mask);
extern void ntfs_inode_update_time(ntfs_inode *ni);
extern int ntfs_inode_sync(ntfs_inode *ni); extern int ntfs_inode_sync(ntfs_inode *ni);
@@ -2340,17 +2340,18 @@ typedef struct {
control entry in the data part of control entry in the data part of
the index. */ the index. */
} __attribute__((__packed__)) key; } __attribute__((__packed__)) key;
/* The (optional) index data is inserted here when creating. */ /* The (optional) index data is inserted here when creating.
// VCN vcn; If INDEX_ENTRY_NODE bit in ie_flags is set, the last VCN vcn; If INDEX_ENTRY_NODE bit in ie_flags is set, the last
// eight bytes of this index entry contain the virtual eight bytes of this index entry contain the virtual
// cluster number of the index block that holds the cluster number of the index block that holds the
// entries immediately preceding the current entry. entries immediately preceding the current entry.
//
// If the key_length is zero, then the vcn immediately If the key_length is zero, then the vcn immediately
// follows the INDEX_ENTRY_HEADER. follows the INDEX_ENTRY_HEADER.
//
// The address of the vcn of "ie" INDEX_ENTRY is given by The address of the vcn of "ie" INDEX_ENTRY is given by
// (char*)ie + le16_to_cpu(ie->length) - sizeof(VCN) (char*)ie + le16_to_cpu(ie->length) - sizeof(VCN)
*/
} __attribute__((__packed__)) INDEX_ENTRY; } __attribute__((__packed__)) INDEX_ENTRY;
/** /**
@@ -3,7 +3,7 @@
* *
* Copyright (c) 2002-2004 Anton Altaparmakov * Copyright (c) 2002-2004 Anton Altaparmakov
* Copyright (c) 2004 Yura Pakhuchiy * Copyright (c) 2004 Yura Pakhuchiy
* Copyright (c) 2004-2007 Szabolcs Szakacsits * Copyright (c) 2004-2008 Szabolcs Szakacsits
* *
* This program/include file is free software; you can redistribute it and/or * This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published * modify it under the terms of the GNU General Public License as published
@@ -51,12 +51,12 @@
* the update of the mapping pairs which converges to the cubic Faulhaber's * the update of the mapping pairs which converges to the cubic Faulhaber's
* formula as the function of the number of extents (fragments, runs). * formula as the function of the number of extents (fragments, runs).
*/ */
#define NTFS_LCNALLOC_BSIZE 1024 #define NTFS_LCNALLOC_BSIZE 4096
#define NTFS_LCNALLOC_SKIP NTFS_LCNALLOC_BSIZE #define NTFS_LCNALLOC_SKIP NTFS_LCNALLOC_BSIZE
static void ntfs_cluster_set_zone_pos(LCN start, LCN end, LCN *pos, LCN tc) static void ntfs_cluster_set_zone_pos(LCN start, LCN end, LCN *pos, LCN tc)
{ {
ntfs_log_trace("pos: %lld tc: %lld\n", (long long)*pos, tc); ntfs_log_trace("pos: %lld tc: %lld\n", (long long)*pos, (long long)tc);
if (tc >= end) if (tc >= end)
*pos = start; *pos = start;
@@ -85,10 +85,15 @@ static s64 max_empty_bit_range(unsigned char *buf, int size)
int max_range = 0; int max_range = 0;
s64 start_pos = -1; s64 start_pos = -1;
ntfs_log_trace("Entering"); ntfs_log_trace("Entering\n");
for (i = 0; i < size; i++, buf++) { for (i = 0; i < size; i++, buf++) {
if (*buf == 0) {
run += 8;
continue;
}
for (j = 0; j < 8; j++) { for (j = 0; j < 8; j++) {
int bit = *buf & (1 << j); int bit = *buf & (1 << j);
@@ -115,7 +120,7 @@ static int bitmap_writeback(ntfs_volume *vol, s64 pos, s64 size, void *b,
{ {
s64 written; s64 written;
ntfs_log_trace("Entering"); ntfs_log_trace("Entering\n");
if (!*writeback) if (!*writeback)
return 0; return 0;
@@ -126,7 +131,8 @@ static int bitmap_writeback(ntfs_volume *vol, s64 pos, s64 size, void *b,
if (written != size) { if (written != size) {
if (!written) if (!written)
errno = EIO; errno = EIO;
ntfs_log_perror("Bitmap write error (%lld, %lld)", pos, size); ntfs_log_perror("Bitmap write error (%lld, %lld)",
(long long)pos, (long long)size);
return -1; return -1;
} }
@@ -189,16 +195,17 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
u8 has_guess, used_zone_pos; u8 has_guess, used_zone_pos;
int err = 0, rlpos, rlsize, buf_size; int err = 0, rlpos, rlsize, buf_size;
ntfs_log_trace("Entering with count = 0x%llx, start_lcn = 0x%llx, " ntfs_log_enter("Entering with count = 0x%llx, start_lcn = 0x%llx, "
"zone = %s_ZONE.\n", (long long)count, (long long) "zone = %s_ZONE.\n", (long long)count, (long long)
start_lcn, zone == MFT_ZONE ? "MFT" : "DATA"); start_lcn, zone == MFT_ZONE ? "MFT" : "DATA");
if (!vol || count < 0 || start_lcn < -1 || !vol->lcnbmp_na || if (!vol || count < 0 || start_lcn < -1 || !vol->lcnbmp_na ||
(s8)zone < FIRST_ZONE || zone > LAST_ZONE) { (s8)zone < FIRST_ZONE || zone > LAST_ZONE) {
errno = EINVAL; errno = EINVAL;
ntfs_log_perror("%s: vcn: %lld, count: %lld, lcn: %lld", ntfs_log_perror("%s: vcn: %lld, count: %lld, lcn: %lld",
__FUNCTION__, (long long)start_vcn, __FUNCTION__, (long long)start_vcn,
(long long)count, (long long)start_lcn); (long long)count, (long long)start_lcn);
return NULL; goto out;
} }
/* Return empty runlist if @count == 0 */ /* Return empty runlist if @count == 0 */
@@ -209,12 +216,12 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
rl[0].lcn = LCN_RL_NOT_MAPPED; rl[0].lcn = LCN_RL_NOT_MAPPED;
rl[0].length = 0; rl[0].length = 0;
} }
return rl; goto out;
} }
buf = ntfs_malloc(NTFS_LCNALLOC_BSIZE); buf = ntfs_malloc(NTFS_LCNALLOC_BSIZE);
if (!buf) if (!buf)
return NULL; goto out;
/* /*
* If no @start_lcn was requested, use the current zone * If no @start_lcn was requested, use the current zone
* position otherwise use the requested @start_lcn. * position otherwise use the requested @start_lcn.
@@ -272,7 +279,7 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
bmp_pos &= ~7; bmp_pos &= ~7;
writeback = 0; writeback = 0;
while (1) { while (lcn < buf_size) {
byte = buf + (lcn >> 3); byte = buf + (lcn >> 3);
bit = 1 << (lcn & 7); bit = 1 << (lcn & 7);
if (has_guess) { if (has_guess) {
@@ -305,25 +312,44 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
/* Allocate the bitmap bit. */ /* Allocate the bitmap bit. */
*byte |= bit; *byte |= bit;
writeback = 1; writeback = 1;
if (vol->free_clusters <= 0)
ntfs_log_error("Non-positive free clusters "
"(%lld)!\n",
(long long)vol->free_clusters);
else
vol->free_clusters--;
/* /*
* Coalesce with previous run if adjacent LCNs. * Coalesce with previous run if adjacent LCNs.
* Otherwise, append a new run. * Otherwise, append a new run.
*/ */
if (prev_lcn == lcn + bmp_pos - prev_run_len && rlpos) if (prev_lcn == lcn + bmp_pos - prev_run_len && rlpos) {
ntfs_log_debug("Cluster coalesce: prev_lcn: "
"%lld lcn: %lld bmp_pos: %lld "
"prev_run_len: %lld\n",
(long long)prev_lcn,
(long long)lcn, (long long)bmp_pos,
(long long)prev_run_len);
rl[rlpos - 1].length = ++prev_run_len; rl[rlpos - 1].length = ++prev_run_len;
else { } else {
if (rlpos) if (rlpos)
rl[rlpos].vcn = rl[rlpos - 1].vcn + rl[rlpos].vcn = rl[rlpos - 1].vcn +
prev_run_len; prev_run_len;
else else {
rl[rlpos].vcn = start_vcn; rl[rlpos].vcn = start_vcn;
ntfs_log_debug("Start_vcn: %lld\n",
(long long)start_vcn);
}
rl[rlpos].lcn = prev_lcn = lcn + bmp_pos; rl[rlpos].lcn = prev_lcn = lcn + bmp_pos;
rl[rlpos].length = prev_run_len = 1; rl[rlpos].length = prev_run_len = 1;
rlpos++; rlpos++;
} }
ntfs_log_debug("RUN: %-16lld %-16lld %-16lld\n",
(long long)rl[rlpos - 1].vcn,
(long long)rl[rlpos - 1].lcn,
(long long)rl[rlpos - 1].length);
/* Done? */ /* Done? */
if (!--clusters) { if (!--clusters) {
if (used_zone_pos) if (used_zone_pos)
@@ -425,7 +451,7 @@ switch_to_data1_zone: search_zone = 2;
search_zone = 1; search_zone = 1;
zone_start = vol->mft_zone_pos; zone_start = vol->mft_zone_pos;
zone_end = vol->mft_zone_end; zone_end = vol->mft_zone_end;
if (!zone_start == vol->mft_zone_start) if (zone_start == vol->mft_zone_start)
pass = 2; pass = 2;
break; break;
} }
@@ -455,13 +481,15 @@ done_ret:
goto err_ret; goto err_ret;
} }
done_err_ret: done_err_ret:
ntfs_log_debug("At done_err_ret (follows done_ret).\n");
free(buf); free(buf);
if (!err) if (err) {
return rl;
ntfs_log_trace("Failed to allocate clusters (%d)", errno);
errno = err; errno = err;
return NULL; ntfs_log_perror("Failed to allocate clusters");
rl = NULL;
}
out:
ntfs_log_leave("\n");
return rl;
wb_err_ret: wb_err_ret:
ntfs_log_trace("At wb_err_ret.\n"); ntfs_log_trace("At wb_err_ret.\n");
@@ -474,6 +502,7 @@ err_ret:
rl[rlpos].vcn = rl[rlpos - 1].vcn + rl[rlpos - 1].length; rl[rlpos].vcn = rl[rlpos - 1].vcn + rl[rlpos - 1].length;
rl[rlpos].lcn = LCN_RL_NOT_MAPPED; rl[rlpos].lcn = LCN_RL_NOT_MAPPED;
rl[rlpos].length = 0; rl[rlpos].length = 0;
ntfs_debug_runlist_dump(rl);
ntfs_cluster_free_from_rl(vol, rl); ntfs_cluster_free_from_rl(vol, rl);
free(rl); free(rl);
rl = NULL; rl = NULL;
@@ -490,6 +519,9 @@ err_ret:
*/ */
int ntfs_cluster_free_from_rl(ntfs_volume *vol, runlist *rl) int ntfs_cluster_free_from_rl(ntfs_volume *vol, runlist *rl)
{ {
s64 nr_freed = 0;
int ret = -1;
ntfs_log_trace("Entering.\n"); ntfs_log_trace("Entering.\n");
for (; rl->length; rl++) { for (; rl->length; rl++) {
@@ -497,15 +529,27 @@ int ntfs_cluster_free_from_rl(ntfs_volume *vol, runlist *rl)
ntfs_log_trace("Dealloc lcn 0x%llx, len 0x%llx.\n", ntfs_log_trace("Dealloc lcn 0x%llx, len 0x%llx.\n",
(long long)rl->lcn, (long long)rl->length); (long long)rl->lcn, (long long)rl->length);
if (rl->lcn >= 0 && ntfs_bitmap_clear_run(vol->lcnbmp_na, if (rl->lcn >= 0) {
rl->lcn, rl->length)) { if (ntfs_bitmap_clear_run(vol->lcnbmp_na, rl->lcn,
int eo = errno; rl->length)) {
ntfs_log_trace("Eeek! Deallocation of clusters failed.\n"); ntfs_log_perror("Cluster deallocation failed "
errno = eo; "(%lld, %lld)",
return -1; (long long)rl->lcn,
(long long)rl->length);
goto out;
}
nr_freed += rl->length ;
} }
} }
return 0;
ret = 0;
out:
vol->free_clusters += nr_freed;
if (vol->free_clusters > vol->nr_clusters)
ntfs_log_error("Too many free clusters (%lld > %lld)!",
(long long)vol->free_clusters,
(long long)vol->nr_clusters);
return ret;
} }
/** /**
@@ -527,7 +571,8 @@ int ntfs_cluster_free_from_rl(ntfs_volume *vol, runlist *rl)
int ntfs_cluster_free(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn, s64 count) int ntfs_cluster_free(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn, s64 count)
{ {
runlist *rl; runlist *rl;
s64 nr_freed, delta, to_free; s64 delta, to_free, nr_freed = 0;
int ret = -1;
if (!vol || !vol->lcnbmp_na || !na || start_vcn < 0 || if (!vol || !vol->lcnbmp_na || !na || start_vcn < 0 ||
(count < 0 && count != -1)) { (count < 0 && count != -1)) {
@@ -535,21 +580,23 @@ int ntfs_cluster_free(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn, s64 count)
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, count 0x%llx, "
ntfs_log_enter("Entering for inode 0x%llx, attr 0x%x, count 0x%llx, "
"vcn 0x%llx.\n", (unsigned long long)na->ni->mft_no, "vcn 0x%llx.\n", (unsigned long long)na->ni->mft_no,
na->type, (long long)count, (long long)start_vcn); na->type, (long long)count, (long long)start_vcn);
rl = ntfs_attr_find_vcn(na, start_vcn); rl = ntfs_attr_find_vcn(na, start_vcn);
if (!rl) { if (!rl) {
if (errno == ENOENT) if (errno == ENOENT)
return 0; ret = 0;
else goto leave;
return -1;
} }
if (rl->lcn < 0 && rl->lcn != LCN_HOLE) { if (rl->lcn < 0 && rl->lcn != LCN_HOLE) {
errno = EIO; errno = EIO;
return -1; ntfs_log_perror("%s: Unexpected lcn (%lld)", __FUNCTION__,
(long long)rl->lcn);
goto leave;
} }
/* Find the starting cluster inside the run that needs freeing. */ /* Find the starting cluster inside the run that needs freeing. */
@@ -564,12 +611,8 @@ int ntfs_cluster_free(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn, s64 count)
/* Do the actual freeing of the clusters in this run. */ /* Do the actual freeing of the clusters in this run. */
if (ntfs_bitmap_clear_run(vol->lcnbmp_na, rl->lcn + delta, if (ntfs_bitmap_clear_run(vol->lcnbmp_na, rl->lcn + delta,
to_free)) to_free))
return -1; goto leave;
/* We have freed @to_free real clusters. */
nr_freed = to_free; nr_freed = to_free;
} else {
/* No real clusters were freed. */
nr_freed = 0;
} }
/* Go to the next run and adjust the number of clusters left to free. */ /* Go to the next run and adjust the number of clusters left to free. */
@@ -586,11 +629,10 @@ int ntfs_cluster_free(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn, s64 count)
// list support! (AIA) // list support! (AIA)
if (rl->lcn < 0 && rl->lcn != LCN_HOLE) { if (rl->lcn < 0 && rl->lcn != LCN_HOLE) {
// FIXME: Eeek! We need rollback! (AIA) // FIXME: Eeek! We need rollback! (AIA)
ntfs_log_trace("Eeek! invalid lcn (= %lli). Should attempt "
"to map runlist! Leaving inconsistent "
"metadata!\n", (long long)rl->lcn);
errno = EIO; errno = EIO;
return -1; ntfs_log_perror("%s: Invalid lcn (%lli)",
__FUNCTION__, (long long)rl->lcn);
goto out;
} }
/* The number of clusters in this run that need freeing. */ /* The number of clusters in this run that need freeing. */
@@ -599,18 +641,13 @@ int ntfs_cluster_free(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn, s64 count)
to_free = count; to_free = count;
if (rl->lcn != LCN_HOLE) { if (rl->lcn != LCN_HOLE) {
/* Do the actual freeing of the clusters in the run. */
if (ntfs_bitmap_clear_run(vol->lcnbmp_na, rl->lcn, if (ntfs_bitmap_clear_run(vol->lcnbmp_na, rl->lcn,
to_free)) { to_free)) {
int eo = errno;
// FIXME: Eeek! We need rollback! (AIA) // FIXME: Eeek! We need rollback! (AIA)
ntfs_log_trace("Eeek! bitmap clear run failed. " ntfs_log_perror("%s: Clearing bitmap run failed",
"Leaving inconsistent metadata!\n"); __FUNCTION__);
errno = eo; goto out;
return -1;
} }
/* We have freed @to_free real clusters. */
nr_freed += to_free; nr_freed += to_free;
} }
@@ -620,12 +657,20 @@ int ntfs_cluster_free(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn, s64 count)
if (count != -1 && count != 0) { if (count != -1 && count != 0) {
// FIXME: Eeek! BUG() // FIXME: Eeek! BUG()
ntfs_log_trace("Eeek! count still not zero (= %lli). Leaving "
"inconsistent metadata!\n", (long long)count);
errno = EIO; errno = EIO;
return -1; ntfs_log_perror("%s: count still not zero (%lld)", __FUNCTION__,
(long long)count);
goto out;
} }
/* Done. Return the number of actual clusters that were freed. */ ret = nr_freed;
return nr_freed; out:
vol->free_clusters += nr_freed ;
if (vol->free_clusters > vol->nr_clusters)
ntfs_log_error("Too many free clusters (%lld > %lld)!",
(long long)vol->free_clusters,
(long long)vol->nr_clusters);
leave:
ntfs_log_leave("\n");
return ret;
} }
@@ -3,7 +3,7 @@
* *
* Copyright (c) 2002-2005 Anton Altaparmakov * Copyright (c) 2002-2005 Anton Altaparmakov
* Copyright (c) 2005 Yura Pakhuchiy * Copyright (c) 2005 Yura Pakhuchiy
* Copyright (c) 2005-2006 Szabolcs Szakacsits * Copyright (c) 2005-2009 Szabolcs Szakacsits
* *
* This program/include file is free software; you can redistribute it and/or * This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published * modify it under the terms of the GNU General Public License as published
@@ -676,8 +676,8 @@ BOOL ntfs_is_logfile_clean(ntfs_attr *log_na, RESTART_PAGE_HEADER *rp)
*/ */
if (ra->client_in_use_list != LOGFILE_NO_CLIENT && if (ra->client_in_use_list != LOGFILE_NO_CLIENT &&
!(ra->flags & RESTART_VOLUME_IS_CLEAN)) { !(ra->flags & RESTART_VOLUME_IS_CLEAN)) {
ntfs_log_error("$LogFile indicates unclean shutdown (%d, %d)\n", ntfs_log_error("The disk contains an unclean file system (%d, "
le16_to_cpu(ra->client_in_use_list), "%d).\n", le16_to_cpu(ra->client_in_use_list),
le16_to_cpu(ra->flags)); le16_to_cpu(ra->flags));
return FALSE; return FALSE;
} }
@@ -2,7 +2,7 @@
* logging.c - Centralised logging. Originated from the Linux-NTFS project. * logging.c - Centralised logging. Originated from the Linux-NTFS project.
* *
* Copyright (c) 2005 Richard Russon * Copyright (c) 2005 Richard Russon
* Copyright (c) 2005-2006 Szabolcs Szakacsits * Copyright (c) 2005-2008 Szabolcs Szakacsits
* *
* This program/include file is free software; you can redistribute it and/or * This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published * modify it under the terms of the GNU General Public License as published
@@ -50,13 +50,16 @@
#define PATH_SEP '/' #define PATH_SEP '/'
#endif #endif
/* Colour prefixes and a suffix */ #ifdef DEBUG
static const char *col_green = "\e[32m"; static int tab;
static const char *col_cyan = "\e[36m"; #endif
static const char *col_yellow = "\e[01;33m";
static const char *col_red = "\e[01;31m"; /* Some gcc 3.x, 4.[01].X crash with internal compiler error. */
static const char *col_redinv = "\e[01;07;31m"; #if __GNUC__ <= 3 || (__GNUC__ == 4 && __GNUC_MINOR__ <= 1)
static const char *col_end = "\e[0m"; # define BROKEN_GCC_FORMAT_ATTRIBUTE
#else
# define BROKEN_GCC_FORMAT_ATTRIBUTE __attribute__((format(printf, 6, 0)))
#endif
/** /**
* struct ntfs_logging - Control info for the logging system * struct ntfs_logging - Control info for the logging system
@@ -67,7 +70,7 @@ static const char *col_end = "\e[0m";
struct ntfs_logging { struct ntfs_logging {
u32 levels; u32 levels;
u32 flags; u32 flags;
ntfs_log_handler *handler; ntfs_log_handler *handler BROKEN_GCC_FORMAT_ATTRIBUTE;
}; };
/** /**
@@ -76,7 +79,8 @@ struct ntfs_logging {
*/ */
static struct ntfs_logging ntfs_log = { static struct ntfs_logging ntfs_log = {
#ifdef DEBUG #ifdef DEBUG
NTFS_LOG_LEVEL_DEBUG | NTFS_LOG_LEVEL_TRACE | NTFS_LOG_LEVEL_DEBUG | NTFS_LOG_LEVEL_TRACE | NTFS_LOG_LEVEL_ENTER |
NTFS_LOG_LEVEL_LEAVE |
#endif #endif
NTFS_LOG_LEVEL_INFO | NTFS_LOG_LEVEL_QUIET | NTFS_LOG_LEVEL_WARNING | NTFS_LOG_LEVEL_INFO | NTFS_LOG_LEVEL_QUIET | NTFS_LOG_LEVEL_WARNING |
NTFS_LOG_LEVEL_ERROR | NTFS_LOG_LEVEL_PERROR | NTFS_LOG_LEVEL_CRITICAL | NTFS_LOG_LEVEL_ERROR | NTFS_LOG_LEVEL_PERROR | NTFS_LOG_LEVEL_CRITICAL |
@@ -183,7 +187,7 @@ u32 ntfs_log_clear_flags(u32 flags)
return old; return old;
} }
#ifndef __HAIKU__
/** /**
* ntfs_log_get_stream - Default output streams for logging levels * ntfs_log_get_stream - Default output streams for logging levels
* @level: Log level * @level: Log level
@@ -195,9 +199,6 @@ u32 ntfs_log_clear_flags(u32 flags)
*/ */
static FILE * ntfs_log_get_stream(u32 level) static FILE * ntfs_log_get_stream(u32 level)
{ {
#if defined(__BEOS__) || defined(__HAIKU__)
return NULL;
#else
FILE *stream; FILE *stream;
switch (level) { switch (level) {
@@ -210,6 +211,8 @@ static FILE * ntfs_log_get_stream(u32 level)
case NTFS_LOG_LEVEL_DEBUG: case NTFS_LOG_LEVEL_DEBUG:
case NTFS_LOG_LEVEL_TRACE: case NTFS_LOG_LEVEL_TRACE:
case NTFS_LOG_LEVEL_ENTER:
case NTFS_LOG_LEVEL_LEAVE:
case NTFS_LOG_LEVEL_WARNING: case NTFS_LOG_LEVEL_WARNING:
case NTFS_LOG_LEVEL_ERROR: case NTFS_LOG_LEVEL_ERROR:
case NTFS_LOG_LEVEL_CRITICAL: case NTFS_LOG_LEVEL_CRITICAL:
@@ -220,7 +223,6 @@ static FILE * ntfs_log_get_stream(u32 level)
} }
return stream; return stream;
#endif
} }
/** /**
@@ -273,7 +275,7 @@ static const char * ntfs_log_get_prefix(u32 level)
return prefix; return prefix;
} }
#endif
/** /**
* ntfs_log_set_handler - Provide an alternate logging handler * ntfs_log_set_handler - Provide an alternate logging handler
@@ -288,7 +290,7 @@ void ntfs_log_set_handler(ntfs_log_handler *handler)
ntfs_log.handler = handler; ntfs_log.handler = handler;
#ifdef HAVE_SYSLOG_H #ifdef HAVE_SYSLOG_H
if (handler == ntfs_log_handler_syslog) if (handler == ntfs_log_handler_syslog)
openlog("libntfs", LOG_PID, LOG_USER); openlog("ntfs-3g", LOG_PID, LOG_USER);
#endif #endif
} else } else
ntfs_log.handler = ntfs_log_handler_null; ntfs_log.handler = ntfs_log_handler_null;
@@ -359,23 +361,28 @@ int ntfs_log_handler_syslog(const char *function __attribute__((unused)),
void *data __attribute__((unused)), void *data __attribute__((unused)),
const char *format, va_list args) const char *format, va_list args)
{ {
char log[LOG_LINE_LEN]; char logbuf[LOG_LINE_LEN];
int ret, olderr = errno; int ret, olderr = errno;
ret = vsnprintf(log, LOG_LINE_LEN, format, args); #ifndef DEBUG
if ((level & NTFS_LOG_LEVEL_PERROR) && errno == ENOSPC)
return 1;
#endif
ret = vsnprintf(logbuf, LOG_LINE_LEN, format, args);
if (ret < 0) { if (ret < 0) {
vsyslog(LOG_NOTICE, format, args); vsyslog(LOG_NOTICE, format, args);
return 1; ret = 1;
goto out;
} }
if ((LOG_LINE_LEN > ret + 3) && (level & NTFS_LOG_LEVEL_PERROR)) { if ((LOG_LINE_LEN > ret + 3) && (level & NTFS_LOG_LEVEL_PERROR)) {
strncat(log, ": ", LOG_LINE_LEN - ret - 1); strncat(logbuf, ": ", LOG_LINE_LEN - ret - 1);
strncat(log, strerror(olderr), LOG_LINE_LEN - (ret + 3)); strncat(logbuf, strerror(olderr), LOG_LINE_LEN - (ret + 3));
ret = strlen(log); ret = strlen(logbuf);
} }
syslog(LOG_NOTICE, "%s", log); syslog(LOG_NOTICE, "%s", logbuf);
out:
errno = olderr; errno = olderr;
return ret; return ret;
} }
@@ -405,49 +412,30 @@ int ntfs_log_handler_syslog(const char *function __attribute__((unused)),
int ntfs_log_handler_fprintf(const char *function, const char *file, int ntfs_log_handler_fprintf(const char *function, const char *file,
int line, u32 level, void *data, const char *format, va_list args) int line, u32 level, void *data, const char *format, va_list args)
{ {
#if defined(__BEOS__) || defined(__HAIKU__) #ifdef __HAIKU__
return 0; return 0;
#else #else
#ifdef DEBUG
int i;
#endif
int ret = 0; int ret = 0;
int olderr = errno; int olderr = errno;
FILE *stream; FILE *stream;
const char *col_prefix = NULL;
const char *col_suffix = NULL;
if (!data) /* Interpret data as a FILE stream. */ if (!data) /* Interpret data as a FILE stream. */
return 0; /* If it's NULL, we can't do anything. */ return 0; /* If it's NULL, we can't do anything. */
stream = (FILE*)data; stream = (FILE*)data;
if (ntfs_log.flags & NTFS_LOG_FLAG_COLOUR) { #ifdef DEBUG
/* Pick a colour determined by the log level */ if (level == NTFS_LOG_LEVEL_LEAVE) {
switch (level) { if (tab)
case NTFS_LOG_LEVEL_DEBUG: tab--;
col_prefix = col_green; return 0;
col_suffix = col_end;
break;
case NTFS_LOG_LEVEL_TRACE:
col_prefix = col_cyan;
col_suffix = col_end;
break;
case NTFS_LOG_LEVEL_WARNING:
col_prefix = col_yellow;
col_suffix = col_end;
break;
case NTFS_LOG_LEVEL_ERROR:
case NTFS_LOG_LEVEL_PERROR:
col_prefix = col_red;
col_suffix = col_end;
break;
case NTFS_LOG_LEVEL_CRITICAL:
col_prefix = col_redinv;
col_suffix = col_end;
break;
}
} }
if (col_prefix) for (i = 0; i < tab; i++)
ret += fprintf(stream, col_prefix); ret += fprintf(stream, " ");
#endif
if ((ntfs_log.flags & NTFS_LOG_FLAG_ONLYNAME) && if ((ntfs_log.flags & NTFS_LOG_FLAG_ONLYNAME) &&
(strchr(file, PATH_SEP))) /* Abbreviate the filename */ (strchr(file, PATH_SEP))) /* Abbreviate the filename */
file = strrchr(file, PATH_SEP) + 1; file = strrchr(file, PATH_SEP) + 1;
@@ -462,7 +450,7 @@ int ntfs_log_handler_fprintf(const char *function, const char *file,
ret += fprintf(stream, "(%d) ", line); ret += fprintf(stream, "(%d) ", line);
if ((ntfs_log.flags & NTFS_LOG_FLAG_FUNCTION) || /* Source function */ if ((ntfs_log.flags & NTFS_LOG_FLAG_FUNCTION) || /* Source function */
(level & NTFS_LOG_LEVEL_TRACE)) (level & NTFS_LOG_LEVEL_TRACE) || (level & NTFS_LOG_LEVEL_ENTER))
ret += fprintf(stream, "%s(): ", function); ret += fprintf(stream, "%s(): ", function);
ret += vfprintf(stream, format, args); ret += vfprintf(stream, format, args);
@@ -470,10 +458,10 @@ int ntfs_log_handler_fprintf(const char *function, const char *file,
if (level & NTFS_LOG_LEVEL_PERROR) if (level & NTFS_LOG_LEVEL_PERROR)
ret += fprintf(stream, ": %s\n", strerror(olderr)); ret += fprintf(stream, ": %s\n", strerror(olderr));
if (col_suffix) #ifdef DEBUG
ret += fprintf(stream, col_suffix); if (level == NTFS_LOG_LEVEL_ENTER)
tab++;
#endif
fflush(stream); fflush(stream);
errno = olderr; errno = olderr;
return ret; return ret;
@@ -526,7 +514,7 @@ int ntfs_log_handler_null(const char *function __attribute__((unused)), const ch
int ntfs_log_handler_stdout(const char *function, const char *file, int ntfs_log_handler_stdout(const char *function, const char *file,
int line, u32 level, void *data, const char *format, va_list args) int line, u32 level, void *data, const char *format, va_list args)
{ {
#if defined(__BEOS__) || defined(__HAIKU__) #ifdef __HAIKU__
return 0; return 0;
#else #else
if (!data) if (!data)
@@ -561,7 +549,7 @@ int ntfs_log_handler_stdout(const char *function, const char *file,
int ntfs_log_handler_outerr(const char *function, const char *file, int ntfs_log_handler_outerr(const char *function, const char *file,
int line, u32 level, void *data, const char *format, va_list args) int line, u32 level, void *data, const char *format, va_list args)
{ {
#if defined(__BEOS__) || defined(__HAIKU__) #ifdef __HAIKU__
return 0; return 0;
#else #else
if (!data) if (!data)
@@ -595,7 +583,7 @@ int ntfs_log_handler_outerr(const char *function, const char *file,
int ntfs_log_handler_stderr(const char *function, const char *file, int ntfs_log_handler_stderr(const char *function, const char *file,
int line, u32 level, void *data, const char *format, va_list args) int line, u32 level, void *data, const char *format, va_list args)
{ {
#if defined(__BEOS__) || defined(__HAIKU__) #ifdef __HAIKU__
return 0; return 0;
#else #else
if (!data) if (!data)
@@ -633,10 +621,6 @@ BOOL ntfs_log_parse_option(const char *option)
} else if (strcmp(option, "--log-trace") == 0) { } else if (strcmp(option, "--log-trace") == 0) {
ntfs_log_set_levels(NTFS_LOG_LEVEL_TRACE); ntfs_log_set_levels(NTFS_LOG_LEVEL_TRACE);
return TRUE; return TRUE;
} else if ((strcmp(option, "--log-colour") == 0) ||
(strcmp(option, "--log-color") == 0)) {
ntfs_log_set_flags(NTFS_LOG_FLAG_COLOUR);
return TRUE;
} }
ntfs_log_debug("Unknown logging option '%s'\n", option); ntfs_log_debug("Unknown logging option '%s'\n", option);
@@ -2,6 +2,7 @@
* logging.h - Centralised logging. Originated from the Linux-NTFS project. * logging.h - Centralised logging. Originated from the Linux-NTFS project.
* *
* Copyright (c) 2005 Richard Russon * Copyright (c) 2005 Richard Russon
* Copyright (c) 2007-2008 Szabolcs Szakacsits
* *
* This program/include file is free software; you can redistribute it and/or * This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published * modify it under the terms of the GNU General Public License as published
@@ -37,7 +38,12 @@ typedef int (ntfs_log_handler)(const char *function, const char *file, int line,
u32 level, void *data, const char *format, va_list args); u32 level, void *data, const char *format, va_list args);
/* Set the logging handler from one of the functions, below. */ /* Set the logging handler from one of the functions, below. */
#ifdef __HAIKU__
void ntfs_log_set_handler(ntfs_log_handler *handler); void ntfs_log_set_handler(ntfs_log_handler *handler);
#else
void ntfs_log_set_handler(ntfs_log_handler *handler
__attribute__((format(printf, 6, 0))));
#endif
/* Logging handlers */ /* Logging handlers */
ntfs_log_handler ntfs_log_handler_syslog __attribute__((format(printf, 6, 0))); ntfs_log_handler ntfs_log_handler_syslog __attribute__((format(printf, 6, 0)));
@@ -75,6 +81,8 @@ int ntfs_log_redirect(const char *function, const char *file, int line,
#define NTFS_LOG_LEVEL_ERROR (1 << 7) /* Operation failed, no damage done */ #define NTFS_LOG_LEVEL_ERROR (1 << 7) /* Operation failed, no damage done */
#define NTFS_LOG_LEVEL_PERROR (1 << 8) /* Message : standard error description */ #define NTFS_LOG_LEVEL_PERROR (1 << 8) /* Message : standard error description */
#define NTFS_LOG_LEVEL_CRITICAL (1 << 9) /* Operation failed,damage may have occurred */ #define NTFS_LOG_LEVEL_CRITICAL (1 << 9) /* Operation failed,damage may have occurred */
#define NTFS_LOG_LEVEL_ENTER (1 << 10) /* Enter a function */
#define NTFS_LOG_LEVEL_LEAVE (1 << 11) /* Leave a function */
/* Logging style flags - Manage the style of the output */ /* Logging style flags - Manage the style of the output */
#define NTFS_LOG_FLAG_PREFIX (1 << 0) /* Prefix messages with "ERROR: ", etc */ #define NTFS_LOG_FLAG_PREFIX (1 << 0) /* Prefix messages with "ERROR: ", etc */
@@ -82,7 +90,6 @@ int ntfs_log_redirect(const char *function, const char *file, int line,
#define NTFS_LOG_FLAG_LINE (1 << 2) /* Show the line number of the message */ #define NTFS_LOG_FLAG_LINE (1 << 2) /* Show the line number of the message */
#define NTFS_LOG_FLAG_FUNCTION (1 << 3) /* Show the function name containing the message */ #define NTFS_LOG_FLAG_FUNCTION (1 << 3) /* Show the function name containing the message */
#define NTFS_LOG_FLAG_ONLYNAME (1 << 4) /* Only display the filename, not the pathname */ #define NTFS_LOG_FLAG_ONLYNAME (1 << 4) /* Only display the filename, not the pathname */
#define NTFS_LOG_FLAG_COLOUR (1 << 5) /* Colour highlight some messages */
/* Macros to simplify logging. One for each level defined above. /* Macros to simplify logging. One for each level defined above.
* Note, ntfs_log_debug/trace have effect only if DEBUG is defined. * Note, ntfs_log_debug/trace have effect only if DEBUG is defined.
@@ -102,9 +109,13 @@ int ntfs_log_redirect(const char *function, const char *file, int line,
#ifdef DEBUG #ifdef DEBUG
#define ntfs_log_debug(FORMAT, ARGS...) ntfs_log_redirect(__FUNCTION__,__FILE__,__LINE__,NTFS_LOG_LEVEL_DEBUG,NULL,FORMAT,##ARGS) #define ntfs_log_debug(FORMAT, ARGS...) ntfs_log_redirect(__FUNCTION__,__FILE__,__LINE__,NTFS_LOG_LEVEL_DEBUG,NULL,FORMAT,##ARGS)
#define ntfs_log_trace(FORMAT, ARGS...) ntfs_log_redirect(__FUNCTION__,__FILE__,__LINE__,NTFS_LOG_LEVEL_TRACE,NULL,FORMAT,##ARGS) #define ntfs_log_trace(FORMAT, ARGS...) ntfs_log_redirect(__FUNCTION__,__FILE__,__LINE__,NTFS_LOG_LEVEL_TRACE,NULL,FORMAT,##ARGS)
#define ntfs_log_enter(FORMAT, ARGS...) ntfs_log_redirect(__FUNCTION__,__FILE__,__LINE__,NTFS_LOG_LEVEL_ENTER,NULL,FORMAT,##ARGS)
#define ntfs_log_leave(FORMAT, ARGS...) ntfs_log_redirect(__FUNCTION__,__FILE__,__LINE__,NTFS_LOG_LEVEL_LEAVE,NULL,FORMAT,##ARGS)
#else #else
#define ntfs_log_debug(FORMAT, ARGS...)do {} while (0) #define ntfs_log_debug(FORMAT, ARGS...)do {} while (0)
#define ntfs_log_trace(FORMAT, ARGS...)do {} while (0) #define ntfs_log_trace(FORMAT, ARGS...)do {} while (0)
#define ntfs_log_enter(FORMAT, ARGS...)do {} while (0)
#define ntfs_log_leave(FORMAT, ARGS...)do {} while (0)
#endif /* DEBUG */ #endif /* DEBUG */
#endif /* _LOGGING_H_ */ #endif /* _LOGGING_H_ */
File diff suppressed because it is too large Load Diff
@@ -3,7 +3,7 @@
* *
* Copyright (c) 2000-2002 Anton Altaparmakov * Copyright (c) 2000-2002 Anton Altaparmakov
* Copyright (c) 2004-2005 Richard Russon * Copyright (c) 2004-2005 Richard Russon
* Copyright (c) 2006 Szabolcs Szakacsits * Copyright (c) 2006-2008 Szabolcs Szakacsits
* *
* This program/include file is free software; you can redistribute it and/or * This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published * modify it under the terms of the GNU General Public License as published
@@ -27,6 +27,7 @@
#include "volume.h" #include "volume.h"
#include "inode.h" #include "inode.h"
#include "layout.h" #include "layout.h"
#include "logging.h"
extern int ntfs_mft_records_read(const ntfs_volume *vol, const MFT_REF mref, extern int ntfs_mft_records_read(const ntfs_volume *vol, const MFT_REF mref,
const s64 count, MFT_RECORD *b); const s64 count, MFT_RECORD *b);
@@ -49,9 +50,17 @@ extern int ntfs_mft_records_read(const ntfs_volume *vol, const MFT_REF mref,
static __inline__ int ntfs_mft_record_read(const ntfs_volume *vol, static __inline__ int ntfs_mft_record_read(const ntfs_volume *vol,
const MFT_REF mref, MFT_RECORD *b) const MFT_REF mref, MFT_RECORD *b)
{ {
return ntfs_mft_records_read(vol, mref, 1, b); int ret;
ntfs_log_enter("Entering for inode %lld\n", (long long)MREF(mref));
ret = ntfs_mft_records_read(vol, mref, 1, b);
ntfs_log_leave("\n");
return ret;
} }
extern int ntfs_mft_record_check(const ntfs_volume *vol, const MFT_REF mref,
MFT_RECORD *m);
extern int ntfs_file_record_read(const ntfs_volume *vol, const MFT_REF mref, extern int ntfs_file_record_read(const ntfs_volume *vol, const MFT_REF mref,
MFT_RECORD **mrec, ATTR_RECORD **attr); MFT_RECORD **mrec, ATTR_RECORD **attr);
@@ -76,7 +85,12 @@ extern int ntfs_mft_records_write(const ntfs_volume *vol, const MFT_REF mref,
static __inline__ int ntfs_mft_record_write(const ntfs_volume *vol, static __inline__ int ntfs_mft_record_write(const ntfs_volume *vol,
const MFT_REF mref, MFT_RECORD *b) const MFT_REF mref, MFT_RECORD *b)
{ {
return ntfs_mft_records_write(vol, mref, 1, b); int ret;
ntfs_log_enter("Entering for inode %lld\n", (long long)MREF(mref));
ret = ntfs_mft_records_write(vol, mref, 1, b);
ntfs_log_leave("\n");
return ret;
} }
/** /**
@@ -34,18 +34,3 @@ void *ntfs_malloc(size_t size)
return p; return p;
} }
#if defined(__BEOS__) || defined(__HAIKU__)
#include <stdio.h>
int ntfs_snprintf(char *buff, size_t size, const char *format, ...)
{
int ret;
char buffer[BUF_SIZE];
va_list args;
va_start(args, format);
memset(buffer,0,BUF_SIZE);
ret = sprintf(buffer, format, args);
va_end(args);
strncpy(buff,buffer,size);
return ret;
}
#endif
@@ -4,10 +4,5 @@
void *ntfs_calloc(size_t size); void *ntfs_calloc(size_t size);
void *ntfs_malloc(size_t size); void *ntfs_malloc(size_t size);
#if defined(__BEOS__) || defined(__HAIKU__)
#define BUF_SIZE 16384
int ntfs_snprintf(char *buff, size_t size, const char *format, ...);
#define snprintf ntfs_snprintf
#endif
#endif /* _NTFS_MISC_H_ */ #endif /* _NTFS_MISC_H_ */
@@ -2,7 +2,7 @@
* mst.c - Multi sector fixup handling code. Originated from the Linux-NTFS project. * mst.c - Multi sector fixup handling code. Originated from the Linux-NTFS project.
* *
* Copyright (c) 2000-2004 Anton Altaparmakov * Copyright (c) 2000-2004 Anton Altaparmakov
* Copyright (c) 2006 Szabolcs Szakacsits * Copyright (c) 2006-2009 Szabolcs Szakacsits
* *
* This program/include file is free software; you can redistribute it and/or * This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published * modify it under the terms of the GNU General Public License as published
@@ -63,6 +63,9 @@ int ntfs_mst_post_read_fixup(NTFS_RECORD *b, const u32 size)
(u32)(usa_ofs + (usa_count * 2)) > size || (u32)(usa_ofs + (usa_count * 2)) > size ||
(size >> NTFS_BLOCK_SIZE_BITS) != usa_count) { (size >> NTFS_BLOCK_SIZE_BITS) != usa_count) {
errno = EINVAL; errno = EINVAL;
ntfs_log_perror("%s: magic: 0x%08x size: %d usa_ofs: %d "
"usa_count: %d", __FUNCTION__, *(le32 *)b,
size, usa_ofs, usa_count);
return -1; return -1;
} }
/* Position of usn in update sequence array. */ /* Position of usn in update sequence array. */
@@ -89,8 +92,12 @@ int ntfs_mst_post_read_fixup(NTFS_RECORD *b, const u32 size)
* Set the magic to "BAAD" and return failure. * Set the magic to "BAAD" and return failure.
* Note that magic_BAAD is already converted to le32. * Note that magic_BAAD is already converted to le32.
*/ */
b->magic = magic_BAAD;
errno = EIO; errno = EIO;
ntfs_log_perror("Incomplete multi-sector transfer: "
"magic: 0x%08x size: %d usa_ofs: %d usa_count:"
" %d data: %d usn: %d", *(le32 *)b, size,
usa_ofs, usa_count, *data_pos, usn);
b->magic = magic_BAAD;
return -1; return -1;
} }
data_pos += NTFS_BLOCK_SIZE/sizeof(u16); data_pos += NTFS_BLOCK_SIZE/sizeof(u16);
@@ -142,6 +149,7 @@ int ntfs_mst_pre_write_fixup(NTFS_RECORD *b, const u32 size)
if (!b || ntfs_is_baad_record(b->magic) || if (!b || ntfs_is_baad_record(b->magic) ||
ntfs_is_hole_record(b->magic)) { ntfs_is_hole_record(b->magic)) {
errno = EINVAL; errno = EINVAL;
ntfs_log_perror("%s: bad argument", __FUNCTION__);
return -1; return -1;
} }
/* Setup the variables. */ /* Setup the variables. */
@@ -153,6 +161,7 @@ int ntfs_mst_pre_write_fixup(NTFS_RECORD *b, const u32 size)
(u32)(usa_ofs + (usa_count * 2)) > size || (u32)(usa_ofs + (usa_count * 2)) > size ||
(size >> NTFS_BLOCK_SIZE_BITS) != usa_count) { (size >> NTFS_BLOCK_SIZE_BITS) != usa_count) {
errno = EINVAL; errno = EINVAL;
ntfs_log_perror("%s", __FUNCTION__);
return -1; return -1;
} }
/* Position of usn in update sequence array. */ /* Position of usn in update sequence array. */
@@ -3,7 +3,7 @@
* *
* Copyright (c) 2002-2005 Anton Altaparmakov * Copyright (c) 2002-2005 Anton Altaparmakov
* Copyright (c) 2002-2005 Richard Russon * Copyright (c) 2002-2005 Richard Russon
* Copyright (c) 2002-2006 Szabolcs Szakacsits * Copyright (c) 2002-2008 Szabolcs Szakacsits
* Copyright (c) 2004 Yura Pakhuchiy * Copyright (c) 2004 Yura Pakhuchiy
* *
* This program/include file is free software; you can redistribute it and/or * This program/include file is free software; you can redistribute it and/or
@@ -463,38 +463,9 @@ static runlist_element *ntfs_rl_split(runlist_element *dst, int dsize,
/** /**
* ntfs_runlists_merge - merge two runlists into one * ntfs_runlists_merge_i - see ntfs_runlists_merge
* @drl: original runlist to be worked on
* @srl: new runlist to be merged into @drl
*
* First we sanity check the two runlists @srl and @drl to make sure that they
* are sensible and can be merged. The runlist @srl must be either after the
* runlist @drl or completely within a hole (or unmapped region) in @drl.
*
* Merging of runlists is necessary in two cases:
* 1. When attribute lists are used and a further extent is being mapped.
* 2. When new clusters are allocated to fill a hole or extend a file.
*
* There are four possible ways @srl can be merged. It can:
* - be inserted at the beginning of a hole,
* - split the hole in two and be inserted between the two fragments,
* - be appended at the end of a hole, or it can
* - replace the whole hole.
* It can also be appended to the end of the runlist, which is just a variant
* of the insert case.
*
* On success, return a pointer to the new, combined, runlist. Note, both
* runlists @drl and @srl are deallocated before returning so you cannot use
* the pointers for anything any more. (Strictly speaking the returned runlist
* may be the same as @dst but this is irrelevant.)
*
* On error, return NULL, with errno set to the error code. Both runlists are
* left unmodified. The following error codes are defined:
* ENOMEM Not enough memory to allocate runlist array.
* EINVAL Invalid parameters were passed in.
* ERANGE The runlists overlap and cannot be merged.
*/ */
runlist_element *ntfs_runlists_merge(runlist_element *drl, static runlist_element *ntfs_runlists_merge_i(runlist_element *drl,
runlist_element *srl) runlist_element *srl)
{ {
int di, si; /* Current index into @[ds]rl. */ int di, si; /* Current index into @[ds]rl. */
@@ -544,9 +515,8 @@ runlist_element *ntfs_runlists_merge(runlist_element *drl,
/* Can't have an entirely unmapped source runlist. */ /* Can't have an entirely unmapped source runlist. */
if (!srl[si].length) { if (!srl[si].length) {
ntfs_log_debug("Eeek! ntfs_runlists_merge() received entirely "
"unmapped source runlist.\n");
errno = EINVAL; errno = EINVAL;
ntfs_log_perror("%s: unmapped source runlist", __FUNCTION__);
return NULL; return NULL;
} }
@@ -567,8 +537,8 @@ runlist_element *ntfs_runlists_merge(runlist_element *drl,
/* Sanity check for illegal overlaps. */ /* Sanity check for illegal overlaps. */
if ((drl[di].vcn == srl[si].vcn) && (drl[di].lcn >= 0) && if ((drl[di].vcn == srl[si].vcn) && (drl[di].lcn >= 0) &&
(srl[si].lcn >= 0)) { (srl[si].lcn >= 0)) {
ntfs_log_debug("Run lists overlap. Cannot merge!\n");
errno = ERANGE; errno = ERANGE;
ntfs_log_perror("Run lists overlap. Cannot merge");
return NULL; return NULL;
} }
@@ -702,6 +672,49 @@ critical_error:
return drl; return drl;
} }
/**
* ntfs_runlists_merge - merge two runlists into one
* @drl: original runlist to be worked on
* @srl: new runlist to be merged into @drl
*
* First we sanity check the two runlists @srl and @drl to make sure that they
* are sensible and can be merged. The runlist @srl must be either after the
* runlist @drl or completely within a hole (or unmapped region) in @drl.
*
* Merging of runlists is necessary in two cases:
* 1. When attribute lists are used and a further extent is being mapped.
* 2. When new clusters are allocated to fill a hole or extend a file.
*
* There are four possible ways @srl can be merged. It can:
* - be inserted at the beginning of a hole,
* - split the hole in two and be inserted between the two fragments,
* - be appended at the end of a hole, or it can
* - replace the whole hole.
* It can also be appended to the end of the runlist, which is just a variant
* of the insert case.
*
* On success, return a pointer to the new, combined, runlist. Note, both
* runlists @drl and @srl are deallocated before returning so you cannot use
* the pointers for anything any more. (Strictly speaking the returned runlist
* may be the same as @dst but this is irrelevant.)
*
* On error, return NULL, with errno set to the error code. Both runlists are
* left unmodified. The following error codes are defined:
* ENOMEM Not enough memory to allocate runlist array.
* EINVAL Invalid parameters were passed in.
* ERANGE The runlists overlap and cannot be merged.
*/
runlist_element *ntfs_runlists_merge(runlist_element *drl,
runlist_element *srl)
{
runlist_element *rl;
ntfs_log_enter("Entering\n");
rl = ntfs_runlists_merge_i(drl, srl);
ntfs_log_leave("\n");
return rl;
}
/** /**
* ntfs_mapping_pairs_decompress - convert mapping pairs array to runlist * ntfs_mapping_pairs_decompress - convert mapping pairs array to runlist
* @vol: ntfs volume on which the attribute resides * @vol: ntfs volume on which the attribute resides
@@ -729,7 +742,7 @@ critical_error:
* two into one, if that is possible (we check for overlap and discard the new * two into one, if that is possible (we check for overlap and discard the new
* runlist if overlap present before returning NULL, with errno = ERANGE). * runlist if overlap present before returning NULL, with errno = ERANGE).
*/ */
runlist_element *ntfs_mapping_pairs_decompress(const ntfs_volume *vol, runlist_element *ntfs_mapping_pairs_decompress_i(const ntfs_volume *vol,
const ATTR_RECORD *attr, runlist_element *old_rl) const ATTR_RECORD *attr, runlist_element *old_rl)
{ {
VCN vcn; /* Current vcn. */ VCN vcn; /* Current vcn. */
@@ -953,6 +966,17 @@ err_out:
return NULL; return NULL;
} }
runlist_element *ntfs_mapping_pairs_decompress(const ntfs_volume *vol,
const ATTR_RECORD *attr, runlist_element *old_rl)
{
runlist_element *rle;
ntfs_log_enter("Entering\n");
rle = ntfs_mapping_pairs_decompress_i(vol, attr, old_rl);
ntfs_log_leave("\n");
return rle;
}
/** /**
* ntfs_rl_vcn_to_lcn - convert a vcn into a lcn given a runlist * ntfs_rl_vcn_to_lcn - convert a vcn into a lcn given a runlist
* @rl: runlist to use for conversion * @rl: runlist to use for conversion
@@ -1642,16 +1666,16 @@ int ntfs_rl_sparse(runlist *rl)
runlist *rlc; runlist *rlc;
if (!rl) { if (!rl) {
ntfs_log_trace("Invalid argument passed.\n");
errno = EINVAL; errno = EINVAL;
ntfs_log_perror("%s: ", __FUNCTION__);
return -1; return -1;
} }
for (rlc = rl; rlc->length; rlc++) for (rlc = rl; rlc->length; rlc++)
if (rlc->lcn < 0) { if (rlc->lcn < 0) {
if (rlc->lcn != LCN_HOLE) { if (rlc->lcn != LCN_HOLE) {
ntfs_log_trace("Received unmapped runlist.\n");
errno = EINVAL; errno = EINVAL;
ntfs_log_perror("%s: bad runlist", __FUNCTION__);
return -1; return -1;
} }
return 1; return 1;
@@ -1672,16 +1696,16 @@ s64 ntfs_rl_get_compressed_size(ntfs_volume *vol, runlist *rl)
s64 ret = 0; s64 ret = 0;
if (!rl) { if (!rl) {
ntfs_log_trace("Invalid argument passed.\n");
errno = EINVAL; errno = EINVAL;
ntfs_log_perror("%s: ", __FUNCTION__);
return -1; return -1;
} }
for (rlc = rl; rlc->length; rlc++) { for (rlc = rl; rlc->length; rlc++) {
if (rlc->lcn < 0) { if (rlc->lcn < 0) {
if (rlc->lcn != LCN_HOLE) { if (rlc->lcn != LCN_HOLE) {
ntfs_log_trace("Received unmapped runlist.\n");
errno = EINVAL; errno = EINVAL;
ntfs_log_perror("%s: bad runlist", __FUNCTION__);
return -1; return -1;
} }
} else } else
@@ -43,6 +43,7 @@
#include "attrib.h" #include "attrib.h"
#include "security.h" #include "security.h"
#include "misc.h" #include "misc.h"
#include "bitmap.h"
/* /*
* The zero GUID. * The zero GUID.
@@ -338,3 +339,32 @@ int ntfs_sd_add_everyone(ntfs_inode *ni)
return ret; return ret;
} }
/**
* ntfs_security_hash - calculate the hash of a security descriptor
* @sd: self-relative security descriptor whose hash to calculate
* @length: size in bytes of the security descritor @sd
*
* Calculate the hash of the self-relative security descriptor @sd of length
* @length bytes.
*
* This hash is used in the $Secure system file as the primary key for the $SDH
* index and is also stored in the header of each security descriptor in the
* $SDS data stream as well as in the index data of both the $SII and $SDH
* indexes. In all three cases it forms part of the SDS_ENTRY_HEADER
* structure.
*
* Return the calculated security hash in little endian.
*/
le32 ntfs_security_hash(const SECURITY_DESCRIPTOR_RELATIVE *sd, const u32 len)
{
const le32 *pos = (const le32 *)sd;
const le32 *end = pos + (len >> 2);
u32 hash = 0;
while (pos < end) {
hash = le32_to_cpup(pos) + ntfs_rol32(hash, 3);
pos++;
}
return cpu_to_le32(hash);
}
@@ -55,4 +55,7 @@ extern char *ntfs_sid_to_mbs(const SID *sid, char *sid_str,
extern void ntfs_generate_guid(GUID *guid); extern void ntfs_generate_guid(GUID *guid);
extern int ntfs_sd_add_everyone(ntfs_inode *ni); extern int ntfs_sd_add_everyone(ntfs_inode *ni);
extern le32 ntfs_security_hash(const SECURITY_DESCRIPTOR_RELATIVE *sd,
const u32 len);
#endif /* defined _NTFS_SECURITY_H */ #endif /* defined _NTFS_SECURITY_H */
@@ -2,7 +2,9 @@
* unistr.c - Unicode string handling. Originated from the Linux-NTFS project. * unistr.c - Unicode string handling. Originated from the Linux-NTFS project.
* *
* Copyright (c) 2000-2004 Anton Altaparmakov * Copyright (c) 2000-2004 Anton Altaparmakov
* Copyright (c) 2002-2006 Szabolcs Szakacsits * Copyright (c) 2002-2009 Szabolcs Szakacsits
* Copyright (c) 2008-2009 Jean-Pierre Andre
* Copyright (c) 2008 Bernhard Kaindl
* *
* This program/include file is free software; you can redistribute it and/or * This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published * modify it under the terms of the GNU General Public License as published
@@ -39,7 +41,11 @@
#ifdef HAVE_ERRNO_H #ifdef HAVE_ERRNO_H
#include <errno.h> #include <errno.h>
#endif #endif
#ifdef HAVE_LOCALE_H
#include <locale.h>
#endif
#include "compat.h"
#include "attrib.h" #include "attrib.h"
#include "types.h" #include "types.h"
#include "unistr.h" #include "unistr.h"
@@ -47,6 +53,8 @@
#include "logging.h" #include "logging.h"
#include "misc.h" #include "misc.h"
#define NOREVBOM 0 /* JPA rejecting U+FFFE and U+FFFF, open to debate */
/* /*
* IMPORTANT * IMPORTANT
* ========= * =========
@@ -54,7 +62,9 @@
* All these routines assume that the Unicode characters are in little endian * All these routines assume that the Unicode characters are in little endian
* encoding inside the strings!!! * encoding inside the strings!!!
*/ */
#ifndef __HAIKU__
static int use_utf8 = 1; /* use UTF-8 encoding for file names */
#endif
/* /*
* This is used by the name collation functions to quickly determine what * This is used by the name collation functions to quickly determine what
* characters are (in)valid. * characters are (in)valid.
@@ -373,7 +383,326 @@ int ntfs_file_values_compare(const FILE_NAME_ATTR *file_name_attr1,
err_val, ic, upcase, upcase_len); err_val, ic, upcase, upcase_len);
} }
#if defined(__BEOS__) || defined(__HAIKU__) #ifndef __HAIKU__
/*
NTFS uses Unicode (UTF-16LE [NTFS-3G uses UCS-2LE, which is enough
for now]) for path names, but the Unicode code points need to be
converted before a path can be accessed under NTFS. For 7 bit ASCII/ANSI,
glibc does this even without a locale in a hard-coded fashion as that
appears to be is easy because the low 7-bit ASCII range appears to be
available in all charsets but it does not convert anything if
there was some error with the locale setup or none set up like
when mount is called during early boot where he (by policy) do
not use locales (and may be not available if /usr is not yet mounted),
so this patch fixes the resulting issues for systems which use
UTF-8 and for others, specifying the locale in fstab brings them
the encoding which they want.
If no locale is defined or there was a problem with setting one
up and whenever nl_langinfo(CODESET) returns a sting starting with
"ANSI", use an internal UCS-2LE <-> UTF-8 codeset converter to fix
the bug where NTFS-3G does not show any path names which include
international characters!!! (and also fails on creating them) as result.
Author: Bernhard Kaindl <bk@suse.de>
Jean-Pierre Andre made it compliant with RFC3629/RFC2781.
*/
/*
* Return the amount of 8-bit elements in UTF-8 needed (without the terminating
* null) to store a given UTF-16LE string.
*
* Return -1 with errno set if string has invalid byte sequence or too long.
*/
static int utf16_to_utf8_size(const ntfschar *ins, const int ins_len, int outs_len)
{
int i, ret = -1;
int count = 0;
BOOL surrog;
surrog = FALSE;
for (i = 0; i < ins_len && ins[i]; i++) {
unsigned short c = le16_to_cpu(ins[i]);
if (surrog) {
if ((c >= 0xdc00) && (c < 0xe000)) {
surrog = FALSE;
count += 4;
} else
goto fail;
} else
if (c < 0x80)
count++;
else if (c < 0x800)
count += 2;
else if (c < 0xd800)
count += 3;
else if (c < 0xdc00)
surrog = TRUE;
#if NOREVBOM
else if ((c >= 0xe000) && (c < 0xfffe))
#else
else if (c >= 0xe000)
#endif
count += 3;
else
goto fail;
if (count > outs_len) {
errno = ENAMETOOLONG;
goto out;
}
}
if (surrog)
goto fail;
ret = count;
out:
return ret;
fail:
errno = EILSEQ;
goto out;
}
/*
* ntfs_utf16_to_utf8 - convert a little endian UTF16LE string to an UTF-8 string
* @ins: input utf16 string buffer
* @ins_len: length of input string in utf16 characters
* @outs: on return contains the (allocated) output multibyte string
* @outs_len: length of output buffer in bytes
*
* Return -1 with errno set if string has invalid byte sequence or too long.
*/
static int ntfs_utf16_to_utf8(const ntfschar *ins, const int ins_len,
char **outs, int outs_len)
{
char *t;
int i, size, ret = -1;
ntfschar halfpair;
halfpair = 0;
if (!*outs)
outs_len = PATH_MAX;
size = utf16_to_utf8_size(ins, ins_len, outs_len);
if (size < 0)
goto out;
if (!*outs) {
outs_len = size + 1;
*outs = ntfs_malloc(outs_len);
if (!*outs)
goto out;
}
t = *outs;
for (i = 0; i < ins_len && ins[i]; i++) {
unsigned short c = le16_to_cpu(ins[i]);
/* size not double-checked */
if (halfpair) {
if ((c >= 0xdc00) && (c < 0xe000)) {
*t++ = 0xf0 + (((halfpair + 64) >> 8) & 7);
*t++ = 0x80 + (((halfpair + 64) >> 2) & 63);
*t++ = 0x80 + ((c >> 6) & 15) + ((halfpair & 3) << 4);
*t++ = 0x80 + (c & 63);
halfpair = 0;
} else
goto fail;
} else if (c < 0x80) {
*t++ = c;
} else {
if (c < 0x800) {
*t++ = (0xc0 | ((c >> 6) & 0x3f));
*t++ = 0x80 | (c & 0x3f);
} else if (c < 0xd800) {
*t++ = 0xe0 | (c >> 12);
*t++ = 0x80 | ((c >> 6) & 0x3f);
*t++ = 0x80 | (c & 0x3f);
} else if (c < 0xdc00)
halfpair = c;
else if (c >= 0xe000) {
*t++ = 0xe0 | (c >> 12);
*t++ = 0x80 | ((c >> 6) & 0x3f);
*t++ = 0x80 | (c & 0x3f);
} else
goto fail;
}
}
*t = '\0';
ret = t - *outs;
out:
return ret;
fail:
errno = EILSEQ;
goto out;
}
/*
* Return the amount of 16-bit elements in UTF-16LE needed
* (without the terminating null) to store given UTF-8 string.
*
* Return -1 with errno set if it's longer than PATH_MAX or string is invalid.
*
* Note: This does not check whether the input sequence is a valid utf8 string,
* and should be used only in context where such check is made!
*/
static int utf8_to_utf16_size(const char *s)
{
int ret = -1;
unsigned int byte;
size_t count = 0;
while ((byte = *((const unsigned char *)s++))) {
if (++count >= PATH_MAX)
goto fail;
if (byte >= 0xF5) {
errno = EILSEQ;
goto out;
}
if (!*s)
break;
if (byte >= 0xC0)
s++;
if (!*s)
break;
if (byte >= 0xE0)
s++;
if (!*s)
break;
if (byte >= 0xF0) {
s++;
if (++count >= PATH_MAX)
goto fail;
}
}
ret = count;
out:
return ret;
fail:
errno = ENAMETOOLONG;
goto out;
}
/*
* This converts one UTF-8 sequence to cpu-endian Unicode value
* within range U+0 .. U+10ffff and excluding U+D800 .. U+DFFF
*
* Return the number of used utf8 bytes or -1 with errno set
* if sequence is invalid.
*/
static int utf8_to_unicode(u32 *wc, const char *s)
{
unsigned int byte = *((const unsigned char *)s);
/* single byte */
if (byte == 0) {
*wc = (u32) 0;
return 0;
} else if (byte < 0x80) {
*wc = (u32) byte;
return 1;
/* double byte */
} else if (byte < 0xc2) {
goto fail;
} else if (byte < 0xE0) {
if (strlen(s) < 2)
goto fail;
if ((s[1] & 0xC0) == 0x80) {
*wc = ((u32)(byte & 0x1F) << 6)
| ((u32)(s[1] & 0x3F));
return 2;
} else
goto fail;
/* three-byte */
} else if (byte < 0xF0) {
if (strlen(s) < 3)
goto fail;
if (((s[1] & 0xC0) == 0x80) && ((s[2] & 0xC0) == 0x80)) {
*wc = ((u32)(byte & 0x0F) << 12)
| ((u32)(s[1] & 0x3F) << 6)
| ((u32)(s[2] & 0x3F));
/* Check valid ranges */
#if NOREVBOM
if (((*wc >= 0x800) && (*wc <= 0xD7FF))
|| ((*wc >= 0xe000) && (*wc <= 0xFFFD)))
return 3;
#else
if (((*wc >= 0x800) && (*wc <= 0xD7FF))
|| ((*wc >= 0xe000) && (*wc <= 0xFFFF)))
return 3;
#endif
}
goto fail;
/* four-byte */
} else if (byte < 0xF5) {
if (strlen(s) < 4)
goto fail;
if (((s[1] & 0xC0) == 0x80) && ((s[2] & 0xC0) == 0x80)
&& ((s[3] & 0xC0) == 0x80)) {
*wc = ((u32)(byte & 0x07) << 18)
| ((u32)(s[1] & 0x3F) << 12)
| ((u32)(s[2] & 0x3F) << 6)
| ((u32)(s[3] & 0x3F));
/* Check valid ranges */
if ((*wc <= 0x10ffff) && (*wc >= 0x10000))
return 4;
}
goto fail;
}
fail:
errno = EILSEQ;
return -1;
}
/**
* ntfs_utf8_to_utf16 - convert a UTF-8 string to a UTF-16LE string
* @ins: input multibyte string buffer
* @outs: on return contains the (allocated) output utf16 string
* @outs_len: length of output buffer in utf16 characters
*
* Return -1 with errno set.
*/
static int ntfs_utf8_to_utf16(const char *ins, ntfschar **outs)
{
const char *t = ins;
u32 wc;
ntfschar *outpos;
int shorts, ret = -1;
shorts = utf8_to_utf16_size(ins);
if (shorts < 0)
goto fail;
if (!*outs) {
*outs = ntfs_malloc((shorts + 1) * sizeof(ntfschar));
if (!*outs)
goto fail;
}
outpos = *outs;
while(1) {
int m = utf8_to_unicode(&wc, t);
if (m < 0)
goto fail;
if (wc < 0x10000)
*outpos++ = cpu_to_le16(wc);
else {
wc -= 0x10000;
*outpos++ = cpu_to_le16((wc >> 10) + 0xd800);
*outpos++ = cpu_to_le16((wc & 0x3ff) + 0xdc00);
}
if (m == 0)
break;
t += m;
}
ret = --outpos - *outs;
fail:
return ret;
}
#endif
#ifdef __HAIKU__
/* Encode a single wide character into a sequence of utf8 bytes. /* Encode a single wide character into a sequence of utf8 bytes.
* Returns the number of bytes consumed, or 0 on error. * Returns the number of bytes consumed, or 0 on error.
*/ */
@@ -562,10 +891,10 @@ int ntfs_ucstombs(const ntfschar *ins, const int ins_len, char **outs, int outs_
* ENAMETOOLONG Destination buffer is too small for input string. * ENAMETOOLONG Destination buffer is too small for input string.
* ENOMEM Not enough memory to allocate destination buffer. * ENOMEM Not enough memory to allocate destination buffer.
*/ */
int ntfs_mbstoucs(const char *ins, ntfschar **outs, int outs_len) int ntfs_mbstoucs(const char *ins, ntfschar **outs)
{ {
int in_len = strlen(ins); int in_len = strlen(ins);
int out_len = outs_len; int out_len = 0;
if(ntfs_duputf82uni((unsigned char*)ins,in_len,outs,&out_len)==0) if(ntfs_duputf82uni((unsigned char*)ins,in_len,outs,&out_len)==0)
return out_len; return out_len;
else else
@@ -620,6 +949,8 @@ int ntfs_ucstombs(const ntfschar *ins, const int ins_len, char **outs,
errno = ENAMETOOLONG; errno = ENAMETOOLONG;
return -1; return -1;
} }
if (use_utf8)
return ntfs_utf16_to_utf8(ins, ins_len, outs, outs_len);
if (!mbs) { if (!mbs) {
mbs_len = (ins_len + 1) * MB_CUR_MAX; mbs_len = (ins_len + 1) * MB_CUR_MAX;
mbs = ntfs_malloc(mbs_len); mbs = ntfs_malloc(mbs_len);
@@ -692,17 +1023,16 @@ err_out:
* ntfs_mbstoucs - convert a multibyte string to a little endian Unicode string * ntfs_mbstoucs - convert a multibyte string to a little endian Unicode string
* @ins: input multibyte string buffer * @ins: input multibyte string buffer
* @outs: on return contains the (allocated) output Unicode string * @outs: on return contains the (allocated) output Unicode string
* @outs_len: length of output buffer in Unicode characters
* *
* Convert the input multibyte string @ins, from the current locale into the * Convert the input multibyte string @ins, from the current locale into the
* corresponding little endian, 2-byte Unicode string. * corresponding little endian, 2-byte Unicode string.
* *
* If *@outs is NULL, the function allocates the string and the caller is * The function allocates the string and the caller is responsible for calling
* responsible for calling free(*@outs); when finished with it. * free(*@outs); when finished with it.
* *
* On success the function returns the number of Unicode characters written to * On success the function returns the number of Unicode characters written to
* the output string *@outs (>= 0), not counting the terminating Unicode NULL * the output string *@outs (>= 0), not counting the terminating Unicode NULL
* character. If the output string buffer was allocated, *@outs is set to it. * character.
* *
* On error, -1 is returned, and errno is set to the error code. The following * On error, -1 is returned, and errno is set to the error code. The following
* error codes can be expected: * error codes can be expected:
@@ -712,7 +1042,7 @@ err_out:
* ENAMETOOLONG Destination buffer is too small for input string. * ENAMETOOLONG Destination buffer is too small for input string.
* ENOMEM Not enough memory to allocate destination buffer. * ENOMEM Not enough memory to allocate destination buffer.
*/ */
int ntfs_mbstoucs(const char *ins, ntfschar **outs, int outs_len) int ntfs_mbstoucs(const char *ins, ntfschar **outs)
{ {
ntfschar *ucs; ntfschar *ucs;
const char *s; const char *s;
@@ -726,12 +1056,10 @@ int ntfs_mbstoucs(const char *ins, ntfschar **outs, int outs_len)
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
ucs = *outs;
ucs_len = outs_len; if (use_utf8)
if (ucs && !ucs_len) { return ntfs_utf8_to_utf16(ins, outs);
errno = ENAMETOOLONG;
return -1;
}
/* Determine the size of the multi-byte string in bytes. */ /* Determine the size of the multi-byte string in bytes. */
ins_size = strlen(ins); ins_size = strlen(ins);
/* Determine the length of the multi-byte string. */ /* Determine the length of the multi-byte string. */
@@ -763,31 +1091,21 @@ int ntfs_mbstoucs(const char *ins, ntfschar **outs, int outs_len)
} }
/* Add the NULL terminator. */ /* Add the NULL terminator. */
ins_len++; ins_len++;
if (!ucs) {
ucs_len = ins_len; ucs_len = ins_len;
ucs = ntfs_malloc(ucs_len * sizeof(ntfschar)); ucs = ntfs_malloc(ucs_len * sizeof(ntfschar));
if (!ucs) if (!ucs)
return -1; return -1;
}
#ifdef HAVE_MBSINIT #ifdef HAVE_MBSINIT
memset(&mbstate, 0, sizeof(mbstate)); memset(&mbstate, 0, sizeof(mbstate));
#else #else
mbtowc(NULL, NULL, 0); mbtowc(NULL, NULL, 0);
#endif #endif
for (i = o = cnt = 0; i < ins_size; i += cnt, o++) { for (i = o = cnt = 0; i < ins_size; i += cnt, o++) {
/* Reallocate memory if necessary or abort. */ /* Reallocate memory if necessary. */
if (o >= ucs_len) { if (o >= ucs_len) {
ntfschar *tc; ntfschar *tc;
if (ucs == *outs) {
errno = ENAMETOOLONG;
return -1;
}
/*
* We will never get here but hey, it's only a bit of
* extra code...
*/
ucs_len = (ucs_len * sizeof(ntfschar) + 64) & ~63; ucs_len = (ucs_len * sizeof(ntfschar) + 64) & ~63;
tc = (ntfschar*)realloc(ucs, ucs_len); tc = realloc(ucs, ucs_len);
if (!tc) if (!tc)
goto err_out; goto err_out;
ucs = tc; ucs = tc;
@@ -827,19 +1145,14 @@ int ntfs_mbstoucs(const char *ins, ntfschar **outs, int outs_len)
#endif #endif
/* Now write the NULL character. */ /* Now write the NULL character. */
ucs[o] = cpu_to_le16(L'\0'); ucs[o] = cpu_to_le16(L'\0');
if (*outs != ucs)
*outs = ucs; *outs = ucs;
return o; return o;
err_out: err_out:
if (ucs != *outs) {
int eo = errno;
free(ucs); free(ucs);
errno = eo;
}
return -1; return -1;
} }
#endif // defined(__BEOS__) || defined(__HAIKU__) #endif //__HAIKU__
/** /**
* ntfs_upcase_table_build - build the default upcase table for NTFS * ntfs_upcase_table_build - build the default upcase table for NTFS
@@ -928,7 +1241,7 @@ ntfschar *ntfs_str2ucs(const char *s, int *len)
{ {
ntfschar *ucs = NULL; ntfschar *ucs = NULL;
if (s && ((*len = ntfs_mbstoucs(s, &ucs, 0)) == -1)) { if (s && ((*len = ntfs_mbstoucs(s, &ucs)) == -1)) {
ntfs_log_perror("Couldn't convert '%s' to Unicode", s); ntfs_log_perror("Couldn't convert '%s' to Unicode", s);
return NULL; return NULL;
} }
@@ -958,3 +1271,26 @@ void ntfs_ucsfree(ntfschar *ucs)
free(ucs); free(ucs);
} }
/*
* Define the character encoding to be used.
* Use UTF-8 unless specified otherwise.
*/
#ifndef __HAIKU__
int ntfs_set_char_encoding(const char *locale)
{
use_utf8 = 0;
if (!locale || strstr(locale,"utf8") || strstr(locale,"UTF8")
|| strstr(locale,"utf-8") || strstr(locale,"UTF-8"))
use_utf8 = 1;
else
if (setlocale(LC_ALL, locale))
use_utf8 = 0;
else {
ntfs_log_error("Invalid locale, encoding to UTF-8\n");
use_utf8 = 1;
}
return 0; /* always successful */
}
#endif
@@ -57,7 +57,7 @@ extern int ntfs_file_values_compare(const FILE_NAME_ATTR *file_name_attr1,
extern int ntfs_ucstombs(const ntfschar *ins, const int ins_len, char **outs, extern int ntfs_ucstombs(const ntfschar *ins, const int ins_len, char **outs,
int outs_len); int outs_len);
extern int ntfs_mbstoucs(const char *ins, ntfschar **outs, int outs_len); extern int ntfs_mbstoucs(const char *ins, ntfschar **outs);
extern void ntfs_upcase_table_build(ntfschar *uc, u32 uc_len); extern void ntfs_upcase_table_build(ntfschar *uc, u32 uc_len);
@@ -112,8 +112,6 @@ static int ntfs_device_unix_io_open(struct ntfs_device *dev, int flags)
if ((flags & O_RDWR) != O_RDWR) if ((flags & O_RDWR) != O_RDWR)
NDevSetReadOnly(dev); NDevSetReadOnly(dev);
/* locking not implemented in BeOS */
#if !defined(__BEOS__) && !defined(__HAIKU__)
memset(&flk, 0, sizeof(flk)); memset(&flk, 0, sizeof(flk));
if (NDevReadOnly(dev)) if (NDevReadOnly(dev))
flk.l_type = F_RDLCK; flk.l_type = F_RDLCK;
@@ -129,7 +127,7 @@ static int ntfs_device_unix_io_open(struct ntfs_device *dev, int flags)
ntfs_log_perror("Failed to close '%s'", dev->d_name); ntfs_log_perror("Failed to close '%s'", dev->d_name);
goto err_out; goto err_out;
} }
#endif
NDevSetOpen(dev); NDevSetOpen(dev);
return 0; return 0;
err_out: err_out:
@@ -161,15 +159,13 @@ static int ntfs_device_unix_io_close(struct ntfs_device *dev)
ntfs_log_perror("Failed to fsync device %s", dev->d_name); ntfs_log_perror("Failed to fsync device %s", dev->d_name);
return -1; return -1;
} }
/* locking not implemented in BeOS */
#if !defined(__BEOS__) && !defined(__HAIKU__)
memset(&flk, 0, sizeof(flk)); memset(&flk, 0, sizeof(flk));
flk.l_type = F_UNLCK; flk.l_type = F_UNLCK;
flk.l_whence = SEEK_SET; flk.l_whence = SEEK_SET;
flk.l_start = flk.l_len = 0LL; flk.l_start = flk.l_len = 0LL;
if (fcntl(DEV_FD(dev), F_SETLK, &flk)) if (fcntl(DEV_FD(dev), F_SETLK, &flk))
ntfs_log_perror("Could not unlock %s", dev->d_name); ntfs_log_perror("Could not unlock %s", dev->d_name);
#endif
if (close(DEV_FD(dev))) { if (close(DEV_FD(dev))) {
ntfs_log_perror("Failed to close device %s", dev->d_name); ntfs_log_perror("Failed to close device %s", dev->d_name);
return -1; return -1;
@@ -247,11 +243,7 @@ static s64 ntfs_device_unix_io_write(struct ntfs_device *dev, const void *buf,
static s64 ntfs_device_unix_io_pread(struct ntfs_device *dev, void *buf, static s64 ntfs_device_unix_io_pread(struct ntfs_device *dev, void *buf,
s64 count, s64 offset) s64 count, s64 offset)
{ {
#if defined(__BEOS__) || defined(__HAIKU__)
return read_pos(DEV_FD(dev), offset, buf,count);
#else
return pread(DEV_FD(dev), buf, count, offset); return pread(DEV_FD(dev), buf, count, offset);
#endif
} }
/** /**
@@ -273,11 +265,7 @@ static s64 ntfs_device_unix_io_pwrite(struct ntfs_device *dev, const void *buf,
return -1; return -1;
} }
NDevSetDirty(dev); NDevSetDirty(dev);
#if defined(__BEOS__) || defined(__HAIKU__)
return write_pos(DEV_FD(dev), offset, buf,count);
#else
return pwrite(DEV_FD(dev), buf, count, offset); return pwrite(DEV_FD(dev), buf, count, offset);
#endif
} }
/** /**
@@ -1,40 +0,0 @@
/**
* version.c - Info about the NTFS library. Originated from the Linux-NTFS project.
*
* Copyright (c) 2005 Anton Altaparmakov
* Copyright (c) 2005 Richard Russon
*
* This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program/include file is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (in the main directory of the NTFS-3G
* distribution in the file COPYING); if not, write to the Free Software
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "version.h"
/* FIXME: merge libntfs into the user space NTFS driver */
static const char *libntfs_version_string = "22:0:0";
/**
* ntfs_libntfs_version - query version number of the ntfs library libntfs
*
* Returns pointer to a text string representing the version of libntfs.
*/
const char *ntfs_libntfs_version(void)
{
return libntfs_version_string;
}
@@ -1,29 +0,0 @@
/*
* version.h - Info about the NTFS library. Originated from the Linux-NTFS project.
*
* Copyright (c) 2005 Anton Altaparmakov
* Copyright (c) 2005 Richard Russon
*
* This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program/include file is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (in the main directory of the NTFS-3G
* distribution in the file COPYING); if not, write to the Free Software
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _NTFS_VERSION_H_
#define _NTFS_VERSION_H_
extern const char *ntfs_libntfs_version(void);
#endif /* _NTFS_VERSION_H_ */
@@ -2,7 +2,7 @@
* volume.c - NTFS volume handling code. Originated from the Linux-NTFS project. * volume.c - NTFS volume handling code. Originated from the Linux-NTFS project.
* *
* Copyright (c) 2000-2006 Anton Altaparmakov * Copyright (c) 2000-2006 Anton Altaparmakov
* Copyright (c) 2002-2006 Szabolcs Szakacsits * Copyright (c) 2002-2009 Szabolcs Szakacsits
* Copyright (c) 2004-2005 Richard Russon * Copyright (c) 2004-2005 Richard Russon
* *
* This program/include file is free software; you can redistribute it and/or * This program/include file is free software; you can redistribute it and/or
@@ -49,7 +49,11 @@
#ifdef HAVE_LIMITS_H #ifdef HAVE_LIMITS_H
#include <limits.h> #include <limits.h>
#endif #endif
#ifdef HAVE_LOCALE_H
#include <locale.h>
#endif
#include "compat.h"
#include "volume.h" #include "volume.h"
#include "attrib.h" #include "attrib.h"
#include "mft.h" #include "mft.h"
@@ -63,9 +67,51 @@
#include "logging.h" #include "logging.h"
#include "misc.h" #include "misc.h"
#ifndef PATH_MAX const char *ntfs_home =
#define PATH_MAX 4096 "Ntfs-3g news, support and information: http://ntfs-3g.org\n";
#endif
static const char *invalid_ntfs_msg =
"The device '%s' doesn't seem to have a valid NTFS.\n"
"Maybe the wrong device is used? Or the whole disk instead of a\n"
"partition (e.g. /dev/sda, not /dev/sda1)? Or the other way around?\n";
static const char *corrupt_volume_msg =
"NTFS is either inconsistent, or there is a hardware fault, or it's a\n"
"SoftRAID/FakeRAID hardware. In the first case run chkdsk /f on Windows\n"
"then reboot into Windows twice. The usage of the /f parameter is very\n"
"important! If the device is a SoftRAID/FakeRAID then first activate\n"
"it and mount a different device under the /dev/mapper/ directory, (e.g.\n"
"/dev/mapper/nvidia_eahaabcc1). Please see the 'dmraid' documentation\n"
"for more details.\n";
static const char *hibernated_volume_msg =
"The NTFS partition is hibernated. Please resume and shutdown Windows\n"
"properly, or mount the volume read-only with the 'ro' mount option, or\n"
"mount the volume read-write with the 'remove_hiberfile' mount option.\n"
"For example type on the command line:\n"
"\n"
" mount -t ntfs-3g -o remove_hiberfile %s %s\n"
"\n";
static const char *unclean_journal_msg =
"Write access is denied because the disk wasn't safely powered\n"
"off and the 'norecover' mount option was specified.\n";
static const char *opened_volume_msg =
"Mount is denied because the NTFS volume is already exclusively opened.\n"
"The volume may be already mounted, or another software may use it which\n"
"could be identified for example by the help of the 'fuser' command.\n";
static const char *fakeraid_msg =
"Either the device is missing or it's powered down, or you have\n"
"SoftRAID hardware and must use an activated, different device under\n"
"/dev/mapper/, (e.g. /dev/mapper/nvidia_eahaabcc1) to mount NTFS.\n"
"Please see the 'dmraid' documentation for help.\n";
static const char *access_denied_msg =
"Please check '%s' and the ntfs-3g binary permissions,\n"
"and the mounting user ID. More explanation is provided at\n"
"http://ntfs-3g.org/support.html#unprivileged\n";
/** /**
* ntfs_volume_alloc - Create an NTFS volume object and initialise it * ntfs_volume_alloc - Create an NTFS volume object and initialise it
@@ -76,17 +122,15 @@
*/ */
ntfs_volume *ntfs_volume_alloc(void) ntfs_volume *ntfs_volume_alloc(void)
{ {
return calloc(1, sizeof(ntfs_volume)); return ntfs_calloc(sizeof(ntfs_volume));
} }
static void ntfs_attr_free(ntfs_attr **na) static void ntfs_attr_free(ntfs_attr **na)
{ {
if (na && *na) { if (na && *na) {
ntfs_attr_close(*na); ntfs_attr_close(*na);
*na = NULL; *na = NULL;
} else }
ntfs_log_error("Tried to free NULL attribute pointer (%p)\n", na);
} }
static int ntfs_inode_free(ntfs_inode **ni) static int ntfs_inode_free(ntfs_inode **ni)
@@ -96,8 +140,7 @@ static int ntfs_inode_free(ntfs_inode **ni)
if (ni && *ni) { if (ni && *ni) {
ret = ntfs_inode_close(*ni); ret = ntfs_inode_close(*ni);
*ni = NULL; *ni = NULL;
} else }
ntfs_log_error("Tried to free NULL inode pointer (%p)\n", ni);
return ret; return ret;
} }
@@ -211,25 +254,14 @@ static int ntfs_mft_load(ntfs_volume *vol)
ntfs_log_perror("Error reading $MFT"); ntfs_log_perror("Error reading $MFT");
goto error_exit; goto error_exit;
} }
if (ntfs_is_baad_record(mb->magic)) {
ntfs_log_error("Incomplete multi sector transfer detected in " if (ntfs_mft_record_check(vol, 0, mb))
"$MFT.\n");
goto io_error_exit;
}
if (!ntfs_is_mft_record(mb->magic)) {
ntfs_log_error("$MFT has invalid magic.\n");
goto io_error_exit;
}
ctx = ntfs_attr_get_search_ctx(vol->mft_ni, NULL);
if (!ctx) {
ntfs_log_perror("Failed to allocate attribute search context");
goto error_exit; goto error_exit;
}
if (p2n(ctx->attr) < p2n(mb) || ctx = ntfs_attr_get_search_ctx(vol->mft_ni, NULL);
(char*)ctx->attr > (char*)mb + vol->mft_record_size) { if (!ctx)
ntfs_log_error("$MFT is corrupt.\n"); goto error_exit;
goto io_error_exit;
}
/* Find the $ATTRIBUTE_LIST attribute in $MFT if present. */ /* Find the $ATTRIBUTE_LIST attribute in $MFT if present. */
if (ntfs_attr_lookup(AT_ATTRIBUTE_LIST, AT_UNNAMED, 0, 0, 0, NULL, 0, if (ntfs_attr_lookup(AT_ATTRIBUTE_LIST, AT_UNNAMED, 0, 0, 0, NULL, 0,
ctx)) { ctx)) {
@@ -429,13 +461,10 @@ ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev, unsigned long flags)
ntfs_volume *vol; ntfs_volume *vol;
NTFS_BOOT_SECTOR *bs; NTFS_BOOT_SECTOR *bs;
int eo; int eo;
#ifdef DEBUG
const char *OK = "OK\n";
const char *FAILED = "FAILED\n";
#endif
if (!dev || !dev->d_ops || !dev->d_name) { if (!dev || !dev->d_ops || !dev->d_name) {
errno = EINVAL; errno = EINVAL;
ntfs_log_perror("%s: dev = %p", __FUNCTION__, dev);
return NULL; return NULL;
} }
@@ -447,6 +476,7 @@ ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev, unsigned long flags)
vol = ntfs_volume_alloc(); vol = ntfs_volume_alloc();
if (!vol) if (!vol)
goto error_exit; goto error_exit;
/* Create the default upcase table. */ /* Create the default upcase table. */
vol->upcase_len = 65536; vol->upcase_len = 65536;
vol->upcase = ntfs_malloc(vol->upcase_len * sizeof(ntfschar)); vol->upcase = ntfs_malloc(vol->upcase_len * sizeof(ntfschar));
@@ -455,32 +485,29 @@ ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev, unsigned long flags)
ntfs_upcase_table_build(vol->upcase, ntfs_upcase_table_build(vol->upcase,
vol->upcase_len * sizeof(ntfschar)); vol->upcase_len * sizeof(ntfschar));
if (flags & MS_RDONLY) if (flags & MS_RDONLY)
NVolSetReadOnly(vol); NVolSetReadOnly(vol);
if (flags & MS_NOATIME)
NVolSetNoATime(vol); /* ...->open needs bracketing to compile with glibc 2.7 */
ntfs_log_debug("Reading bootsector... "); if ((dev->d_ops->open)(dev, NVolReadOnly(vol) ? O_RDONLY: O_RDWR)) {
if (dev->d_ops->open(dev, NVolReadOnly(vol) ? O_RDONLY: O_RDWR)) { ntfs_log_perror("Error opening '%s'", dev->d_name);
ntfs_log_debug(FAILED);
ntfs_log_perror("Error opening partition device");
goto error_exit; goto error_exit;
} }
/* Attach the device to the volume. */ /* Attach the device to the volume. */
vol->dev = dev; vol->dev = dev;
/* Now read the bootsector. */ /* Now read the bootsector. */
br = ntfs_pread(dev, 0, sizeof(NTFS_BOOT_SECTOR), bs); br = ntfs_pread(dev, 0, sizeof(NTFS_BOOT_SECTOR), bs);
if (br != sizeof(NTFS_BOOT_SECTOR)) { if (br != sizeof(NTFS_BOOT_SECTOR)) {
ntfs_log_debug(FAILED);
if (br != -1) if (br != -1)
errno = EINVAL; errno = EINVAL;
if (!br) if (!br)
ntfs_log_error("Partition is smaller than bootsector " ntfs_log_error("Failed to read bootsector (size=0)\n");
"size.\n");
else else
ntfs_log_perror("Error reading bootsector"); ntfs_log_perror("Error reading bootsector");
goto error_exit; goto error_exit;
} }
ntfs_log_debug(OK);
if (!ntfs_boot_sector_is_ntfs(bs)) { if (!ntfs_boot_sector_is_ntfs(bs)) {
errno = EINVAL; errno = EINVAL;
goto error_exit; goto error_exit;
@@ -498,9 +525,7 @@ ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev, unsigned long flags)
"%s\n", strerror(errno)); "%s\n", strerror(errno));
/* We now initialize the cluster allocator. */ /* We now initialize the cluster allocator. */
mft_zone_size = vol->nr_clusters >> 3; /* 12.5% */
mft_zone_size = min(vol->nr_clusters >> 3, /* 12.5% */
200 * 1000 * 1024 >> vol->cluster_size_bits);
/* Setup the mft zone. */ /* Setup the mft zone. */
vol->mft_zone_start = vol->mft_zone_pos = vol->mft_lcn; vol->mft_zone_start = vol->mft_zone_pos = vol->mft_lcn;
@@ -540,9 +565,9 @@ ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev, unsigned long flags)
* respective zone. * respective zone.
*/ */
vol->data1_zone_pos = vol->mft_zone_end; vol->data1_zone_pos = vol->mft_zone_end;
ntfs_log_debug("data1_zone_pos = 0x%llx\n", vol->data1_zone_pos); ntfs_log_debug("data1_zone_pos = %lld\n", (long long)vol->data1_zone_pos);
vol->data2_zone_pos = 0; vol->data2_zone_pos = 0;
ntfs_log_debug("data2_zone_pos = 0x%llx\n", vol->data2_zone_pos); ntfs_log_debug("data2_zone_pos = %lld\n", (long long)vol->data2_zone_pos);
/* Set the mft data allocation position to mft record 24. */ /* Set the mft data allocation position to mft record 24. */
vol->mft_data_pos = 24; vol->mft_data_pos = 24;
@@ -552,22 +577,16 @@ ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev, unsigned long flags)
*/ */
/* Need to setup $MFT so we can use the library read functions. */ /* Need to setup $MFT so we can use the library read functions. */
ntfs_log_debug("Loading $MFT... ");
if (ntfs_mft_load(vol) < 0) { if (ntfs_mft_load(vol) < 0) {
ntfs_log_debug(FAILED);
ntfs_log_perror("Failed to load $MFT"); ntfs_log_perror("Failed to load $MFT");
goto error_exit; goto error_exit;
} }
ntfs_log_debug(OK);
/* Need to setup $MFTMirr so we can use the write functions, too. */ /* Need to setup $MFTMirr so we can use the write functions, too. */
ntfs_log_debug("Loading $MFTMirr... ");
if (ntfs_mftmirr_load(vol) < 0) { if (ntfs_mftmirr_load(vol) < 0) {
ntfs_log_debug(FAILED);
ntfs_log_perror("Failed to load $MFTMirr"); ntfs_log_perror("Failed to load $MFTMirr");
goto error_exit; goto error_exit;
} }
ntfs_log_debug(OK);
return vol; return vol;
error_exit: error_exit:
eo = errno; eo = errno;
@@ -646,7 +665,7 @@ static ntfs_inode *ntfs_hiberfile_open(ntfs_volume *vol)
return NULL; return NULL;
} }
unicode_len = ntfs_mbstoucs(hiberfile, &unicode, 0); unicode_len = ntfs_mbstoucs(hiberfile, &unicode);
if (unicode_len < 0) { if (unicode_len < 0) {
ntfs_log_perror("Couldn't convert 'hiberfil.sys' to Unicode"); ntfs_log_perror("Couldn't convert 'hiberfil.sys' to Unicode");
goto out; goto out;
@@ -684,11 +703,11 @@ out:
* Return: 0 if Windows isn't hibernated for sure * Return: 0 if Windows isn't hibernated for sure
* -1 otherwise and errno is set to the appropriate value * -1 otherwise and errno is set to the appropriate value
*/ */
static int ntfs_volume_check_hiberfile(ntfs_volume *vol) int ntfs_volume_check_hiberfile(ntfs_volume *vol, int verbose)
{ {
ntfs_inode *ni; ntfs_inode *ni;
ntfs_attr *na = NULL; ntfs_attr *na = NULL;
int i, bytes_read, err; int bytes_read, err;
char *buf = NULL; char *buf = NULL;
ni = ntfs_hiberfile_open(vol); ni = ntfs_hiberfile_open(vol);
@@ -714,23 +733,18 @@ static int ntfs_volume_check_hiberfile(ntfs_volume *vol)
goto out; goto out;
} }
if (bytes_read < NTFS_HIBERFILE_HEADER_SIZE) { if (bytes_read < NTFS_HIBERFILE_HEADER_SIZE) {
ntfs_log_error("Hibernated non-system partition, refused to " if (verbose)
"mount.\n"); ntfs_log_error("Hibernated non-system partition, "
"refused to mount.\n");
errno = EPERM; errno = EPERM;
goto out; goto out;
} }
if (memcmp(buf, "hibr", 4) == 0) { if (memcmp(buf, "hibr", 4) == 0) {
if (verbose)
ntfs_log_error("Windows is hibernated, refused to mount.\n"); ntfs_log_error("Windows is hibernated, refused to mount.\n");
errno = EPERM; errno = EPERM;
goto out; goto out;
} }
for (i = 0; i < NTFS_HIBERFILE_HEADER_SIZE; i++) {
if (buf[i]) {
ntfs_log_error("Windows is hibernated, won't mount.\n");
errno = EPERM;
goto out;
}
}
/* All right, all header bytes are zero */ /* All right, all header bytes are zero */
errno = 0; errno = 0;
out: out:
@@ -753,10 +767,9 @@ out:
* to mount as the ntfs volume. * to mount as the ntfs volume.
* *
* @flags is an optional second parameter. The same flags are used as for * @flags is an optional second parameter. The same flags are used as for
* the mount system call (man 2 mount). Currently only the following flags * the mount system call (man 2 mount). Currently only the following flag
* are implemented: * is implemented:
* MS_RDONLY - mount volume read-only * MS_RDONLY - mount volume read-only
* MS_NOATIME - do not update access time
* *
* The function opens the device @dev and verifies that it contains a valid * The function opens the device @dev and verifies that it contains a valid
* bootsector. Then, it allocates an ntfs_volume structure and initializes * bootsector. Then, it allocates an ntfs_volume structure and initializes
@@ -770,10 +783,6 @@ out:
ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags) ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags)
{ {
s64 l; s64 l;
#ifdef DEBUG
const char *OK = "OK\n";
const char *FAILED = "FAILED\n";
#endif
ntfs_volume *vol; ntfs_volume *vol;
u8 *m = NULL, *m2 = NULL; u8 *m = NULL, *m2 = NULL;
ntfs_attr_search_ctx *ctx = NULL; ntfs_attr_search_ctx *ctx = NULL;
@@ -786,10 +795,8 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags)
u32 u; u32 u;
vol = ntfs_volume_startup(dev, flags); vol = ntfs_volume_startup(dev, flags);
if (!vol) { if (!vol)
ntfs_log_perror("Failed to startup volume");
return NULL; return NULL;
}
/* Load data from $MFT and $MFTMirr and compare the contents. */ /* Load data from $MFT and $MFTMirr and compare the contents. */
m = ntfs_malloc(vol->mftmirr_size << vol->mft_record_size_bits); m = ntfs_malloc(vol->mftmirr_size << vol->mft_record_size_bits);
@@ -819,7 +826,7 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags)
} }
vol->mftmirr_size = l; vol->mftmirr_size = l;
} }
ntfs_log_debug("Comparing $MFTMirr to $MFT... "); ntfs_log_debug("Comparing $MFTMirr to $MFT...\n");
for (i = 0; i < vol->mftmirr_size; ++i) { for (i = 0; i < vol->mftmirr_size; ++i) {
MFT_RECORD *mrec, *mrec2; MFT_RECORD *mrec, *mrec2;
const char *ESTR[12] = { "$MFT", "$MFTMirr", "$LogFile", const char *ESTR[12] = { "$MFT", "$MFTMirr", "$LogFile",
@@ -837,14 +844,12 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags)
mrec = (MFT_RECORD*)(m + i * vol->mft_record_size); mrec = (MFT_RECORD*)(m + i * vol->mft_record_size);
if (mrec->flags & MFT_RECORD_IN_USE) { if (mrec->flags & MFT_RECORD_IN_USE) {
if (ntfs_is_baad_recordp(mrec)) { if (ntfs_is_baad_recordp(mrec)) {
ntfs_log_debug("FAILED\n");
ntfs_log_error("$MFT error: Incomplete multi " ntfs_log_error("$MFT error: Incomplete multi "
"sector transfer detected in " "sector transfer detected in "
"'%s'.\n", s); "'%s'.\n", s);
goto io_error_exit; goto io_error_exit;
} }
if (!ntfs_is_mft_recordp(mrec)) { if (!ntfs_is_mft_recordp(mrec)) {
ntfs_log_debug("FAILED\n");
ntfs_log_error("$MFT error: Invalid mft " ntfs_log_error("$MFT error: Invalid mft "
"record for '%s'.\n", s); "record for '%s'.\n", s);
goto io_error_exit; goto io_error_exit;
@@ -853,62 +858,59 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags)
mrec2 = (MFT_RECORD*)(m2 + i * vol->mft_record_size); mrec2 = (MFT_RECORD*)(m2 + i * vol->mft_record_size);
if (mrec2->flags & MFT_RECORD_IN_USE) { if (mrec2->flags & MFT_RECORD_IN_USE) {
if (ntfs_is_baad_recordp(mrec2)) { if (ntfs_is_baad_recordp(mrec2)) {
ntfs_log_debug("FAILED\n");
ntfs_log_error("$MFTMirr error: Incomplete " ntfs_log_error("$MFTMirr error: Incomplete "
"multi sector transfer " "multi sector transfer "
"detected in '%s'.\n", s); "detected in '%s'.\n", s);
goto io_error_exit; goto io_error_exit;
} }
if (!ntfs_is_mft_recordp(mrec2)) { if (!ntfs_is_mft_recordp(mrec2)) {
ntfs_log_debug("FAILED\n");
ntfs_log_error("$MFTMirr error: Invalid mft " ntfs_log_error("$MFTMirr error: Invalid mft "
"record for '%s'.\n", s); "record for '%s'.\n", s);
goto io_error_exit; goto io_error_exit;
} }
} }
if (memcmp(mrec, mrec2, ntfs_mft_record_get_data_size(mrec))) { if (memcmp(mrec, mrec2, ntfs_mft_record_get_data_size(mrec))) {
ntfs_log_debug(FAILED);
ntfs_log_error("$MFTMirr does not match $MFT (record " ntfs_log_error("$MFTMirr does not match $MFT (record "
"%d).\n", i); "%d).\n", i);
goto io_error_exit; goto io_error_exit;
} }
} }
ntfs_log_debug(OK);
free(m2); free(m2);
free(m); free(m);
m = m2 = NULL; m = m2 = NULL;
/* Now load the bitmap from $Bitmap. */ /* Now load the bitmap from $Bitmap. */
ntfs_log_debug("Loading $Bitmap... "); ntfs_log_debug("Loading $Bitmap...\n");
vol->lcnbmp_ni = ntfs_inode_open(vol, FILE_Bitmap); vol->lcnbmp_ni = ntfs_inode_open(vol, FILE_Bitmap);
if (!vol->lcnbmp_ni) { if (!vol->lcnbmp_ni) {
ntfs_log_debug(FAILED); ntfs_log_perror("Failed to open inode FILE_Bitmap");
ntfs_log_perror("Failed to open inode");
goto error_exit; goto error_exit;
} }
/* Get an ntfs attribute for $Bitmap/$DATA. */
vol->lcnbmp_na = ntfs_attr_open(vol->lcnbmp_ni, AT_DATA, AT_UNNAMED, 0); vol->lcnbmp_na = ntfs_attr_open(vol->lcnbmp_ni, AT_DATA, AT_UNNAMED, 0);
if (!vol->lcnbmp_na) { if (!vol->lcnbmp_na) {
ntfs_log_debug(FAILED);
ntfs_log_perror("Failed to open ntfs attribute"); ntfs_log_perror("Failed to open ntfs attribute");
goto error_exit; goto error_exit;
} }
/* Done with the $Bitmap mft record. */
ntfs_log_debug(OK); if (vol->lcnbmp_na->data_size > vol->lcnbmp_na->allocated_size) {
ntfs_log_error("Corrupt cluster map size (%lld > %lld)\n",
(long long)vol->lcnbmp_na->data_size,
(long long)vol->lcnbmp_na->allocated_size);
goto io_error_exit;
}
/* Now load the upcase table from $UpCase. */ /* Now load the upcase table from $UpCase. */
ntfs_log_debug("Loading $UpCase... "); ntfs_log_debug("Loading $UpCase...\n");
ni = ntfs_inode_open(vol, FILE_UpCase); ni = ntfs_inode_open(vol, FILE_UpCase);
if (!ni) { if (!ni) {
ntfs_log_debug(FAILED); ntfs_log_perror("Failed to open inode FILE_UpCase");
ntfs_log_perror("Failed to open inode");
goto error_exit; goto error_exit;
} }
/* Get an ntfs attribute for $UpCase/$DATA. */ /* Get an ntfs attribute for $UpCase/$DATA. */
na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0); na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
if (!na) { if (!na) {
ntfs_log_debug(FAILED);
ntfs_log_perror("Failed to open ntfs attribute"); ntfs_log_perror("Failed to open ntfs attribute");
goto error_exit; goto error_exit;
} }
@@ -919,7 +921,6 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags)
* characters. * characters.
*/ */
if (na->data_size & ~0x1ffffffffULL) { if (na->data_size & ~0x1ffffffffULL) {
ntfs_log_debug(FAILED);
ntfs_log_error("Error: Upcase table is too big (max 32-bit " ntfs_log_error("Error: Upcase table is too big (max 32-bit "
"allowed).\n"); "allowed).\n");
errno = EINVAL; errno = EINVAL;
@@ -930,15 +931,12 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags)
/* Throw away default table. */ /* Throw away default table. */
free(vol->upcase); free(vol->upcase);
vol->upcase = ntfs_malloc(na->data_size); vol->upcase = ntfs_malloc(na->data_size);
if (!vol->upcase) { if (!vol->upcase)
ntfs_log_debug(FAILED);
goto error_exit; goto error_exit;
} }
}
/* Read in the $DATA attribute value into the buffer. */ /* Read in the $DATA attribute value into the buffer. */
l = ntfs_attr_pread(na, 0, na->data_size, vol->upcase); l = ntfs_attr_pread(na, 0, na->data_size, vol->upcase);
if (l != na->data_size) { if (l != na->data_size) {
ntfs_log_debug(FAILED);
ntfs_log_error("Failed to read $UpCase, unexpected length " ntfs_log_error("Failed to read $UpCase, unexpected length "
"(%lld != %lld).\n", (long long)l, "(%lld != %lld).\n", (long long)l,
(long long)na->data_size); (long long)na->data_size);
@@ -946,7 +944,6 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags)
goto error_exit; goto error_exit;
} }
/* Done with the $UpCase mft record. */ /* Done with the $UpCase mft record. */
ntfs_log_debug(OK);
ntfs_attr_close(na); ntfs_attr_close(na);
if (ntfs_inode_close(ni)) { if (ntfs_inode_close(ni)) {
ntfs_log_perror("Failed to close $UpCase"); ntfs_log_perror("Failed to close $UpCase");
@@ -957,24 +954,20 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags)
* Now load $Volume and set the version information and flags in the * Now load $Volume and set the version information and flags in the
* vol structure accordingly. * vol structure accordingly.
*/ */
ntfs_log_debug("Loading $Volume... "); ntfs_log_debug("Loading $Volume...\n");
vol->vol_ni = ntfs_inode_open(vol, FILE_Volume); vol->vol_ni = ntfs_inode_open(vol, FILE_Volume);
if (!vol->vol_ni) { if (!vol->vol_ni) {
ntfs_log_debug(FAILED); ntfs_log_perror("Failed to open inode FILE_Volume");
ntfs_log_perror("Failed to open inode");
goto error_exit; goto error_exit;
} }
/* Get a search context for the $Volume/$VOLUME_INFORMATION lookup. */ /* Get a search context for the $Volume/$VOLUME_INFORMATION lookup. */
ctx = ntfs_attr_get_search_ctx(vol->vol_ni, NULL); ctx = ntfs_attr_get_search_ctx(vol->vol_ni, NULL);
if (!ctx) { if (!ctx)
ntfs_log_debug(FAILED);
ntfs_log_perror("Failed to allocate attribute search context");
goto error_exit; goto error_exit;
}
/* Find the $VOLUME_INFORMATION attribute. */ /* Find the $VOLUME_INFORMATION attribute. */
if (ntfs_attr_lookup(AT_VOLUME_INFORMATION, AT_UNNAMED, 0, 0, 0, NULL, if (ntfs_attr_lookup(AT_VOLUME_INFORMATION, AT_UNNAMED, 0, 0, 0, NULL,
0, ctx)) { 0, ctx)) {
ntfs_log_debug(FAILED);
ntfs_log_perror("$VOLUME_INFORMATION attribute not found in " ntfs_log_perror("$VOLUME_INFORMATION attribute not found in "
"$Volume"); "$Volume");
goto error_exit; goto error_exit;
@@ -982,7 +975,6 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags)
a = ctx->attr; a = ctx->attr;
/* Has to be resident. */ /* Has to be resident. */
if (a->non_resident) { if (a->non_resident) {
ntfs_log_debug(FAILED);
ntfs_log_error("Attribute $VOLUME_INFORMATION must be " ntfs_log_error("Attribute $VOLUME_INFORMATION must be "
"resident but it isn't.\n"); "resident but it isn't.\n");
errno = EIO; errno = EIO;
@@ -995,7 +987,6 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags)
le32_to_cpu(ctx->mrec->bytes_in_use) || le32_to_cpu(ctx->mrec->bytes_in_use) ||
le16_to_cpu(a->value_offset) + le32_to_cpu( le16_to_cpu(a->value_offset) + le32_to_cpu(
a->value_length) > le32_to_cpu(a->length)) { a->value_length) > le32_to_cpu(a->length)) {
ntfs_log_debug(FAILED);
ntfs_log_error("$VOLUME_INFORMATION in $Volume is corrupt.\n"); ntfs_log_error("$VOLUME_INFORMATION in $Volume is corrupt.\n");
errno = EIO; errno = EIO;
goto error_exit; goto error_exit;
@@ -1013,7 +1004,6 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags)
if (ntfs_attr_lookup(AT_VOLUME_NAME, AT_UNNAMED, 0, 0, 0, NULL, 0, if (ntfs_attr_lookup(AT_VOLUME_NAME, AT_UNNAMED, 0, 0, 0, NULL, 0,
ctx)) { ctx)) {
if (errno != ENOENT) { if (errno != ENOENT) {
ntfs_log_debug(FAILED);
ntfs_log_perror("Failed to lookup of $VOLUME_NAME in " ntfs_log_perror("Failed to lookup of $VOLUME_NAME in "
"$Volume failed"); "$Volume failed");
goto error_exit; goto error_exit;
@@ -1024,16 +1014,13 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags)
* had zero length. * had zero length.
*/ */
vol->vol_name = ntfs_malloc(1); vol->vol_name = ntfs_malloc(1);
if (!vol->vol_name) { if (!vol->vol_name)
ntfs_log_debug(FAILED);
goto error_exit; goto error_exit;
}
vol->vol_name[0] = '\0'; vol->vol_name[0] = '\0';
} else { } else {
a = ctx->attr; a = ctx->attr;
/* Has to be resident. */ /* Has to be resident. */
if (a->non_resident) { if (a->non_resident) {
ntfs_log_debug(FAILED);
ntfs_log_error("$VOLUME_NAME must be resident.\n"); ntfs_log_error("$VOLUME_NAME must be resident.\n");
errno = EIO; errno = EIO;
goto error_exit; goto error_exit;
@@ -1052,10 +1039,9 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags)
ntfs_log_debug("Forcing name into ASCII by replacing " ntfs_log_debug("Forcing name into ASCII by replacing "
"non-ASCII characters with underscores.\n"); "non-ASCII characters with underscores.\n");
vol->vol_name = ntfs_malloc(u + 1); vol->vol_name = ntfs_malloc(u + 1);
if (!vol->vol_name) { if (!vol->vol_name)
ntfs_log_debug(FAILED);
goto error_exit; goto error_exit;
}
for (j = 0; j < (s32)u; j++) { for (j = 0; j < (s32)u; j++) {
ntfschar uc = le16_to_cpu(vname[j]); ntfschar uc = le16_to_cpu(vname[j]);
if (uc > 0xff) if (uc > 0xff)
@@ -1065,27 +1051,23 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags)
vol->vol_name[u] = '\0'; vol->vol_name[u] = '\0';
} }
} }
ntfs_log_debug(OK);
ntfs_attr_put_search_ctx(ctx); ntfs_attr_put_search_ctx(ctx);
ctx = NULL; ctx = NULL;
/* Now load the attribute definitions from $AttrDef. */ /* Now load the attribute definitions from $AttrDef. */
ntfs_log_debug("Loading $AttrDef... "); ntfs_log_debug("Loading $AttrDef...\n");
ni = ntfs_inode_open(vol, FILE_AttrDef); ni = ntfs_inode_open(vol, FILE_AttrDef);
if (!ni) { if (!ni) {
ntfs_log_debug(FAILED);
ntfs_log_perror("Failed to open $AttrDef"); ntfs_log_perror("Failed to open $AttrDef");
goto error_exit; goto error_exit;
} }
/* Get an ntfs attribute for $AttrDef/$DATA. */ /* Get an ntfs attribute for $AttrDef/$DATA. */
na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0); na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
if (!na) { if (!na) {
ntfs_log_debug(FAILED);
ntfs_log_perror("Failed to open ntfs attribute"); ntfs_log_perror("Failed to open ntfs attribute");
goto error_exit; goto error_exit;
} }
/* Check we don't overflow 32-bits. */ /* Check we don't overflow 32-bits. */
if (na->data_size > 0xffffffffLL) { if (na->data_size > 0xffffffffLL) {
ntfs_log_debug(FAILED);
ntfs_log_error("Attribute definition table is too big (max " ntfs_log_error("Attribute definition table is too big (max "
"32-bit allowed).\n"); "32-bit allowed).\n");
errno = EINVAL; errno = EINVAL;
@@ -1093,14 +1075,11 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags)
} }
vol->attrdef_len = na->data_size; vol->attrdef_len = na->data_size;
vol->attrdef = ntfs_malloc(na->data_size); vol->attrdef = ntfs_malloc(na->data_size);
if (!vol->attrdef) { if (!vol->attrdef)
ntfs_log_debug(FAILED);
goto error_exit; goto error_exit;
}
/* Read in the $DATA attribute value into the buffer. */ /* Read in the $DATA attribute value into the buffer. */
l = ntfs_attr_pread(na, 0, na->data_size, vol->attrdef); l = ntfs_attr_pread(na, 0, na->data_size, vol->attrdef);
if (l != na->data_size) { if (l != na->data_size) {
ntfs_log_debug(FAILED);
ntfs_log_error("Failed to read $AttrDef, unexpected length " ntfs_log_error("Failed to read $AttrDef, unexpected length "
"(%lld != %lld).\n", (long long)l, "(%lld != %lld).\n", (long long)l,
(long long)na->data_size); (long long)na->data_size);
@@ -1108,7 +1087,6 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags)
goto error_exit; goto error_exit;
} }
/* Done with the $AttrDef mft record. */ /* Done with the $AttrDef mft record. */
ntfs_log_debug(OK);
ntfs_attr_close(na); ntfs_attr_close(na);
if (ntfs_inode_close(ni)) { if (ntfs_inode_close(ni)) {
ntfs_log_perror("Failed to close $AttrDef"); ntfs_log_perror("Failed to close $AttrDef");
@@ -1119,12 +1097,14 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags)
* We care only about read-write mounts. * We care only about read-write mounts.
*/ */
if (!(flags & MS_RDONLY)) { if (!(flags & MS_RDONLY)) {
if (ntfs_volume_check_hiberfile(vol) < 0) if (!(flags & MS_IGNORE_HIBERFILE) &&
ntfs_volume_check_hiberfile(vol, 1) < 0)
goto error_exit; goto error_exit;
if (ntfs_volume_check_logfile(vol) < 0) { if (ntfs_volume_check_logfile(vol) < 0) {
if (!(flags & MS_FORCE)) if (!(flags & MS_RECOVER))
goto error_exit; goto error_exit;
ntfs_log_info("WARNING: Forced mount, reset $LogFile.\n"); ntfs_log_info("The file system wasn't safely "
"closed on Windows. Fixing.\n");
if (ntfs_logfile_reset(vol)) if (ntfs_logfile_reset(vol))
goto error_exit; goto error_exit;
} }
@@ -1154,9 +1134,8 @@ error_exit:
* *
* @flags is an optional second parameter. The same flags are used as for * @flags is an optional second parameter. The same flags are used as for
* the mount system call (man 2 mount). Currently only the following flags * the mount system call (man 2 mount). Currently only the following flags
* are implemented: * is implemented:
* MS_RDONLY - mount volume read-only * MS_RDONLY - mount volume read-only
* MS_NOATIME - do not update access time
* *
* The function opens the device or file @name and verifies that it contains a * The function opens the device or file @name and verifies that it contains a
* valid bootsector. Then, it allocates an ntfs_volume structure and initializes * valid bootsector. Then, it allocates an ntfs_volume structure and initializes
@@ -1463,10 +1442,9 @@ int ntfs_volume_write_flags(ntfs_volume *vol, const u16 flags)
} }
/* Get a pointer to the volume information attribute. */ /* Get a pointer to the volume information attribute. */
ctx = ntfs_attr_get_search_ctx(vol->vol_ni, NULL); ctx = ntfs_attr_get_search_ctx(vol->vol_ni, NULL);
if (!ctx) { if (!ctx)
ntfs_log_perror("Failed to allocate attribute search context");
return -1; return -1;
}
if (ntfs_attr_lookup(AT_VOLUME_INFORMATION, AT_UNNAMED, 0, 0, 0, NULL, if (ntfs_attr_lookup(AT_VOLUME_INFORMATION, AT_UNNAMED, 0, 0, 0, NULL,
0, ctx)) { 0, ctx)) {
ntfs_log_error("Attribute $VOLUME_INFORMATION was not found " ntfs_log_error("Attribute $VOLUME_INFORMATION was not found "
@@ -1497,13 +1475,92 @@ int ntfs_volume_write_flags(ntfs_volume *vol, const u16 flags)
vol->flags = c->flags = flags & VOLUME_FLAGS_MASK; vol->flags = c->flags = flags & VOLUME_FLAGS_MASK;
/* Write them to disk. */ /* Write them to disk. */
ntfs_inode_mark_dirty(vol->vol_ni); ntfs_inode_mark_dirty(vol->vol_ni);
if (ntfs_inode_sync(vol->vol_ni)) { if (ntfs_inode_sync(vol->vol_ni))
ntfs_log_perror("Error writing $Volume");
goto err_out; goto err_out;
}
ret = 0; /* success */ ret = 0; /* success */
err_out: err_out:
ntfs_attr_put_search_ctx(ctx); ntfs_attr_put_search_ctx(ctx);
return ret; return ret;
} }
int ntfs_volume_error(int err)
{
int ret;
switch (err) {
case 0:
ret = NTFS_VOLUME_OK;
break;
case EINVAL:
ret = NTFS_VOLUME_NOT_NTFS;
break;
case EIO:
ret = NTFS_VOLUME_CORRUPT;
break;
case EPERM:
ret = NTFS_VOLUME_HIBERNATED;
break;
case EOPNOTSUPP:
ret = NTFS_VOLUME_UNCLEAN_UNMOUNT;
break;
case EBUSY:
ret = NTFS_VOLUME_LOCKED;
break;
case ENXIO:
ret = NTFS_VOLUME_RAID;
break;
case EACCES:
ret = NTFS_VOLUME_NO_PRIVILEGE;
break;
default:
ret = NTFS_VOLUME_UNKNOWN_REASON;
break;
}
return ret;
}
void ntfs_mount_error(const char *volume, const char *mntpoint, int err)
{
switch (err) {
case NTFS_VOLUME_NOT_NTFS:
ntfs_log_error(invalid_ntfs_msg, volume);
break;
case NTFS_VOLUME_CORRUPT:
ntfs_log_error("%s", corrupt_volume_msg);
break;
case NTFS_VOLUME_HIBERNATED:
ntfs_log_error(hibernated_volume_msg, volume, mntpoint);
break;
case NTFS_VOLUME_UNCLEAN_UNMOUNT:
ntfs_log_error("%s", unclean_journal_msg);
break;
case NTFS_VOLUME_LOCKED:
ntfs_log_error("%s", opened_volume_msg);
break;
case NTFS_VOLUME_RAID:
ntfs_log_error("%s", fakeraid_msg);
break;
case NTFS_VOLUME_NO_PRIVILEGE:
ntfs_log_error(access_denied_msg, volume);
break;
}
}
int ntfs_set_locale(void)
{
#ifndef __HAIKU__
const char *locale;
locale = setlocale(LC_ALL, "");
if (!locale) {
locale = setlocale(LC_ALL, NULL);
ntfs_log_error("Couldn't set local environment, using default "
"'%s'.\n", locale);
return 1;
}
#endif
return 0;
}
@@ -4,7 +4,7 @@
* Copyright (c) 2000-2004 Anton Altaparmakov * Copyright (c) 2000-2004 Anton Altaparmakov
* Copyright (c) 2004-2005 Richard Russon * Copyright (c) 2004-2005 Richard Russon
* Copyright (c) 2005-2006 Yura Pakhuchiy * Copyright (c) 2005-2006 Yura Pakhuchiy
* Copyright (c) 2005-2006 Szabolcs Szakacsits * Copyright (c) 2005-2009 Szabolcs Szakacsits
* *
* This program/include file is free software; you can redistribute it and/or * This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published * modify it under the terms of the GNU General Public License as published
@@ -43,30 +43,21 @@
#endif #endif
/* /*
* Under Cygwin, DJGPP and FreeBSD we do not have MS_RDONLY and MS_NOATIME, * Under Cygwin, DJGPP and FreeBSD we do not have MS_RDONLY,
* so we define them ourselves. * so we define them ourselves.
*/ */
#ifndef MS_RDONLY #ifndef MS_RDONLY
#define MS_RDONLY 1 #define MS_RDONLY 1
#endif #endif
/*
* Solaris defines MS_RDONLY but not MS_NOATIME thus we need to carefully
* define MS_NOATIME.
*/
#ifndef MS_NOATIME
#if (MS_RDONLY != 1)
# define MS_NOATIME 1
#else
# define MS_NOATIME 2
#endif
#endif
#define MS_EXCLUSIVE 0x08000000 #define MS_EXCLUSIVE 0x08000000
#ifndef MS_FORCE #ifndef MS_RECOVER
#define MS_FORCE 0x10000000 #define MS_RECOVER 0x10000000
#endif #endif
#define MS_IGNORE_HIBERFILE 0x20000000
/* Forward declaration */ /* Forward declaration */
typedef struct _ntfs_volume ntfs_volume; typedef struct _ntfs_volume ntfs_volume;
@@ -89,6 +80,22 @@ typedef enum {
extern int ntfs_check_if_mounted(const char *file, unsigned long *mnt_flags); extern int ntfs_check_if_mounted(const char *file, unsigned long *mnt_flags);
typedef enum {
NTFS_VOLUME_OK = 0,
NTFS_VOLUME_SYNTAX_ERROR = 11,
NTFS_VOLUME_NOT_NTFS = 12,
NTFS_VOLUME_CORRUPT = 13,
NTFS_VOLUME_HIBERNATED = 14,
NTFS_VOLUME_UNCLEAN_UNMOUNT = 15,
NTFS_VOLUME_LOCKED = 16,
NTFS_VOLUME_RAID = 17,
NTFS_VOLUME_UNKNOWN_REASON = 18,
NTFS_VOLUME_NO_PRIVILEGE = 19,
NTFS_VOLUME_OUT_OF_MEMORY = 20,
NTFS_VOLUME_FUSE_ERROR = 21,
NTFS_VOLUME_INSECURE = 22
} ntfs_volume_status;
/** /**
* enum ntfs_volume_state_bits - * enum ntfs_volume_state_bits -
* *
@@ -98,7 +105,6 @@ typedef enum {
NV_ReadOnly, /* 1: Volume is read-only. */ NV_ReadOnly, /* 1: Volume is read-only. */
NV_CaseSensitive, /* 1: Volume is mounted case-sensitive. */ NV_CaseSensitive, /* 1: Volume is mounted case-sensitive. */
NV_LogFileEmpty, /* 1: $logFile journal is empty. */ NV_LogFileEmpty, /* 1: $logFile journal is empty. */
NV_NoATime, /* 1: Do not update access time. */
} ntfs_volume_state_bits; } ntfs_volume_state_bits;
#define test_nvol_flag(nv, flag) test_bit(NV_##flag, (nv)->state) #define test_nvol_flag(nv, flag) test_bit(NV_##flag, (nv)->state)
@@ -117,10 +123,6 @@ typedef enum {
#define NVolSetLogFileEmpty(nv) set_nvol_flag(nv, LogFileEmpty) #define NVolSetLogFileEmpty(nv) set_nvol_flag(nv, LogFileEmpty)
#define NVolClearLogFileEmpty(nv) clear_nvol_flag(nv, LogFileEmpty) #define NVolClearLogFileEmpty(nv) clear_nvol_flag(nv, LogFileEmpty)
#define NVolNoATime(nv) test_nvol_flag(nv, NoATime)
#define NVolSetNoATime(nv) set_nvol_flag(nv, NoATime)
#define NVolClearNoATime(nv) clear_nvol_flag(nv, NoATime)
/* /*
* NTFS version 1.1 and 1.2 are used by Windows NT4. * NTFS version 1.1 and 1.2 are used by Windows NT4.
* NTFS version 2.x is used by Windows 2000 Beta * NTFS version 2.x is used by Windows 2000 Beta
@@ -212,12 +214,13 @@ struct _ntfs_volume {
s32 attrdef_len; /* Size of the attribute definition table in s32 attrdef_len; /* Size of the attribute definition table in
bytes. */ bytes. */
/* Temp: for directory handling */ s64 free_clusters; /* Track the number of free clusters which
void *private_data; /* ntfs_dir for . */ greatly improves statfs() performance */
void *private_bmp1; /* ntfs_bmp for $MFT/$BITMAP */ s64 free_mft_records; /* Same for free mft records (see above) */
void *private_bmp2; /* ntfs_bmp for $Bitmap */
}; };
extern const char *ntfs_home;
extern ntfs_volume *ntfs_volume_alloc(void); extern ntfs_volume *ntfs_volume_alloc(void);
extern ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev, extern ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev,
@@ -230,9 +233,15 @@ extern ntfs_volume *ntfs_mount(const char *name, unsigned long flags);
extern int ntfs_umount(ntfs_volume *vol, const BOOL force); extern int ntfs_umount(ntfs_volume *vol, const BOOL force);
extern int ntfs_version_is_supported(ntfs_volume *vol); extern int ntfs_version_is_supported(ntfs_volume *vol);
extern int ntfs_volume_check_hiberfile(ntfs_volume *vol, int verbose);
extern int ntfs_logfile_reset(ntfs_volume *vol); extern int ntfs_logfile_reset(ntfs_volume *vol);
extern int ntfs_volume_write_flags(ntfs_volume *vol, const u16 flags); extern int ntfs_volume_write_flags(ntfs_volume *vol, const u16 flags);
extern int ntfs_volume_error(int err);
extern void ntfs_mount_error(const char *vol, const char *mntpoint, int err);
extern int ntfs_set_locale(void);
#endif /* defined _NTFS_VOLUME_H */ #endif /* defined _NTFS_VOLUME_H */
@@ -52,6 +52,10 @@ typedef struct ntfs_volume ntfs_volume;
#include "types.h" #include "types.h"
#include "device.h" #include "device.h"
#ifndef MAX_PATH
#define MAX_PATH 1024
#endif
#ifndef NTFS_BLOCK_SIZE #ifndef NTFS_BLOCK_SIZE
#define NTFS_BLOCK_SIZE 512 #define NTFS_BLOCK_SIZE 512
#define NTFS_BLOCK_SIZE_BITS 9 #define NTFS_BLOCK_SIZE_BITS 9
@@ -5,54 +5,9 @@
#include <lock.h> #include <lock.h>
#ifdef __HAIKU__
typedef recursive_lock lock; typedef recursive_lock lock;
#define LOCK(l) recursive_lock_lock(&l); #define LOCK(l) recursive_lock_lock(&l);
#define UNLOCK(l) recursive_lock_unlock(&l); #define UNLOCK(l) recursive_lock_unlock(&l);
#else
typedef struct lock lock;
typedef struct mlock mlock;
struct lock {
sem_id s;
long c;
};
struct mlock {
sem_id s;
};
extern int new_lock(lock *l, const char *name);
extern int free_lock(lock *l);
static inline status_t LOCK(lock *l)
{
if (atomic_add(&(l->c), -1) <= 0)
return acquire_sem(l->s);
return B_OK;
}
static inline status_t UNLOCK(lock *l)
{
if (atomic_add(&(l->c), 1) < 0)
return release_sem(l->s);
return B_OK;
}
#define LOCK(l) if (atomic_add(&l.c, -1) <= 0) acquire_sem(l.s);
#define UNLOCK(l) if (atomic_add(&l.c, 1) < 0) release_sem(l.s);
extern int new_mlock(mlock *l, long c, const char *name);
extern int free_mlock(mlock *l);
#define LOCKM(l,cnt) acquire_sem_etc(l.s, cnt, 0, 0)
#define UNLOCKM(l,cnt) release_sem_etc(l.s, cnt, 0)
#endif //__HAIKU__
#endif #endif
@@ -24,8 +24,6 @@
extern "C" { extern "C" {
#endif #endif
#ifdef __HAIKU__
#include <fs_interface.h> #include <fs_interface.h>
#include <kernel/lock.h> #include <kernel/lock.h>
#include <fs_info.h> #include <fs_info.h>
@@ -38,15 +36,6 @@ extern "C" {
#include <NodeMonitor.h> #include <NodeMonitor.h>
#include <util/kernel_cpp.h> #include <util/kernel_cpp.h>
#else
#include "fsproto.h"
#include "lock.h"
#define publish_vnode new_vnode
#endif
#include "config.h" #include "config.h"
#include "attrib.h" #include "attrib.h"
#include "inode.h" #include "inode.h"
@@ -56,7 +45,6 @@ extern "C" {
#include "layout.h" #include "layout.h"
#include "index.h" #include "index.h"
#include "utils.h" #include "utils.h"
#include "version.h"
#include "ntfstime.h" #include "ntfstime.h"
#include "misc.h" #include "misc.h"
#include "utils.h" #include "utils.h"
@@ -111,16 +99,10 @@ typedef struct nspace
{ {
ntfs_volume *ntvol; ntfs_volume *ntvol;
char devicePath[MAX_PATH]; char devicePath[MAX_PATH];
#ifdef __HAIKU__
dev_t id; dev_t id;
#else
nspace_id id;
#endif
int free_cluster_count; int free_cluster_count;
char volumeLabel[MAX_PATH]; char volumeLabel[MAX_PATH];
ulong flags; ulong flags;
int state; int state;
s64 free_clusters; s64 free_clusters;
long free_mft; long free_mft;
@@ -131,10 +113,7 @@ typedef struct nspace
BOOL debug; BOOL debug;
BOOL noatime; BOOL noatime;
BOOL no_detach; BOOL no_detach;
lock vlock; lock vlock;
} nspace; } nspace;
+16 -13
View File
@@ -38,10 +38,6 @@
#include "ntfsdir.h" #include "ntfsdir.h"
//callback function for readdir() //callback function for readdir()
static int _ntfs_dirent_filler(void *_dirent, const ntfschar *name,
const int name_len, const int name_type, const s64 pos,
const MFT_REF mref, const unsigned dt_type);
static int _ntfs_dirent_filler(void *_dirent, const ntfschar *name, static int _ntfs_dirent_filler(void *_dirent, const ntfschar *name,
const int name_len, const int name_type, const s64 pos, const int name_len, const int name_type, const s64 pos,
const MFT_REF mref, const unsigned dt_type) const MFT_REF mref, const unsigned dt_type)
@@ -58,14 +54,18 @@ static int _ntfs_dirent_filler(void *_dirent, const ntfschar *name,
cookie->readed = 0; cookie->readed = 0;
return -1; return -1;
} else { } else {
if (ntfs_ucstombs(name, name_len, &filename, 0) < 0) if (ntfs_ucstombs(name, name_len, &filename, 0) >= 0) {
return -1; if(filename) {
strcpy(cookie->name,filename); strcpy(cookie->name,filename);
cookie->ino=MREF(mref); cookie->ino=MREF(mref);
cookie->readed = 1; cookie->readed = 1;
free(filename);
return 0; return 0;
} }
} }
return -1;
}
}
return 0; return 0;
} }
@@ -114,6 +114,7 @@ fs_opendir( fs_volume *_vol, fs_vnode *_node, void** _cookie )
cookie->pos = 0; cookie->pos = 0;
cookie->ino = 0; cookie->ino = 0;
cookie->readed = 0; cookie->readed = 0;
cookie->last = 0;
cookie->name[0] = 0; cookie->name[0] = 0;
cookie->show_sys_files = ns->show_sys_files; cookie->show_sys_files = ns->show_sys_files;
*_cookie = (void*)cookie; *_cookie = (void*)cookie;
@@ -159,36 +160,37 @@ fs_readdir( fs_volume *_vol, fs_vnode *_node, void *_cookie, struct dirent *buf,
LOCK_VOL(ns); LOCK_VOL(ns);
ERRPRINT("fs_readdir - ENTER\n"); ERRPRINT("fs_readdir - ENTER (sizeof(buf)=%d, bufsize=%d, num=%d\n",sizeof(buf),bufsize,*num);
if (!ns || !node || !cookie || !num || bufsize < sizeof(buf)) { if (!ns || !node || !cookie || !num || bufsize < sizeof(buf)) {
result = EINVAL; result = EINVAL;
goto exit; goto exit;
} }
if(cookie->readed == 1) { if(cookie->readed == 1 || cookie->last == 1) {
result = ENOENT; result = ENOENT;
goto exit; goto exit;
} }
ni = ntfs_inode_open(ns->ntvol, node->vnid); ni = ntfs_inode_open(ns->ntvol, node->vnid);
if(ni==NULL) { if(ni==NULL) {
ERRPRINT("fs_readdir - Dir not opened\n"); ERRPRINT("fs_readdir - dir not opened\n");
result = ENOENT; result = ENOENT;
goto exit; goto exit;
} }
result = ntfs_readdir(ni, &cookie->pos, cookie, (ntfs_filldir_t)_ntfs_dirent_filler); result = ntfs_readdir(ni, &cookie->pos, cookie, (ntfs_filldir_t)_ntfs_dirent_filler);
if(result==0) {
realLen = nameLength>255?255:nameLength; realLen = nameLength>255?255:nameLength;
buf->d_dev = ns->id; buf->d_dev = ns->id;
buf->d_ino = cookie->ino; buf->d_ino = cookie->ino;
memcpy(buf->d_name,cookie->name, realLen+1); memcpy(buf->d_name,cookie->name, realLen+1);
buf->d_reclen = sizeof(buf) + realLen - 1; buf->d_reclen = sizeof(buf) + realLen - 1;
if(result==0)
cookie->last = 1;
result = B_NO_ERROR; result = B_NO_ERROR;
}
else
result = ENOENT;
ERRPRINT("fs_readdir - FILE: [%s]\n",buf->d_name); ERRPRINT("fs_readdir - FILE: [%s]\n",buf->d_name);
@@ -225,6 +227,7 @@ fs_rewinddir( fs_volume *_vol, fs_vnode *vnode, void *_cookie )
cookie->pos = 0; cookie->pos = 0;
cookie->ino = 0; cookie->ino = 0;
cookie->readed = 0; cookie->readed = 0;
cookie->last = 0;
cookie->name[0] = 0; cookie->name[0] = 0;
result = B_NO_ERROR; result = B_NO_ERROR;
} }
@@ -26,6 +26,7 @@ typedef struct dircookie
{ {
u64 pos; u64 pos;
int readed; int readed;
int last;
ino_t ino; ino_t ino;
BOOL show_sys_files; BOOL show_sys_files;
char name[MAX_PATH]; char name[MAX_PATH];
@@ -4,5 +4,5 @@
# /boot/home/config/settings/kernel/drivers/ # /boot/home/config/settings/kernel/drivers/
# #
hide_sys_files true hide_sys_files true
read_only true read_only false
no_atime true no_atime true
@@ -69,12 +69,10 @@
#include "volume.h" #include "volume.h"
#include "debug.h" #include "debug.h"
#include "dir.h" #include "dir.h"
#include "version.h"
#include "logging.h" #include "logging.h"
#include "misc.h" #include "misc.h"
const char *ntfs_bugs = "Developers' email address: "NTFS_DEV_LIST"\n"; const char *ntfs_bugs = "Developers' email address: "NTFS_DEV_LIST"\n";
const char *ntfs_home = "Linux NTFS homepage: http://www.linux-ntfs.org\n";
const char *ntfs_gpl = "This program is free software, released under the GNU " const char *ntfs_gpl = "This program is free software, released under the GNU "
"General Public License\nand you are welcome to redistribute it under " "General Public License\nand you are welcome to redistribute it under "
"certain conditions. It comes with\nABSOLUTELY NO WARRANTY; for " "certain conditions. It comes with\nABSOLUTELY NO WARRANTY; for "
@@ -82,23 +80,6 @@ const char *ntfs_gpl = "This program is free software, released under the GNU "
"\"COPYING\" distributed with this program, or online at:\n" "\"COPYING\" distributed with this program, or online at:\n"
"http://www.gnu.org/copyleft/gpl.html\n"; "http://www.gnu.org/copyleft/gpl.html\n";
/**
* utils_set_locale
*/
/*
int utils_set_locale(void)
{
const char *locale;
locale = setlocale(LC_ALL, "");
if (!locale) {
locale = setlocale(LC_ALL, NULL);
ntfs_log_error("Couldn't set local environment, using default '%s'.\n", locale);
return 1;
} else {
return 0;
}
}*/
/** /**
* utils_valid_device - Perform some safety checks on the device, before we start * utils_valid_device - Perform some safety checks on the device, before we start
@@ -35,7 +35,6 @@
#include "inode.h" #include "inode.h"
#include "runlist.h" #include "runlist.h"
#include "utils.h" #include "utils.h"
#include "version.h"
#include "ntfs.h" #include "ntfs.h"
#include "volume_util.h" #include "volume_util.h"
@@ -166,7 +165,7 @@ int ntfs_change_label(ntfs_volume *vol, char *label)
goto err_out; goto err_out;
} }
} }
label_len = ntfs_mbstoucs(label, &new_label, 0); label_len = ntfs_mbstoucs(label, &new_label);
if (label_len == -1) { if (label_len == -1) {
ntfs_log_perror("Unable to convert label string to Unicode"); ntfs_log_perror("Unable to convert label string to Unicode");
goto err_out; goto err_out;