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:
@@ -2,8 +2,6 @@ SubDir HAIKU_TOP src add-ons kernel file_systems ntfs ;
|
||||
|
||||
SubDirHdrs [ FDirName $(SUBDIR) libntfs ] ;
|
||||
|
||||
SetSubDirSupportedPlatformsBeOSCompatible ;
|
||||
|
||||
SubDirCcFlags -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
|
||||
fs_open_attrib_dir(fs_volume *_vol, fs_vnode *_node, void **_cookie)
|
||||
{
|
||||
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;
|
||||
|
||||
@@ -88,17 +81,10 @@ exit:
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef __HAIKU__
|
||||
status_t
|
||||
fs_close_attrib_dir(fs_volume *_vol, fs_vnode *_node, void *_cookie)
|
||||
{
|
||||
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");
|
||||
|
||||
@@ -113,17 +99,10 @@ fs_close_attrib_dir(void *_ns, void *_node, void *_cookie)
|
||||
return B_NO_ERROR;
|
||||
}
|
||||
|
||||
#ifdef __HAIKU__
|
||||
status_t
|
||||
fs_free_attrib_dir_cookie(fs_volume *_vol, fs_vnode *_node, void *_cookie)
|
||||
{
|
||||
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;
|
||||
|
||||
@@ -149,17 +128,11 @@ exit:
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef __HAIKU__
|
||||
status_t
|
||||
fs_rewind_attrib_dir(fs_volume *_vol, fs_vnode *_node, void *_cookie)
|
||||
{
|
||||
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;
|
||||
|
||||
LOCK_VOL(ns);
|
||||
@@ -184,19 +157,12 @@ exit:
|
||||
}
|
||||
|
||||
|
||||
#ifdef __HAIKU__
|
||||
status_t
|
||||
fs_read_attrib_dir(fs_volume *_vol, fs_vnode *_node, void *_cookie, struct dirent *entry, size_t bufsize, uint32 *num)
|
||||
{
|
||||
nspace *ns = (nspace *)_vol->private_volume;
|
||||
vnode *node = (vnode *)_node->private_node;
|
||||
#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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#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
|
||||
fs_open_attrib(fs_volume *_vol, fs_vnode *_node, const char *name, int openMode, void **_cookie)
|
||||
{
|
||||
@@ -276,25 +220,22 @@ exit:
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __HAIKU__
|
||||
|
||||
status_t
|
||||
fs_close_attrib(fs_volume *_vol, fs_vnode *_node, void *cookie)
|
||||
{
|
||||
return B_NO_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __HAIKU__
|
||||
|
||||
status_t
|
||||
fs_free_attrib_cookie(fs_volume *_vol, fs_vnode *_node, void *cookie)
|
||||
{
|
||||
return B_NO_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __HAIKU__
|
||||
|
||||
status_t
|
||||
fs_read_attrib_stat(fs_volume *_vol, fs_vnode *_node, void *_cookie,struct stat *stat)
|
||||
{
|
||||
@@ -327,33 +268,24 @@ exit:
|
||||
|
||||
return B_NO_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __HAIKU__
|
||||
|
||||
status_t
|
||||
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;
|
||||
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;
|
||||
|
||||
LOCK_VOL(ns);
|
||||
|
||||
ERRPRINT("fs_read_attr - ENTER\n");
|
||||
|
||||
#ifdef __HAIKU_
|
||||
if (_cookie != &kBeOSTypeCookie) {
|
||||
result = ENOENT;
|
||||
goto exit;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (node->mime == NULL) {
|
||||
result = ENOENT;
|
||||
@@ -379,17 +311,11 @@ exit:
|
||||
}
|
||||
|
||||
|
||||
#ifdef __HAIKU__
|
||||
status_t
|
||||
fs_write_attrib(fs_volume *_vol, fs_vnode *_node, void *_cookie,off_t pos, const void *buffer, size_t *_length)
|
||||
{
|
||||
nspace *ns = (nspace *)_vol->private_volume;
|
||||
#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;
|
||||
|
||||
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");
|
||||
|
||||
*_length = 0;
|
||||
#ifdef __HAIKU_
|
||||
|
||||
if (_cookie != &kBeOSTypeCookie) {
|
||||
result = ENOSYS;
|
||||
}
|
||||
#endif
|
||||
|
||||
ERRPRINT("fs_write_attrib - EXIT, result is %s\n", strerror(result));
|
||||
|
||||
|
||||
@@ -123,7 +123,7 @@ fs_identify_partition(int fd, partition_data *partition, void **_cookie)
|
||||
if(!ioctl(fd,B_GET_PATH_FOR_DEVICE,devpath))
|
||||
return -1;
|
||||
//try mount
|
||||
ntVolume = utils_mount_volume(devpath,MS_RDONLY|MS_NOATIME,true);
|
||||
ntVolume = utils_mount_volume(devpath,MS_RDONLY,true);
|
||||
if(!ntVolume)
|
||||
return -1;
|
||||
|
||||
@@ -208,8 +208,8 @@ fs_mount(fs_volume *_vol, const char *device, ulong flags, const char *args, ino
|
||||
mnt_flags |= MS_RDONLY;
|
||||
ns->flags |= B_MOUNT_READ_ONLY;
|
||||
}
|
||||
if (ns->noatime)
|
||||
mnt_flags |= MS_NOATIME;
|
||||
// if (ns->noatime)
|
||||
// mnt_flags |= MS_NOATIME;
|
||||
|
||||
ns->ntvol=utils_mount_volume(device,mnt_flags,true);
|
||||
if(ns->ntvol!=NULL)
|
||||
@@ -367,7 +367,7 @@ fs_walk(fs_volume *_vol, fs_vnode *_dir, const char *file, ino_t *vnid)
|
||||
result = ENOENT;
|
||||
} else {
|
||||
unicode = ntfs_calloc(MAX_PATH);
|
||||
len = ntfs_mbstoucs(file, &unicode, MAX_PATH);
|
||||
len = ntfs_mbstoucs(file, &unicode);
|
||||
if (len < 0) {
|
||||
result = EILSEQ;
|
||||
goto exit;
|
||||
@@ -882,7 +882,7 @@ fs_create(fs_volume *_vol, fs_vnode *_dir, const char *name, int omode, int perm
|
||||
goto exit;
|
||||
}
|
||||
|
||||
uname_len = ntfs_mbstoucs(name, &uname, 0);
|
||||
uname_len = ntfs_mbstoucs(name, &uname);
|
||||
if (uname_len < 0) {
|
||||
result = EINVAL;
|
||||
goto exit;
|
||||
@@ -1285,13 +1285,13 @@ fs_create_symlink(fs_volume *_vol, fs_vnode *_dir, const char *name, const char
|
||||
goto exit;
|
||||
}
|
||||
|
||||
uname_len = ntfs_mbstoucs(name, &uname, 0);
|
||||
uname_len = ntfs_mbstoucs(name, &uname);
|
||||
if (uname_len < 0) {
|
||||
result = EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
utarget_len = ntfs_mbstoucs(target, &utarget, 0);
|
||||
utarget_len = ntfs_mbstoucs(target, &utarget);
|
||||
if (utarget_len < 0) {
|
||||
result = EINVAL;
|
||||
goto exit;
|
||||
@@ -1380,7 +1380,7 @@ fs_mkdir(fs_volume *_vol, fs_vnode *_dir, const char *name, int perms)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
uname_len = ntfs_mbstoucs(name, &uname, 0);
|
||||
uname_len = ntfs_mbstoucs(name, &uname);
|
||||
if (uname_len < 0) {
|
||||
result = EINVAL;
|
||||
goto exit;
|
||||
@@ -1475,13 +1475,13 @@ fs_rename(fs_volume *_vol, fs_vnode *_odir, const char *oldname, fs_vnode *_ndir
|
||||
goto exit;
|
||||
|
||||
//convert names from utf8 to unicode string
|
||||
unewname_len = ntfs_mbstoucs(newname, &unewname, 0);
|
||||
unewname_len = ntfs_mbstoucs(newname, &unewname);
|
||||
if (unewname_len < 0) {
|
||||
result = EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
uoldname_len = ntfs_mbstoucs(oldname, &uoldname, 0);
|
||||
uoldname_len = ntfs_mbstoucs(oldname, &uoldname);
|
||||
if (uoldname_len < 0) {
|
||||
result = EINVAL;
|
||||
goto exit;
|
||||
@@ -1544,13 +1544,14 @@ fs_rename(fs_volume *_vol, fs_vnode *_odir, const char *oldname, fs_vnode *_ndir
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ntfs_delete(oi, odi, uoldname, uoldname_len);
|
||||
|
||||
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_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 );
|
||||
|
||||
} else { //renaming
|
||||
@@ -1590,10 +1591,12 @@ fs_rename(fs_volume *_vol, fs_vnode *_odir, const char *oldname, fs_vnode *_ndir
|
||||
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_attribute_changed(ns->id, onode->vnid, "BEOS:TYPE", B_ATTR_CHANGED);
|
||||
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;
|
||||
status_t result = B_NO_ERROR;
|
||||
|
||||
uname_len = ntfs_mbstoucs(name, &uname, 0);
|
||||
uname_len = ntfs_mbstoucs(name, &uname);
|
||||
if (uname_len < 0) {
|
||||
result = EINVAL;
|
||||
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))
|
||||
result = errno;
|
||||
else
|
||||
ni = NULL;
|
||||
|
||||
ni = bi = NULL;
|
||||
|
||||
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);
|
||||
|
||||
if( ns == NULL || dir == NULL || name ==NULL) {
|
||||
if( ns == NULL || dir == NULL || name == NULL) {
|
||||
result = EINVAL;
|
||||
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 ;
|
||||
|
||||
SetSubDirSupportedPlatformsBeOSCompatible ;
|
||||
|
||||
SubDirCcFlags -Wall -Wno-multichar -DHAVE_CONFIG_H=1 ;
|
||||
|
||||
StaticLibrary libntfs.a :
|
||||
@@ -27,7 +25,6 @@ StaticLibrary libntfs.a :
|
||||
runlist.c
|
||||
security.c
|
||||
unistr.c
|
||||
version.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) 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
|
||||
* 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,
|
||||
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,
|
||||
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 {
|
||||
NA_Initialized, /* 1: structure is initialized. */
|
||||
@@ -204,30 +207,15 @@ typedef enum {
|
||||
#define NAttrSetNonResident(na) set_nattr_flag(na, NonResident)
|
||||
#define NAttrClearNonResident(na) clear_nattr_flag(na, NonResident)
|
||||
|
||||
#define GenNAttrIno(func_name,flag) \
|
||||
static inline int NAttr##func_name(ntfs_attr *na) \
|
||||
{ \
|
||||
if (na->type == AT_DATA && na->name == AT_UNNAMED) \
|
||||
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; \
|
||||
}
|
||||
#define GenNAttrIno(func_name, flag) \
|
||||
extern int NAttr##func_name(ntfs_attr *na); \
|
||||
extern void NAttrSet##func_name(ntfs_attr *na); \
|
||||
extern void NAttrClear##func_name(ntfs_attr *na);
|
||||
|
||||
GenNAttrIno(Compressed, COMPRESSED)
|
||||
GenNAttrIno(Encrypted, ENCRYPTED)
|
||||
GenNAttrIno(Sparse, SPARSE_FILE)
|
||||
GenNAttrIno(Compressed, FILE_ATTR_COMPRESSED)
|
||||
GenNAttrIno(Encrypted, FILE_ATTR_ENCRYPTED)
|
||||
GenNAttrIno(Sparse, FILE_ATTR_SPARSE_FILE)
|
||||
#undef GenNAttrIno
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
// FIXME / TODO: Above here the file is cleaned up. (AIA)
|
||||
/**
|
||||
* get_attribute_value_length - return the length of the value of an attribute
|
||||
* @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);
|
||||
extern int ntfs_attr_remove(ntfs_inode *ni, const ATTR_TYPES type,
|
||||
ntfschar *name, u32 name_len);
|
||||
extern s64 ntfs_attr_get_free_bits(ntfs_attr *na);
|
||||
|
||||
#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);
|
||||
if (!ctx) {
|
||||
err = errno;
|
||||
ntfs_log_trace("Failed to obtain attribute search context.\n");
|
||||
goto err_out;
|
||||
}
|
||||
if (!ntfs_attr_lookup(attr->type, (attr->name_length) ? (ntfschar*)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (c) 2002-2006 Anton Altaparmakov
|
||||
* 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
|
||||
* 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;
|
||||
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) {
|
||||
errno = EINVAL;
|
||||
ntfs_log_perror("%s: Invalid argument (%p, %lld, %lld)",
|
||||
__FUNCTION__, na, (long long)start_bit, (long long)count);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -147,9 +149,9 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
|
||||
/* read it in... */
|
||||
br = ntfs_attr_pread(na, start_bit >> 3, 1, buf);
|
||||
if (br != 1) {
|
||||
free(buf);
|
||||
if (br >= 0)
|
||||
errno = EIO;
|
||||
return -1;
|
||||
goto free_err_out;
|
||||
}
|
||||
/* and set or clear the appropriate bits in it. */
|
||||
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;
|
||||
if (!lastbyte_pos) {
|
||||
// FIXME: Eeek! BUG!
|
||||
ntfs_log_trace("Eeek! lastbyte is zero. Leaving "
|
||||
ntfs_log_error("Lastbyte is zero. Leaving "
|
||||
"inconsistent metadata.\n");
|
||||
err = EIO;
|
||||
errno = EIO;
|
||||
goto free_err_out;
|
||||
}
|
||||
/* 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);
|
||||
if (br != 1) {
|
||||
// FIXME: Eeek! We need rollback! (AIA)
|
||||
ntfs_log_trace("Eeek! Read of last byte "
|
||||
"failed. Leaving "
|
||||
"inconsistent metadata.\n");
|
||||
err = EIO;
|
||||
if (br >= 0)
|
||||
errno = EIO;
|
||||
ntfs_log_perror("Reading of last byte "
|
||||
"failed (%lld). Leaving inconsistent "
|
||||
"metadata", (long long)br);
|
||||
goto free_err_out;
|
||||
}
|
||||
/* 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);
|
||||
if (br != bufsize) {
|
||||
// FIXME: Eeek! We need rollback! (AIA)
|
||||
ntfs_log_trace("Eeek! Failed to write buffer to bitmap. "
|
||||
"Leaving inconsistent metadata.\n");
|
||||
err = EIO;
|
||||
if (br >= 0)
|
||||
errno = 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;
|
||||
}
|
||||
|
||||
@@ -234,22 +239,19 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
|
||||
|
||||
if (lastbyte && count != 0) {
|
||||
// FIXME: Eeek! BUG!
|
||||
ntfs_log_trace("Eeek! Last buffer but count is not zero (= "
|
||||
"%lli). Leaving inconsistent metadata.\n",
|
||||
ntfs_log_error("Last buffer but count is not zero "
|
||||
"(%lld). Leaving inconsistent metadata.\n",
|
||||
(long long)count);
|
||||
err = EIO;
|
||||
errno = EIO;
|
||||
goto free_err_out;
|
||||
}
|
||||
} while (count > 0);
|
||||
|
||||
/* Done! */
|
||||
free(buf);
|
||||
return 0;
|
||||
ret = 0;
|
||||
|
||||
free_err_out:
|
||||
free(buf);
|
||||
errno = err;
|
||||
return -1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -265,7 +267,13 @@ free_err_out:
|
||||
*/
|
||||
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)
|
||||
{
|
||||
ntfs_log_trace("Dealloc from bit 0x%llx, count 0x%llx.\n",
|
||||
(long long)start_bit, (long long)count);
|
||||
int ret;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* bootsect.c - Boot sector handling code. Originated from the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2000-2006 Anton Altaparmakov
|
||||
* Copyright (c) 2003-2006 Szabolcs Szakacsits
|
||||
* Copyright (c) 2003-2008 Szabolcs Szakacsits
|
||||
* Copyright (c) 2005 Yura Pakhuchiy
|
||||
*
|
||||
* This program/include file is free software; you can redistribute it and/or
|
||||
@@ -151,6 +151,13 @@ not_ntfs:
|
||||
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
|
||||
* @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);
|
||||
ntfs_log_debug("NumberOfSectors = %lld\n", sectors);
|
||||
ntfs_log_debug("NumberOfSectors = %lld\n", (long long)sectors);
|
||||
if (!sectors) {
|
||||
ntfs_log_error("Volume size is set to zero.\n");
|
||||
return -1;
|
||||
@@ -198,9 +205,7 @@ int ntfs_boot_sector_parse(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs)
|
||||
SEEK_SET) == -1) {
|
||||
ntfs_log_perror("Failed to read last sector (%lld)",
|
||||
(long long)sectors);
|
||||
ntfs_log_error("Perhaps the volume is a RAID/LDM but it wasn't "
|
||||
"setup yet, or the\nwrong device was used, "
|
||||
"or the partition table is incorrect.\n" );
|
||||
ntfs_log_error("%s", last_sector_error);
|
||||
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->mftmirr_lcn = sle64_to_cpu(bs->mftmirr_lcn);
|
||||
ntfs_log_debug("MFT LCN = 0x%llx\n", vol->mft_lcn);
|
||||
ntfs_log_debug("MFTMirr LCN = 0x%llx\n", vol->mftmirr_lcn);
|
||||
ntfs_log_debug("MFT LCN = %lld\n", (long long)vol->mft_lcn);
|
||||
ntfs_log_debug("MFTMirr LCN = %lld\n", (long long)vol->mftmirr_lcn);
|
||||
if (vol->mft_lcn > vol->nr_clusters ||
|
||||
vol->mftmirr_lcn > vol->nr_clusters) {
|
||||
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
|
||||
*/
|
||||
|
||||
#if defined(WINDOWS) || defined(__BEOS__) || defined (__HAIKU__)
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "compat.h"
|
||||
|
||||
/* TODO: Add check for FFS in the configure script... (AIA) */
|
||||
|
||||
#ifndef HAVE_FFS
|
||||
/**
|
||||
* ffs - Find the first set bit in an int
|
||||
@@ -69,5 +65,186 @@ int ffs(int x)
|
||||
}
|
||||
#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-2004 Anton Altaparmakov
|
||||
* Copyright (c) 2008-2009 Szabolcs Szakacsits
|
||||
*
|
||||
* 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
|
||||
@@ -26,14 +27,28 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
#ifdef HAVE_SYS_PARAM_H
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
|
||||
#ifdef WINDOWS
|
||||
#ifndef PATH_MAX
|
||||
#define PATH_MAX 4096
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_FFS
|
||||
#define HAVE_FFS
|
||||
extern int ffs(int i);
|
||||
#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_STDARG_H
|
||||
|
||||
@@ -44,9 +59,11 @@ extern int ffs(int i);
|
||||
|
||||
#else /* !defined WINDOWS */
|
||||
|
||||
#ifndef __HAIKU__
|
||||
#ifndef O_BINARY
|
||||
#define O_BINARY 0 /* unix is binary by default */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#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);
|
||||
do_next_sb:
|
||||
ntfs_log_debug("Beginning sub-block at offset = 0x%x in the cb.\n",
|
||||
cb - cb_start);
|
||||
ntfs_log_debug("Beginning sub-block at offset = %d in the cb.\n",
|
||||
(int)(cb - cb_start));
|
||||
/*
|
||||
* 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
|
||||
|
||||
@@ -63,9 +63,15 @@ void ntfs_debug_runlist_dump(const runlist_element *rl)
|
||||
|
||||
if (idx > -LCN_EINVAL - 1)
|
||||
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
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -178,7 +178,7 @@ s64 ntfs_pread(struct ntfs_device *dev, const s64 pos, s64 count, void *b)
|
||||
s64 br, total;
|
||||
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) {
|
||||
errno = EINVAL;
|
||||
@@ -229,7 +229,8 @@ s64 ntfs_pwrite(struct ntfs_device *dev, const s64 pos, s64 count,
|
||||
s64 written, total, ret = -1;
|
||||
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) {
|
||||
errno = EINVAL;
|
||||
goto out;
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
*
|
||||
* Copyright (c) 2002-2005 Anton Altaparmakov
|
||||
* Copyright (c) 2004-2005 Richard Russon
|
||||
* Copyright (c) 2004-2006 Szabolcs Szakacsits
|
||||
* Copyright (c) 2005-2006 Yura Pakhuchiy
|
||||
* Copyright (c) 2004-2008 Szabolcs Szakacsits
|
||||
* Copyright (c) 2005-2007 Yura Pakhuchiy
|
||||
*
|
||||
* 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
|
||||
@@ -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,
|
||||
0, ctx)) {
|
||||
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;
|
||||
}
|
||||
/* 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);
|
||||
if (index_block_size < NTFS_BLOCK_SIZE ||
|
||||
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);
|
||||
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 +
|
||||
sizeof(INDEX_ENTRY_HEADER) > index_end ||
|
||||
(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;
|
||||
}
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
if (ie->ie_flags & INDEX_ENTRY_END)
|
||||
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
|
||||
* 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. */
|
||||
ia_na = ntfs_attr_open(dir_ni, AT_INDEX_ALLOCATION, NTFS_INDEX_I30, 4);
|
||||
if (!ia_na) {
|
||||
ntfs_log_perror("Failed to open index allocation attribute. Directory "
|
||||
"inode 0x%llx is corrupt or driver bug",
|
||||
ntfs_log_perror("Failed to open index allocation (inode %lld)",
|
||||
(unsigned long long)dir_ni->mft_no);
|
||||
goto put_err_out;
|
||||
}
|
||||
@@ -265,7 +273,7 @@ descend_into_child_node:
|
||||
}
|
||||
|
||||
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",
|
||||
(long long)sle64_to_cpu(ia->index_block_vcn),
|
||||
(long long)vcn);
|
||||
@@ -273,7 +281,7 @@ descend_into_child_node:
|
||||
goto close_err_out;
|
||||
}
|
||||
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 "
|
||||
"specified size (%u).\n", (long long)vcn,
|
||||
(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);
|
||||
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",
|
||||
(long long)vcn, (unsigned long long)dir_ni->mft_no);
|
||||
errno = EIO;
|
||||
@@ -305,8 +313,8 @@ descend_into_child_node:
|
||||
sizeof(INDEX_ENTRY_HEADER) > index_end ||
|
||||
(u8*)ie + le16_to_cpu(ie->key_length) >
|
||||
index_end) {
|
||||
ntfs_log_debug("Index entry out of bounds in directory "
|
||||
"inode 0x%llx.\n",
|
||||
ntfs_log_error("Index entry out of bounds in directory "
|
||||
"inode %lld.\n",
|
||||
(unsigned long long)dir_ni->mft_no);
|
||||
errno = EIO;
|
||||
goto close_err_out;
|
||||
@@ -317,6 +325,13 @@ descend_into_child_node:
|
||||
*/
|
||||
if (ie->ie_flags & INDEX_ENTRY_END)
|
||||
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
|
||||
* 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 ((ia->index.ih_flags & NODE_MASK) == LEAF_NODE) {
|
||||
ntfs_log_debug("Index entry with child node found in a leaf "
|
||||
"node in directory inode 0x%llx.\n",
|
||||
ntfs_log_error("Index entry with child node found in a leaf "
|
||||
"node in directory inode %lld.\n",
|
||||
(unsigned long long)dir_ni->mft_no);
|
||||
errno = EIO;
|
||||
goto close_err_out;
|
||||
@@ -371,7 +386,7 @@ descend_into_child_node:
|
||||
vcn = sle64_to_cpup((u8*)ie + le16_to_cpu(ie->length) - 8);
|
||||
if (vcn >= 0)
|
||||
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);
|
||||
errno = EIO;
|
||||
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);
|
||||
if (!unicode || !ascii) {
|
||||
ntfs_log_debug("Out of memory.\n");
|
||||
if (!ascii) {
|
||||
ntfs_log_error("Out of memory.\n");
|
||||
err = ENOMEM;
|
||||
goto close;
|
||||
}
|
||||
@@ -466,9 +480,10 @@ ntfs_inode *ntfs_pathname_to_inode(ntfs_volume *vol, ntfs_inode *parent,
|
||||
q++;
|
||||
}
|
||||
|
||||
len = ntfs_mbstoucs(p, &unicode, MAX_PATH);
|
||||
len = ntfs_mbstoucs(p, &unicode);
|
||||
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;
|
||||
goto close;
|
||||
} 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;
|
||||
}
|
||||
|
||||
free(unicode);
|
||||
unicode = NULL;
|
||||
|
||||
p = q;
|
||||
while (p && *p && *p == PATH_SEP)
|
||||
p++;
|
||||
@@ -578,6 +596,8 @@ static int ntfs_filldir(ntfs_inode *dir_ni, s64 *pos, u8 ivcn_bits,
|
||||
return 0;
|
||||
if (ie->key.file_name.file_attributes & FILE_ATTR_I30_INDEX_PRESENT)
|
||||
dt_type = NTFS_DT_DIR;
|
||||
else if (fn->file_attributes & FILE_ATTR_SYSTEM)
|
||||
dt_type = NTFS_DT_UNKNOWN;
|
||||
else
|
||||
dt_type = NTFS_DT_REG;
|
||||
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)
|
||||
return ERR_MREF(-1);
|
||||
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 "
|
||||
"inode.\n", (unsigned long long)ni->mft_no);
|
||||
ntfs_log_error("No file name found in inode %lld\n",
|
||||
(unsigned long long)ni->mft_no);
|
||||
goto err_out;
|
||||
}
|
||||
if (ctx->attr->non_resident) {
|
||||
ntfs_log_debug("File name attribute must be resident. Corrupt inode "
|
||||
"0x%llx.\n", (unsigned long long)ni->mft_no);
|
||||
ntfs_log_error("File name attribute must be resident (inode "
|
||||
"%lld)\n", (unsigned long long)ni->mft_no);
|
||||
goto io_err_out;
|
||||
}
|
||||
fn = (FILE_NAME_ATTR*)((u8*)ctx->attr +
|
||||
le16_to_cpu(ctx->attr->value_offset));
|
||||
if ((u8*)fn + le32_to_cpu(ctx->attr->value_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);
|
||||
goto io_err_out;
|
||||
}
|
||||
@@ -695,7 +715,7 @@ int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos,
|
||||
|
||||
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);
|
||||
|
||||
/* Open the index allocation attribute. */
|
||||
@@ -703,7 +723,7 @@ int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos,
|
||||
if (!ia_na) {
|
||||
if (errno != ENOENT) {
|
||||
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);
|
||||
return -1;
|
||||
}
|
||||
@@ -724,7 +744,7 @@ int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos,
|
||||
le16_to_cpu(dir_ni->mrec->sequence_number)),
|
||||
NTFS_DT_DIR);
|
||||
if (rc)
|
||||
goto done;
|
||||
goto err_out;
|
||||
++*pos;
|
||||
}
|
||||
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,
|
||||
parent_mref, NTFS_DT_DIR);
|
||||
if (rc)
|
||||
goto done;
|
||||
goto err_out;
|
||||
++*pos;
|
||||
}
|
||||
|
||||
@@ -752,8 +772,8 @@ int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos,
|
||||
/* Find the index root attribute in the mft record. */
|
||||
if (ntfs_attr_lookup(AT_INDEX_ROOT, NTFS_INDEX_I30, 4, CASE_SENSITIVE, 0, NULL,
|
||||
0, ctx)) {
|
||||
ntfs_log_debug("Index root attribute missing in directory inode "
|
||||
"0x%llx.\n", (unsigned long long)dir_ni->mft_no);
|
||||
ntfs_log_perror("Index root attribute missing in directory inode "
|
||||
"%lld", (unsigned long long)dir_ni->mft_no);
|
||||
goto dir_err_out;
|
||||
}
|
||||
/* 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);
|
||||
if (index_block_size < NTFS_BLOCK_SIZE ||
|
||||
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);
|
||||
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).
|
||||
*/
|
||||
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. */
|
||||
if ((u8*)ie < (u8*)ctx->mrec || (u8*)ie +
|
||||
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. */
|
||||
if (ie->ie_flags & INDEX_ENTRY_END)
|
||||
break;
|
||||
|
||||
if (!le16_to_cpu(ie->length))
|
||||
goto dir_err_out;
|
||||
|
||||
/* Skip index root entry if continuing previous readdir. */
|
||||
if (ir_pos > (u8*)ie - (u8*)ir)
|
||||
continue;
|
||||
@@ -816,7 +840,7 @@ int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos,
|
||||
if (rc) {
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
ctx = NULL;
|
||||
goto done;
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
@@ -850,7 +874,7 @@ skip_index_root:
|
||||
|
||||
bmp_pos = ia_pos >> index_block_size_bits;
|
||||
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");
|
||||
goto dir_err_out;
|
||||
}
|
||||
@@ -881,6 +905,7 @@ find_next_index_buffer:
|
||||
if (bmp_buf_pos >> 3 < bmp_buf_size)
|
||||
continue;
|
||||
/* Read next chunk from the index bitmap. */
|
||||
bmp_buf_pos = 0;
|
||||
if ((bmp_pos >> 3) + bmp_buf_size > bmp_na->data_size)
|
||||
bmp_buf_size = bmp_na->data_size - (bmp_pos >> 3);
|
||||
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);
|
||||
if (sle64_to_cpu(ia->index_block_vcn) != ia_start >>
|
||||
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",
|
||||
(long long)sle64_to_cpu(ia->index_block_vcn),
|
||||
(long long)ia_start >> index_vcn_size_bits,
|
||||
@@ -915,7 +940,7 @@ find_next_index_buffer:
|
||||
goto dir_err_out;
|
||||
}
|
||||
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 "
|
||||
"specified size (%u).\n", (long long)ia_start >>
|
||||
index_vcn_size_bits,
|
||||
@@ -926,8 +951,8 @@ find_next_index_buffer:
|
||||
}
|
||||
index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length);
|
||||
if (index_end > (u8*)ia + index_block_size) {
|
||||
ntfs_log_debug("Size of index buffer (VCN 0x%llx) of directory inode "
|
||||
"0x%llx exceeds maximum size.\n",
|
||||
ntfs_log_error("Size of index buffer (VCN 0x%llx) of directory inode "
|
||||
"%lld exceeds maximum size.\n",
|
||||
(long long)ia_start >> index_vcn_size_bits,
|
||||
(unsigned long long)dir_ni->mft_no);
|
||||
goto dir_err_out;
|
||||
@@ -948,13 +973,17 @@ find_next_index_buffer:
|
||||
sizeof(INDEX_ENTRY_HEADER) > index_end ||
|
||||
(u8*)ie + le16_to_cpu(ie->key_length) >
|
||||
index_end) {
|
||||
ntfs_log_debug("Index entry out of bounds in directory inode "
|
||||
"0x%llx.\n", (unsigned long long)dir_ni->mft_no);
|
||||
ntfs_log_error("Index entry out of bounds in directory inode "
|
||||
"%lld.\n", (unsigned long long)dir_ni->mft_no);
|
||||
goto dir_err_out;
|
||||
}
|
||||
/* The last entry cannot contain a name. */
|
||||
if (ie->ie_flags & INDEX_ENTRY_END)
|
||||
break;
|
||||
|
||||
if (!le16_to_cpu(ie->length))
|
||||
goto dir_err_out;
|
||||
|
||||
/* Skip index entry if continuing previous readdir. */
|
||||
if (ia_pos - ia_start > (u8*)ie - (u8*)ia)
|
||||
continue;
|
||||
@@ -965,7 +994,7 @@ find_next_index_buffer:
|
||||
rc = ntfs_filldir(dir_ni, pos, index_vcn_size_bits,
|
||||
INDEX_TYPE_ALLOCATION, ia, ie, dirent, filldir);
|
||||
if (rc)
|
||||
goto done;
|
||||
goto err_out;
|
||||
}
|
||||
goto find_next_index_buffer;
|
||||
EOD:
|
||||
@@ -978,13 +1007,7 @@ done:
|
||||
ntfs_attr_close(bmp_na);
|
||||
if (ia_na)
|
||||
ntfs_attr_close(ia_na);
|
||||
#ifdef DEBUG
|
||||
if (!rc)
|
||||
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;
|
||||
dir_err_out:
|
||||
errno = EIO;
|
||||
@@ -1037,7 +1060,7 @@ err_out:
|
||||
*/
|
||||
static ntfs_inode *__ntfs_create(ntfs_inode *dir_ni,
|
||||
ntfschar *name, u8 name_len, dev_t type, dev_t dev,
|
||||
ntfschar *target, u8 target_len)
|
||||
ntfschar *target, int target_len)
|
||||
{
|
||||
ntfs_inode *ni;
|
||||
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_mft_change_time = utc2ntfs(ni->last_mft_change_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));
|
||||
/* Add FILE_NAME attribute to inode. */
|
||||
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,
|
||||
ntfschar *target, u8 target_len)
|
||||
ntfschar *target, int 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 __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? */
|
||||
if ((na->data_size != sizeof(INDEX_ROOT) + sizeof(INDEX_ENTRY_HEADER))){
|
||||
/* Both ENOTEMPTY and EEXIST are ok. We use the more common. */
|
||||
errno = EEXIST;
|
||||
errno = ENOTEMPTY;
|
||||
ntfs_log_debug("Directory is not empty\n");
|
||||
ret = -1;
|
||||
}
|
||||
@@ -1327,7 +1353,7 @@ static int ntfs_check_unlinkable_dir(ntfs_inode *ni, FILE_NAME_ATTR *fn)
|
||||
int ret;
|
||||
|
||||
ret = ntfs_check_empty_dir(ni);
|
||||
if (!ret || errno != EEXIST)
|
||||
if (!ret || errno != ENOTEMPTY)
|
||||
return ret;
|
||||
/*
|
||||
* 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) ||
|
||||
(link_count == 2 && fn->file_name_type == FILE_NAME_DOS)) {
|
||||
errno = EEXIST;
|
||||
errno = ENOTEMPTY;
|
||||
ntfs_log_debug("Non-empty directory without hard links\n");
|
||||
goto no_hardlink;
|
||||
}
|
||||
@@ -1360,7 +1386,6 @@ no_hardlink:
|
||||
int ntfs_delete(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name, u8 name_len)
|
||||
{
|
||||
ntfs_attr_search_ctx *actx = NULL;
|
||||
ntfs_index_context *ictx = NULL;
|
||||
FILE_NAME_ATTR *fn = NULL;
|
||||
BOOL looking_for_dos_name = FALSE, looking_for_win32_name = FALSE;
|
||||
BOOL case_sensitive_match = TRUE;
|
||||
@@ -1417,8 +1442,9 @@ search:
|
||||
/* Ignore hard links from other directories */
|
||||
if (dir_ni->mft_no != MREF_LE(fn->parent_directory)) {
|
||||
ntfs_log_debug("MFT record numbers don't match "
|
||||
"(%llu != %llu)\n", dir_ni->mft_no,
|
||||
MREF_LE(fn->parent_directory));
|
||||
"(%llu != %llu)\n",
|
||||
(long long unsigned)dir_ni->mft_no,
|
||||
(long long unsigned)MREF_LE(fn->parent_directory));
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1455,19 +1481,7 @@ search:
|
||||
if (ntfs_check_unlinkable_dir(ni, fn) < 0)
|
||||
goto err_out;
|
||||
|
||||
ictx = ntfs_index_ctx_get(dir_ni, NTFS_INDEX_I30, 4);
|
||||
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))
|
||||
if (ntfs_index_remove(dir_ni, fn, le32_to_cpu(actx->attr->value_length)))
|
||||
goto err_out;
|
||||
|
||||
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
|
||||
* non-resident attributes and mark all MFT record as not in use.
|
||||
*/
|
||||
if (ni->mrec->link_count)
|
||||
goto out;
|
||||
if (ni->mrec->link_count) {
|
||||
ntfs_inode_update_times(ni, NTFS_UPDATE_CTIME);
|
||||
goto ok;
|
||||
}
|
||||
ntfs_attr_reinit_search_ctx(actx);
|
||||
while (!ntfs_attrs_walk(actx)) {
|
||||
if (actx->attr->non_resident) {
|
||||
@@ -1531,12 +1547,14 @@ search:
|
||||
"Leaving inconsistent metadata.\n");
|
||||
}
|
||||
ni = NULL;
|
||||
ok:
|
||||
ntfs_inode_update_times(dir_ni, NTFS_UPDATE_MCTIME);
|
||||
out:
|
||||
if (actx)
|
||||
ntfs_attr_put_search_ctx(actx);
|
||||
if (ictx)
|
||||
ntfs_index_ctx_put(ictx);
|
||||
if (ni && ntfs_inode_close(ni) && !err)
|
||||
if (ntfs_inode_close(dir_ni) && !err)
|
||||
err = errno;
|
||||
if (ntfs_inode_close(ni) && !err)
|
||||
err = errno;
|
||||
if (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. */
|
||||
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");
|
||||
err = errno;
|
||||
/* Try to remove just added attribute from index. */
|
||||
ictx = ntfs_index_ctx_get(dir_ni, NTFS_INDEX_I30, 4);
|
||||
if (!ictx)
|
||||
if (ntfs_index_remove(dir_ni, fn, fn_len))
|
||||
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;
|
||||
}
|
||||
/* Increment hard links count. */
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
* Copyright (c) 2002 Anton Altaparmakov
|
||||
* Copyright (c) 2005-2006 Yura Pakhuchiy
|
||||
* 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
|
||||
* modify it under the terms of the GNU General Public License as published
|
||||
@@ -28,17 +29,10 @@
|
||||
|
||||
#define PATH_SEP '/'
|
||||
|
||||
#ifdef __HAIKU__
|
||||
#ifndef MAX_PATH
|
||||
#define MAX_PATH 1024
|
||||
#endif
|
||||
|
||||
/*
|
||||
* We do not have S_IFSOCK under BeOS/Haiku
|
||||
*/
|
||||
#if defined(__BEOS__) || defined(__HAIKU__)
|
||||
#ifndef S_IFSOCK
|
||||
#define S_IFSOCK 0140000
|
||||
#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,
|
||||
ntfschar *name, u8 name_len, dev_t type, dev_t dev);
|
||||
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_delete(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name,
|
||||
u8 name_len);
|
||||
|
||||
@@ -48,9 +48,6 @@
|
||||
#ifdef HAVE_SYS_BYTEORDER_H
|
||||
#include <sys/byteorder.h>
|
||||
#endif
|
||||
#ifdef HAVE_BYTEORDER_H
|
||||
#include <byteorder.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_PARAM_H
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* Copyright (c) 2004-2005 Anton Altaparmakov
|
||||
* Copyright (c) 2004-2005 Richard Russon
|
||||
* 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
|
||||
* 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;
|
||||
}
|
||||
|
||||
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),
|
||||
1, icx->block_size, buf);
|
||||
1, icx->block_size, ib);
|
||||
if (ret != 1) {
|
||||
ntfs_log_perror("Failed to write index block %lld of inode "
|
||||
"%llu", (long long)vcn,
|
||||
(unsigned long long)icx->ni->mft_no);
|
||||
ntfs_log_perror("Failed to write index block %lld, inode %llu",
|
||||
(long long)vcn, (unsigned long long)icx->ni->mft_no);
|
||||
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)
|
||||
{
|
||||
if (ntfs_ib_write(icx, icx->ib_vcn, icx->ib))
|
||||
if (ntfs_ib_write(icx, icx->ib))
|
||||
return STATUS_ERROR;
|
||||
|
||||
icx->ib_dirty = FALSE;
|
||||
@@ -148,18 +147,14 @@ static void ntfs_index_ctx_free(ntfs_index_context *icx)
|
||||
if (icx->actx)
|
||||
ntfs_attr_put_search_ctx(icx->actx);
|
||||
|
||||
if (icx->is_in_root) {
|
||||
if (icx->ia_na)
|
||||
ntfs_attr_close(icx->ia_na);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!icx->is_in_root) {
|
||||
if (icx->ib_dirty) {
|
||||
/* 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);
|
||||
}
|
||||
|
||||
@@ -225,7 +220,7 @@ static u8 *ntfs_ie_get_end(INDEX_HEADER *ih)
|
||||
|
||||
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;
|
||||
INDEX_ENTRY *ie;
|
||||
u8 *end;
|
||||
|
||||
ntfs_log_trace("Entering\n");
|
||||
|
||||
end = ntfs_ie_get_end(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);
|
||||
return n;
|
||||
}
|
||||
@@ -434,10 +431,8 @@ static INDEX_ROOT *ntfs_ir_lookup(ntfs_inode *ni, ntfschar *name,
|
||||
ntfs_log_trace("Entering\n");
|
||||
|
||||
*ctx = ntfs_attr_get_search_ctx(ni, NULL);
|
||||
if (!*ctx) {
|
||||
ntfs_log_perror("Failed to get $INDEX_ROOT search context");
|
||||
if (!*ctx)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ntfs_attr_lookup(AT_INDEX_ROOT, name, name_len, CASE_SENSITIVE,
|
||||
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));
|
||||
err_out:
|
||||
if (!ir)
|
||||
if (!ir) {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -577,7 +585,7 @@ static int ntfs_ib_read(ntfs_index_context *icx, VCN vcn, INDEX_BLOCK *dst)
|
||||
{
|
||||
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);
|
||||
|
||||
@@ -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
|
||||
* to disk.
|
||||
*/
|
||||
int ntfs_index_lookup(const void *key, const int key_len,
|
||||
ntfs_index_context *icx)
|
||||
int ntfs_index_lookup(const void *key, const int key_len, ntfs_index_context *icx)
|
||||
{
|
||||
VCN old_vcn, vcn;
|
||||
ntfs_inode *ni = icx->ni;
|
||||
INDEX_ROOT *ir;
|
||||
INDEX_ENTRY *ie;
|
||||
INDEX_BLOCK *ib = NULL;
|
||||
ntfs_attr_search_ctx *actx;
|
||||
int ret, err = 0;
|
||||
|
||||
ntfs_log_trace("Entering\n");
|
||||
@@ -670,7 +676,7 @@ int ntfs_index_lookup(const void *key, const int key_len,
|
||||
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 (errno == ENOENT)
|
||||
errno = EIO;
|
||||
@@ -682,7 +688,7 @@ int ntfs_index_lookup(const void *key, const int key_len,
|
||||
errno = EINVAL;
|
||||
ntfs_log_perror("Index block size (%d) is smaller than the "
|
||||
"sector size (%d)", icx->block_size, NTFS_BLOCK_SIZE);
|
||||
return -1;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
icx->actx = actx;
|
||||
icx->ir = ir;
|
||||
|
||||
if (ret != STATUS_KEEP_SEARCHING) {
|
||||
@@ -741,7 +746,7 @@ descend_into_child_node:
|
||||
}
|
||||
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))
|
||||
goto err_out;
|
||||
@@ -755,7 +760,7 @@ descend_into_child_node:
|
||||
/* STATUS_OK or STATUS_NOT_FOUND */
|
||||
icx->is_in_root = FALSE;
|
||||
icx->ib = ib;
|
||||
icx->parent_vcn[icx->pindex] = icx->ib_vcn = vcn;
|
||||
icx->parent_vcn[icx->pindex] = vcn;
|
||||
goto done;
|
||||
}
|
||||
|
||||
@@ -768,20 +773,15 @@ descend_into_child_node:
|
||||
|
||||
goto descend_into_child_node;
|
||||
err_out:
|
||||
if (icx->ia_na)
|
||||
ntfs_attr_close(icx->ia_na);
|
||||
free(ib);
|
||||
if (!err)
|
||||
err = EIO;
|
||||
if (actx)
|
||||
ntfs_attr_put_search_ctx(actx);
|
||||
errno = err;
|
||||
return -1;
|
||||
done:
|
||||
icx->entry = ie;
|
||||
icx->data = (u8 *)ie + offsetof(INDEX_ENTRY, key);
|
||||
icx->data_len = le16_to_cpu(ie->key_length);
|
||||
icx->max_depth = icx->pindex;
|
||||
ntfs_log_trace("Done.\n");
|
||||
if (err) {
|
||||
errno = err;
|
||||
@@ -797,7 +797,7 @@ static INDEX_BLOCK *ntfs_ib_alloc(VCN ib_vcn, u32 ib_size,
|
||||
INDEX_BLOCK *ib;
|
||||
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);
|
||||
if (!ib)
|
||||
@@ -893,7 +893,7 @@ static int ntfs_ibm_modify(ntfs_index_context *icx, VCN vcn, int set)
|
||||
ntfs_attr *na;
|
||||
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);
|
||||
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);
|
||||
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))
|
||||
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 +
|
||||
le32_to_cpu(dst->index.entries_offset));
|
||||
ret = ntfs_ib_write(icx, new_vcn, dst);
|
||||
ret = ntfs_ib_write(icx, dst);
|
||||
|
||||
free(dst);
|
||||
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)
|
||||
{
|
||||
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");
|
||||
|
||||
ies_start = (char *)ntfs_ie_get_first(&src->index);
|
||||
ies_end = (char *)ntfs_ie_get_end(&src->index);
|
||||
ies_start = (char *)ntfs_ie_get_first(&ib->index);
|
||||
ies_end = (char *)ntfs_ie_get_end(&ib->index);
|
||||
|
||||
ie_last = ntfs_ie_get_last((INDEX_ENTRY *)ies_start, ies_end);
|
||||
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));
|
||||
|
||||
src->index.index_length = cpu_to_le32(((char *)ie - ies_start) +
|
||||
le16_to_cpu(ie->length) + le32_to_cpu(src->index.entries_offset));
|
||||
ib->index.index_length = cpu_to_le32(((char *)ie - ies_start) +
|
||||
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_OK;
|
||||
@@ -1109,7 +1109,7 @@ static int ntfs_ia_add(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_ENTRY *ie;
|
||||
INDEX_BLOCK *ib = NULL;
|
||||
@@ -1118,17 +1118,21 @@ static int ntfs_ir_reparent(ntfs_index_context *icx)
|
||||
|
||||
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)
|
||||
return -1;
|
||||
goto out;
|
||||
|
||||
if ((ir->index.ih_flags & NODE_MASK) == SMALL_INDEX)
|
||||
if (ntfs_ia_add(icx))
|
||||
goto err_out;
|
||||
goto out;
|
||||
|
||||
new_ib_vcn = ntfs_ibm_get_free(icx);
|
||||
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);
|
||||
if (ib == NULL) {
|
||||
@@ -1136,7 +1140,11 @@ static int ntfs_ir_reparent(ntfs_index_context *icx)
|
||||
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;
|
||||
|
||||
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,
|
||||
sizeof(INDEX_ROOT) - sizeof(INDEX_HEADER) +
|
||||
le32_to_cpu(ir->index.allocated_size)))
|
||||
/* FIXME: revert bitmap, index root */
|
||||
goto err_out;
|
||||
/* FIXME: revert index root */
|
||||
goto clear_bmp;
|
||||
/*
|
||||
* FIXME: do it earlier if we have enough space in IR (should always),
|
||||
* 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:
|
||||
free(ib);
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
out:
|
||||
return ret;
|
||||
clear_bmp:
|
||||
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));
|
||||
if (ret == STATUS_OK) {
|
||||
|
||||
ntfs_attr_search_ctx *ctx;
|
||||
|
||||
icx->ir = ntfs_ir_lookup(icx->ni, icx->name, icx->name_len, &ctx);
|
||||
icx->ir = ntfs_ir_lookup2(icx->ni, icx->name, icx->name_len);
|
||||
if (!icx->ir)
|
||||
return STATUS_ERROR;
|
||||
|
||||
icx->ir->index.allocated_size = cpu_to_le32(data_size);
|
||||
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
|
||||
} else if (errno != ENOSPC)
|
||||
ntfs_log_trace("Failed to truncate INDEX_ROOT");
|
||||
} else if (ret == STATUS_ERROR)
|
||||
ntfs_log_perror("Failed to truncate INDEX_ROOT");
|
||||
|
||||
ntfs_attr_close(na);
|
||||
return ret;
|
||||
@@ -1304,6 +1309,10 @@ static int ntfs_ir_insert_median(ntfs_index_context *icx, INDEX_ENTRY *median,
|
||||
|
||||
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) +
|
||||
le16_to_cpu(median->length);
|
||||
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)
|
||||
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,
|
||||
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)))
|
||||
goto err_out;
|
||||
|
||||
if (ntfs_ib_write(icx, old_vcn, ib))
|
||||
if (ntfs_ib_write(icx, ib))
|
||||
goto err_out;
|
||||
|
||||
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 error return is STATUS_ERROR.
|
||||
@@ -1395,8 +1408,6 @@ static int ntfs_ib_split(ntfs_index_context *icx, INDEX_BLOCK *ib)
|
||||
else
|
||||
ret = ntfs_ib_insert(icx, median, new_vcn);
|
||||
|
||||
ntfs_inode_mark_dirty(icx->actx->ntfs_ino);
|
||||
|
||||
if (ret != STATUS_OK) {
|
||||
ntfs_ibm_clear(icx, new_vcn);
|
||||
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)
|
||||
{
|
||||
char *fn;
|
||||
INDEX_HEADER *ih;
|
||||
int allocated_size, new_size;
|
||||
int ret = STATUS_ERROR;
|
||||
|
||||
#ifdef DEBUG
|
||||
char *fn;
|
||||
fn = ntfs_ie_filename_get(ie);
|
||||
ntfs_log_trace("file: '%s'\n", fn);
|
||||
ntfs_attr_name_free(&fn);
|
||||
#endif
|
||||
|
||||
while (1) {
|
||||
|
||||
@@ -1478,7 +1491,7 @@ int ntfs_index_add_filename(ntfs_inode *ni, FILE_NAME_ATTR *fn, MFT_REF mref)
|
||||
{
|
||||
INDEX_ENTRY *ie;
|
||||
ntfs_index_context *icx;
|
||||
int fn_size, ie_size, ret = -1;
|
||||
int fn_size, ie_size, err, ret = -1;
|
||||
|
||||
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;
|
||||
|
||||
ret = ntfs_ie_add(icx, ie);
|
||||
|
||||
err = errno;
|
||||
ntfs_index_ctx_put(icx);
|
||||
errno = err;
|
||||
out:
|
||||
free(ie);
|
||||
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)
|
||||
ntfs_inode_mark_dirty(icx->actx->ntfs_ino);
|
||||
else
|
||||
if (ntfs_ib_write(icx, ntfs_icx_parent_vcn(icx), ib))
|
||||
if (ntfs_ib_write(icx, ib))
|
||||
goto out;
|
||||
|
||||
ntfs_index_ctx_reinit(icx);
|
||||
@@ -1560,9 +1574,6 @@ static void ntfs_ir_leafify(ntfs_index_context *icx, INDEX_HEADER *ih)
|
||||
|
||||
/* Not fatal error */
|
||||
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)
|
||||
{
|
||||
int entry_pos;
|
||||
int entry_pos, pindex;
|
||||
VCN vcn;
|
||||
INDEX_BLOCK *ib = NULL;
|
||||
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);
|
||||
entry_pos = icx->parent_pos[icx->pindex]++;
|
||||
pindex = icx->pindex;
|
||||
descend:
|
||||
vcn = ntfs_ie_get_vcn(ie_succ);
|
||||
if (ntfs_ib_read(icx, vcn, ib))
|
||||
@@ -1679,9 +1691,8 @@ descend:
|
||||
goto descend;
|
||||
|
||||
if (ntfs_ih_zero_entry(&ib->index)) {
|
||||
errno = EOPNOTSUPP;
|
||||
ntfs_log_perror("Failed to find any entry in an index block. "
|
||||
"Please run chkdsk.");
|
||||
errno = EIO;
|
||||
ntfs_log_perror("Empty index block");
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1703,18 +1714,18 @@ descend:
|
||||
new_size = le32_to_cpu(ih->index_length) + delta;
|
||||
if (delta > 0) {
|
||||
if (icx->is_in_root) {
|
||||
if (ntfs_ir_truncate(icx, new_size)) {
|
||||
errno = EOPNOTSUPP;
|
||||
ntfs_log_perror("Denied to truncate INDEX ROOT during entry removal");
|
||||
ret = ntfs_ir_make_space(icx, new_size);
|
||||
if (ret != STATUS_OK)
|
||||
goto out2;
|
||||
}
|
||||
|
||||
ih = &icx->ir->index;
|
||||
entry = ntfs_ie_get_by_pos(ih, entry_pos);
|
||||
|
||||
} else if (new_size > le32_to_cpu(ih->allocated_size)) {
|
||||
errno = EOPNOTSUPP;
|
||||
ntfs_log_perror("Denied to split INDEX BLOCK during entry removal");
|
||||
icx->pindex = pindex;
|
||||
ret = ntfs_ib_split(icx, icx->ib);
|
||||
if (ret == STATUS_OK)
|
||||
ret = STATUS_KEEP_SEARCHING;
|
||||
goto out2;
|
||||
}
|
||||
}
|
||||
@@ -1725,7 +1736,6 @@ descend:
|
||||
if (icx->is_in_root) {
|
||||
if (ntfs_ir_truncate(icx, new_size))
|
||||
goto out2;
|
||||
ntfs_inode_mark_dirty(icx->actx->ntfs_ino);
|
||||
} else
|
||||
if (ntfs_icx_ib_write(icx))
|
||||
goto out2;
|
||||
@@ -1736,7 +1746,7 @@ descend:
|
||||
if (ntfs_index_rm_leaf(icx))
|
||||
goto out2;
|
||||
} else
|
||||
if (ntfs_ib_write(icx, vcn, ib))
|
||||
if (ntfs_ib_write(icx, ib))
|
||||
goto out2;
|
||||
|
||||
ret = STATUS_OK;
|
||||
@@ -1757,10 +1767,10 @@ out:
|
||||
*
|
||||
* 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;
|
||||
int err;
|
||||
int err, ret = STATUS_OK;
|
||||
|
||||
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 (ntfs_index_rm_node(icx))
|
||||
goto err_out;
|
||||
ret = ntfs_index_rm_node(icx);
|
||||
|
||||
} 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))
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
ntfs_index_ctx_reinit(icx);
|
||||
ntfs_log_trace("Done.\n");
|
||||
return 0;
|
||||
out:
|
||||
return ret;
|
||||
err_out:
|
||||
err = errno;
|
||||
ntfs_index_ctx_reinit(icx);
|
||||
errno = err;
|
||||
ntfs_log_trace("Failed.\n");
|
||||
ret = STATUS_ERROR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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-2005 Richard Russon
|
||||
* 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
|
||||
* 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
|
||||
* @ia: index block if @is_in_root is FALSE or NULL otherwise
|
||||
* @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_vcn: entry's parent node or VCN_INDEX_ROOT_PARENT
|
||||
* @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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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
|
||||
* INDEX_ALLOCATION attribute. @ib_dirty is TRUE if index block was changed and
|
||||
* FALSE otherwise.
|
||||
@@ -96,9 +95,7 @@ typedef struct {
|
||||
INDEX_BLOCK *ib;
|
||||
ntfs_attr *ia_na;
|
||||
int parent_pos[MAX_PARENT_VCN]; /* parent entries' positions */
|
||||
VCN ib_vcn;
|
||||
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 */
|
||||
BOOL ib_dirty;
|
||||
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,
|
||||
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);
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
* inode.c - Inode handling code. Originated from the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2002-2005 Anton Altaparmakov
|
||||
* Copyright (c) 2002-2006 Szabolcs Szakacsits
|
||||
* Copyright (c) 2004-2005 Yura Pakhuchiy
|
||||
* Copyright (c) 2002-2008 Szabolcs Szakacsits
|
||||
* Copyright (c) 2004-2007 Yura Pakhuchiy
|
||||
* Copyright (c) 2004-2005 Richard Russon
|
||||
*
|
||||
* This program/include file is free software; you can redistribute it and/or
|
||||
@@ -51,6 +51,13 @@
|
||||
#include "logging.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
|
||||
* @ni: ntfs inode to set dirty
|
||||
@@ -80,7 +87,7 @@ static ntfs_inode *__ntfs_inode_allocate(ntfs_volume *vol)
|
||||
{
|
||||
ntfs_inode *ni;
|
||||
|
||||
ni = (ntfs_inode*)calloc(1, sizeof(ntfs_inode));
|
||||
ni = (ntfs_inode*)ntfs_calloc(sizeof(ntfs_inode));
|
||||
if (ni)
|
||||
ni->vol = vol;
|
||||
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)
|
||||
{
|
||||
s64 l;
|
||||
ntfs_inode *ni;
|
||||
ntfs_inode *ni = NULL;
|
||||
ntfs_attr_search_ctx *ctx;
|
||||
int err = 0;
|
||||
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) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
goto out;
|
||||
}
|
||||
ni = __ntfs_inode_allocate(vol);
|
||||
if (!ni)
|
||||
return NULL;
|
||||
goto out;
|
||||
if (ntfs_file_record_read(vol, mref, &ni->mrec, NULL))
|
||||
goto err_out;
|
||||
if (!(ni->mrec->flags & MFT_RECORD_IN_USE)) {
|
||||
err = ENOENT;
|
||||
errno = ENOENT;
|
||||
goto err_out;
|
||||
}
|
||||
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. */
|
||||
if (ntfs_attr_lookup(AT_STANDARD_INFORMATION, AT_UNNAMED,
|
||||
0, CASE_SENSITIVE, 0, NULL, 0, ctx)) {
|
||||
err = errno;
|
||||
ntfs_log_trace("Failed to receive STANDARD_INFORMATION "
|
||||
"attribute.\n");
|
||||
ntfs_log_perror("No STANDARD_INFORMATION in base record\n");
|
||||
goto put_err_out;
|
||||
}
|
||||
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)
|
||||
goto put_err_out;
|
||||
if (l > 0x40000) {
|
||||
err = EIO;
|
||||
errno = EIO;
|
||||
ntfs_log_perror("Too large attrlist (%lld)\n", (long long)l);
|
||||
goto put_err_out;
|
||||
}
|
||||
ni->attr_list_size = l;
|
||||
@@ -207,7 +212,9 @@ ntfs_inode *ntfs_inode_open(ntfs_volume *vol, const MFT_REF mref)
|
||||
if (!l)
|
||||
goto put_err_out;
|
||||
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;
|
||||
}
|
||||
get_size:
|
||||
@@ -232,17 +239,16 @@ get_size:
|
||||
}
|
||||
}
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
out:
|
||||
ntfs_log_leave("\n");
|
||||
return ni;
|
||||
|
||||
put_err_out:
|
||||
if (!err)
|
||||
err = errno;
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
err_out:
|
||||
if (!err)
|
||||
err = errno;
|
||||
__ntfs_inode_release(ni);
|
||||
errno = err;
|
||||
return NULL;
|
||||
ni = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -258,6 +264,8 @@ err_out:
|
||||
* If it is an extent inode, we disconnect it from its base inode before we
|
||||
* 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
|
||||
* 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:
|
||||
@@ -269,17 +277,19 @@ err_out:
|
||||
*/
|
||||
int ntfs_inode_close(ntfs_inode *ni)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
if (!ni)
|
||||
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 (NInoDirty(ni) || NInoAttrListDirty(ni)) {
|
||||
if (ntfs_inode_sync(ni)) {
|
||||
if (errno != EIO)
|
||||
errno = EBUSY;
|
||||
return -1;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
/* 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 (errno != EIO)
|
||||
errno = EBUSY;
|
||||
return -1;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
} else if (ni->nr_extents == -1) {
|
||||
@@ -342,7 +352,10 @@ int ntfs_inode_close(ntfs_inode *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)
|
||||
{
|
||||
u64 mft_no = MREF_LE(mref);
|
||||
ntfs_inode *ni;
|
||||
ntfs_inode *ni = NULL;
|
||||
ntfs_inode **extent_nis;
|
||||
int i;
|
||||
|
||||
if (!base_ni) {
|
||||
errno = EINVAL;
|
||||
ntfs_log_perror("%s", __FUNCTION__);
|
||||
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)base_ni->mft_no);
|
||||
|
||||
/* Is the extent inode already open and attached to the base inode? */
|
||||
if (base_ni->nr_extents > 0) {
|
||||
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);
|
||||
if (seq_no && seq_no != le16_to_cpu(
|
||||
ni->mrec->sequence_number)) {
|
||||
ntfs_log_debug("Found stale extent mft reference! "
|
||||
"Corrupt file system. Run chkdsk.\n");
|
||||
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. */
|
||||
return ni;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
/* Wasn't there, we need to load the extent inode. */
|
||||
ni = __ntfs_inode_allocate(base_ni->vol);
|
||||
if (!ni)
|
||||
return NULL;
|
||||
if (ntfs_file_record_read(base_ni->vol, le64_to_cpu(mref), &ni->mrec,
|
||||
NULL))
|
||||
goto out;
|
||||
if (ntfs_file_record_read(base_ni->vol, le64_to_cpu(mref), &ni->mrec, NULL))
|
||||
goto err_out;
|
||||
ni->mft_no = mft_no;
|
||||
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[base_ni->nr_extents++] = ni;
|
||||
out:
|
||||
ntfs_log_leave("\n");
|
||||
return ni;
|
||||
err_out:
|
||||
__ntfs_inode_release(ni);
|
||||
ntfs_log_perror("Failed to open extent inode");
|
||||
return NULL;
|
||||
ni = 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) {
|
||||
if (ni->mft_no != MREF_LE(ale->mft_reference) &&
|
||||
prev_attached != MREF_LE(ale->mft_reference)) {
|
||||
if (!ntfs_extent_inode_open(ni,
|
||||
MREF_LE(ale->mft_reference))) {
|
||||
if (!ntfs_extent_inode_open(ni, ale->mft_reference)) {
|
||||
ntfs_log_trace("Couldn't attach extent inode.\n");
|
||||
return -1;
|
||||
}
|
||||
@@ -498,20 +514,17 @@ static int ntfs_inode_sync_standard_information(ntfs_inode *ni)
|
||||
{
|
||||
ntfs_attr_search_ctx *ctx;
|
||||
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);
|
||||
if (!ctx)
|
||||
return -1;
|
||||
if (ntfs_attr_lookup(AT_STANDARD_INFORMATION, AT_UNNAMED,
|
||||
0, CASE_SENSITIVE, 0, NULL, 0, ctx)) {
|
||||
err = errno;
|
||||
ntfs_log_trace("Failed to receive STANDARD_INFORMATION "
|
||||
"attribute.\n");
|
||||
ntfs_log_perror("Failed to sync standard info (inode %lld)",
|
||||
(long long)ni->mft_no);
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
errno = err;
|
||||
return -1;
|
||||
}
|
||||
std_info = (STANDARD_INFORMATION *)((u8 *)ctx->attr +
|
||||
@@ -569,7 +582,7 @@ static int ntfs_inode_sync_file_name(ntfs_inode *ni)
|
||||
if (!err)
|
||||
err = errno;
|
||||
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;
|
||||
}
|
||||
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;
|
||||
ntfs_log_perror("Failed to get index ctx, inode %lld",
|
||||
(long long)index_ni->mft_no);
|
||||
ntfs_inode_close(index_ni);
|
||||
if (ni != index_ni && ntfs_inode_close(index_ni) && !err)
|
||||
err = errno;
|
||||
continue;
|
||||
}
|
||||
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",
|
||||
(long long)index_ni->mft_no);
|
||||
ntfs_index_ctx_put(ictx);
|
||||
ntfs_inode_close(index_ni);
|
||||
if (ni != index_ni && ntfs_inode_close(index_ni) && !err)
|
||||
err = errno;
|
||||
continue;
|
||||
}
|
||||
/* Update flags and file size. */
|
||||
@@ -651,6 +666,7 @@ err_out:
|
||||
*/
|
||||
int ntfs_inode_sync(ntfs_inode *ni)
|
||||
{
|
||||
int ret = 0;
|
||||
int err = 0;
|
||||
|
||||
if (!ni) {
|
||||
@@ -659,7 +675,7 @@ int ntfs_inode_sync(ntfs_inode *ni)
|
||||
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. */
|
||||
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)
|
||||
err = EBUSY;
|
||||
}
|
||||
ntfs_log_perror("Failed to sync standard info (inode %lld)",
|
||||
(long long)ni->mft_no);
|
||||
}
|
||||
|
||||
/* Update FILE_NAME's in the index. */
|
||||
@@ -770,10 +784,13 @@ sync_inode:
|
||||
}
|
||||
}
|
||||
|
||||
if (!err)
|
||||
return 0;
|
||||
if (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;
|
||||
|
||||
if (!ni) {
|
||||
ntfs_log_trace("Invalid arguments.\n");
|
||||
errno = EINVAL;
|
||||
ntfs_log_perror("%s", __FUNCTION__);
|
||||
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) {
|
||||
ntfs_log_trace("Inode already has got attribute list.\n");
|
||||
errno = EEXIST;
|
||||
ntfs_log_perror("Inode already has attribute list");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -814,7 +831,6 @@ int ntfs_inode_add_attrlist(ntfs_inode *ni)
|
||||
ctx = ntfs_attr_get_search_ctx(ni, NULL);
|
||||
if (!ctx) {
|
||||
err = errno;
|
||||
ntfs_log_trace("Couldn't get search context.\n");
|
||||
goto err_out;
|
||||
}
|
||||
/* Walk through all attributes. */
|
||||
@@ -824,7 +840,7 @@ int ntfs_inode_add_attrlist(ntfs_inode *ni)
|
||||
|
||||
if (ctx->attr->type == AT_ATTRIBUTE_LIST) {
|
||||
err = EIO;
|
||||
ntfs_log_trace("Eeek! Attribute list already present.\n");
|
||||
ntfs_log_perror("Attribute list already present");
|
||||
goto put_err_out;
|
||||
}
|
||||
|
||||
@@ -864,7 +880,8 @@ int ntfs_inode_add_attrlist(ntfs_inode *ni)
|
||||
/* Check for real error occurred. */
|
||||
if (errno != ENOENT) {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -882,8 +899,7 @@ int ntfs_inode_add_attrlist(ntfs_inode *ni)
|
||||
offsetof(ATTR_RECORD, resident_end))) {
|
||||
/* Failed to free space. */
|
||||
err = errno;
|
||||
ntfs_log_trace("Failed to free space for "
|
||||
"$ATTRIBUTE_LIST.\n");
|
||||
ntfs_log_perror("Failed to free space for attrlist");
|
||||
goto rollback;
|
||||
}
|
||||
}
|
||||
@@ -892,7 +908,7 @@ int ntfs_inode_add_attrlist(ntfs_inode *ni)
|
||||
if (ntfs_resident_attr_record_add(ni,
|
||||
AT_ATTRIBUTE_LIST, NULL, 0, NULL, 0, 0) < 0) {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -900,12 +916,12 @@ int ntfs_inode_add_attrlist(ntfs_inode *ni)
|
||||
na = ntfs_attr_open(ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0);
|
||||
if (!na) {
|
||||
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;
|
||||
}
|
||||
if (ntfs_attr_truncate(na, al_len)) {
|
||||
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);
|
||||
goto remove_attrlist_record;;
|
||||
}
|
||||
@@ -923,11 +939,9 @@ remove_attrlist_record:
|
||||
if (!ntfs_attr_lookup(AT_ATTRIBUTE_LIST, NULL, 0,
|
||||
CASE_SENSITIVE, 0, NULL, 0, ctx)) {
|
||||
if (ntfs_attr_record_rm(ctx))
|
||||
ntfs_log_trace("Rollback failed. Failed to remove attribute "
|
||||
"list record.\n");
|
||||
ntfs_log_perror("Rollback failed to remove attrlist");
|
||||
} else
|
||||
ntfs_log_trace("Rollback failed. Couldn't find attribute list "
|
||||
"record.\n");
|
||||
ntfs_log_perror("Rollback failed to find attrlist");
|
||||
/* Setup back in-memory runlist. */
|
||||
ni->attr_list = al;
|
||||
ni->attr_list_size = al_len;
|
||||
@@ -947,11 +961,10 @@ rollback:
|
||||
sle64_to_cpu(ale->lowest_vcn),
|
||||
NULL, 0, ctx)) {
|
||||
if (ntfs_attr_record_move_to(ctx, ni))
|
||||
ntfs_log_trace("Rollback failed. Couldn't "
|
||||
"back attribute to base MFT record.\n");
|
||||
ntfs_log_perror("Rollback failed to "
|
||||
"move attribute");
|
||||
} else
|
||||
ntfs_log_trace("Rollback failed. ntfs_attr_lookup "
|
||||
"failed.\n");
|
||||
ntfs_log_perror("Rollback failed to find attr");
|
||||
ntfs_attr_reinit_search_ctx(ctx);
|
||||
}
|
||||
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
|
||||
* @ni: ntfs inode in which MFT record free space
|
||||
* ntfs_inode_free_space - free space in the MFT record of an inode
|
||||
* @ni: ntfs inode in which MFT record needs more free space
|
||||
* @size: amount of space needed to free
|
||||
*
|
||||
* 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)
|
||||
{
|
||||
ntfs_attr_search_ctx *ctx;
|
||||
int freed, err;
|
||||
int freed;
|
||||
|
||||
if (!ni || size < 0) {
|
||||
ntfs_log_trace("Invalid arguments.\n");
|
||||
errno = EINVAL;
|
||||
ntfs_log_perror("%s: ni=%p size=%d", __FUNCTION__, ni, size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ntfs_log_trace("Entering for inode 0x%llx, size %d.\n",
|
||||
(long long) ni->mft_no, size);
|
||||
ntfs_log_trace("Entering for inode %lld, size %d\n",
|
||||
(unsigned long long)ni->mft_no, size);
|
||||
|
||||
freed = (le32_to_cpu(ni->mrec->bytes_allocated) -
|
||||
le32_to_cpu(ni->mrec->bytes_in_use));
|
||||
@@ -997,138 +1010,96 @@ int ntfs_inode_free_space(ntfs_inode *ni, int size)
|
||||
return 0;
|
||||
|
||||
ctx = ntfs_attr_get_search_ctx(ni, NULL);
|
||||
if (!ctx) {
|
||||
err = errno;
|
||||
ntfs_log_trace("Failed to get attribute search context.\n");
|
||||
errno = err;
|
||||
if (!ctx)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Chkdsk complain if $STANDARD_INFORMATION is not in the base MFT
|
||||
* record. FIXME: I'm not sure in this, need to recheck. For now simply
|
||||
* 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.
|
||||
* $STANDARD_INFORMATION and $ATTRIBUTE_LIST must stay in the base MFT
|
||||
* record, so position search context on the first attribute after them.
|
||||
*/
|
||||
if (ntfs_attr_lookup(AT_FILE_NAME, NULL, 0, CASE_SENSITIVE, 0, NULL,
|
||||
0, ctx)) {
|
||||
if (errno != ENOENT) {
|
||||
err = errno;
|
||||
ntfs_log_trace("Attribute lookup failed.\n");
|
||||
if (ntfs_attr_position(AT_FILE_NAME, ctx))
|
||||
goto put_err_out;
|
||||
}
|
||||
if (ctx->attr->type == AT_END) {
|
||||
err = ENOSPC;
|
||||
goto put_err_out;
|
||||
}
|
||||
}
|
||||
|
||||
while (1) {
|
||||
int record_size;
|
||||
|
||||
/*
|
||||
* Check whether attribute is from different MFT record. If so,
|
||||
* find next, because we don't need such.
|
||||
*/
|
||||
while (ctx->ntfs_ino->mft_no != ni->mft_no) {
|
||||
if (ntfs_attr_lookup(AT_UNUSED, NULL, 0, CASE_SENSITIVE,
|
||||
0, NULL, 0, ctx)) {
|
||||
err = errno;
|
||||
if (errno != ENOENT) {
|
||||
ntfs_log_trace("Attribute lookup failed.\n");
|
||||
} else
|
||||
err = ENOSPC;
|
||||
retry:
|
||||
if (ntfs_attr_position(AT_UNUSED, ctx))
|
||||
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);
|
||||
|
||||
/* Move away attribute. */
|
||||
if (ntfs_attr_record_move_away(ctx, 0)) {
|
||||
err = errno;
|
||||
ntfs_log_trace("Failed to move out attribute.\n");
|
||||
ntfs_log_perror("Failed to move out attribute #2");
|
||||
break;
|
||||
}
|
||||
freed += record_size;
|
||||
|
||||
/* Check whether we done. */
|
||||
/* Check whether we are done. */
|
||||
if (size <= freed) {
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reposition to first attribute after $STANDARD_INFORMATION and
|
||||
* $ATTRIBUTE_LIST (see comments upwards).
|
||||
* Reposition to first attribute after $STANDARD_INFORMATION
|
||||
* 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);
|
||||
if (ntfs_attr_lookup(AT_FILE_NAME, NULL, 0, CASE_SENSITIVE, 0,
|
||||
NULL, 0, ctx)) {
|
||||
if (errno != ENOENT) {
|
||||
err = errno;
|
||||
ntfs_log_trace("Attribute lookup failed.\n");
|
||||
if (ntfs_attr_position(AT_FILE_NAME, ctx))
|
||||
break;
|
||||
}
|
||||
if (ctx->attr->type == AT_END) {
|
||||
err = ENOSPC;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
put_err_out:
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
if (err == ENOSPC)
|
||||
ntfs_log_trace("No attributes left that can be moved out.\n");
|
||||
errno = err;
|
||||
if (errno == ENOSPC)
|
||||
ntfs_log_trace("No attributes left that could be moved out.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_inode_update_atime - update access time for ntfs inode
|
||||
* @ni: ntfs inode for which update access time
|
||||
* ntfs_inode_update_times - update selected time fields for ntfs inode
|
||||
* @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.
|
||||
* Do not update time for system files.
|
||||
* This function updates time fields to current time. Fields to update are
|
||||
* 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;
|
||||
|
||||
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);
|
||||
if (mask & NTFS_UPDATE_ATIME)
|
||||
ni->last_access_time = now;
|
||||
if (mask & NTFS_UPDATE_MTIME)
|
||||
ni->last_data_change_time = now;
|
||||
if (mask & NTFS_UPDATE_CTIME)
|
||||
ni->last_mft_change_time = now;
|
||||
|
||||
NInoFileNameSetDirty(ni);
|
||||
NInoSetDirty(ni);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/*
|
||||
* inode.h - Defines for NTFS inode handling. Originated from the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2001,2002 Anton Altaparmakov
|
||||
* Copyright (c) 2004-2005 Yura Pakhuchiy
|
||||
* Copyright (c) 2001-2004 Anton Altaparmakov
|
||||
* Copyright (c) 2004-2007 Yura Pakhuchiy
|
||||
* 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
|
||||
* 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 NInoAttrListTestAndClearDirty(ni) test_and_clear_nino_al_flag(ni, Dirty)
|
||||
|
||||
#define NInoFileNameDirty(ni) \
|
||||
test_nino_flag(ni, FileNameDirty)
|
||||
#define NInoFileNameSetDirty(ni) \
|
||||
set_nino_flag(ni, FileNameDirty)
|
||||
#define NInoFileNameClearDirty(ni) \
|
||||
clear_nino_flag(ni, FileNameDirty)
|
||||
#define NInoFileNameDirty(ni) test_nino_flag(ni, FileNameDirty)
|
||||
#define NInoFileNameSetDirty(ni) set_nino_flag(ni, FileNameDirty)
|
||||
#define NInoFileNameClearDirty(ni) clear_nino_flag(ni, FileNameDirty)
|
||||
#define NInoFileNameTestAndSetDirty(ni) \
|
||||
test_and_set_nino_flag(ni, FileNameDirty)
|
||||
#define NInoFileNameTestAndClearDirty(ni) \
|
||||
@@ -130,12 +127,14 @@ struct _ntfs_inode {
|
||||
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. */
|
||||
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
|
||||
index. (NOTE: Equal to allocated size of
|
||||
the unnamed data attribute for normal or
|
||||
@@ -143,12 +142,28 @@ struct _ntfs_inode {
|
||||
of the unnamed data attribute for sparse or
|
||||
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 last_data_change_time;
|
||||
time_t last_mft_change_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_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_update_atime(ntfs_inode *ni);
|
||||
extern void ntfs_inode_update_time(ntfs_inode *ni);
|
||||
extern void ntfs_inode_update_times(ntfs_inode *ni, ntfs_time_update_flags mask);
|
||||
|
||||
extern int ntfs_inode_sync(ntfs_inode *ni);
|
||||
|
||||
|
||||
@@ -2340,17 +2340,18 @@ typedef struct {
|
||||
control entry in the data part of
|
||||
the index. */
|
||||
} __attribute__((__packed__)) key;
|
||||
/* The (optional) index data is inserted here when creating. */
|
||||
// VCN vcn; If INDEX_ENTRY_NODE bit in ie_flags is set, the last
|
||||
// eight bytes of this index entry contain the virtual
|
||||
// cluster number of the index block that holds the
|
||||
// entries immediately preceding the current entry.
|
||||
//
|
||||
// If the key_length is zero, then the vcn immediately
|
||||
// follows the INDEX_ENTRY_HEADER.
|
||||
//
|
||||
// The address of the vcn of "ie" INDEX_ENTRY is given by
|
||||
// (char*)ie + le16_to_cpu(ie->length) - sizeof(VCN)
|
||||
/* The (optional) index data is inserted here when creating.
|
||||
VCN vcn; If INDEX_ENTRY_NODE bit in ie_flags is set, the last
|
||||
eight bytes of this index entry contain the virtual
|
||||
cluster number of the index block that holds the
|
||||
entries immediately preceding the current entry.
|
||||
|
||||
If the key_length is zero, then the vcn immediately
|
||||
follows the INDEX_ENTRY_HEADER.
|
||||
|
||||
The address of the vcn of "ie" INDEX_ENTRY is given by
|
||||
(char*)ie + le16_to_cpu(ie->length) - sizeof(VCN)
|
||||
*/
|
||||
} __attribute__((__packed__)) INDEX_ENTRY;
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (c) 2002-2004 Anton Altaparmakov
|
||||
* 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
|
||||
* 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
|
||||
* 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
|
||||
|
||||
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)
|
||||
*pos = start;
|
||||
@@ -85,10 +85,15 @@ static s64 max_empty_bit_range(unsigned char *buf, int size)
|
||||
int max_range = 0;
|
||||
s64 start_pos = -1;
|
||||
|
||||
ntfs_log_trace("Entering");
|
||||
ntfs_log_trace("Entering\n");
|
||||
|
||||
for (i = 0; i < size; i++, buf++) {
|
||||
|
||||
if (*buf == 0) {
|
||||
run += 8;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (j = 0; j < 8; 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;
|
||||
|
||||
ntfs_log_trace("Entering");
|
||||
ntfs_log_trace("Entering\n");
|
||||
|
||||
if (!*writeback)
|
||||
return 0;
|
||||
@@ -126,7 +131,8 @@ static int bitmap_writeback(ntfs_volume *vol, s64 pos, s64 size, void *b,
|
||||
if (written != size) {
|
||||
if (!written)
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -189,16 +195,17 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
|
||||
u8 has_guess, used_zone_pos;
|
||||
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)
|
||||
start_lcn, zone == MFT_ZONE ? "MFT" : "DATA");
|
||||
|
||||
if (!vol || count < 0 || start_lcn < -1 || !vol->lcnbmp_na ||
|
||||
(s8)zone < FIRST_ZONE || zone > LAST_ZONE) {
|
||||
errno = EINVAL;
|
||||
ntfs_log_perror("%s: vcn: %lld, count: %lld, lcn: %lld",
|
||||
__FUNCTION__, (long long)start_vcn,
|
||||
(long long)count, (long long)start_lcn);
|
||||
return NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* 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].length = 0;
|
||||
}
|
||||
return rl;
|
||||
goto out;
|
||||
}
|
||||
|
||||
buf = ntfs_malloc(NTFS_LCNALLOC_BSIZE);
|
||||
if (!buf)
|
||||
return NULL;
|
||||
goto out;
|
||||
/*
|
||||
* If no @start_lcn was requested, use the current zone
|
||||
* 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;
|
||||
writeback = 0;
|
||||
|
||||
while (1) {
|
||||
while (lcn < buf_size) {
|
||||
byte = buf + (lcn >> 3);
|
||||
bit = 1 << (lcn & 7);
|
||||
if (has_guess) {
|
||||
@@ -305,25 +312,44 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
|
||||
/* Allocate the bitmap bit. */
|
||||
*byte |= bit;
|
||||
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.
|
||||
* 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;
|
||||
else {
|
||||
} else {
|
||||
if (rlpos)
|
||||
rl[rlpos].vcn = rl[rlpos - 1].vcn +
|
||||
prev_run_len;
|
||||
else
|
||||
else {
|
||||
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].length = prev_run_len = 1;
|
||||
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? */
|
||||
if (!--clusters) {
|
||||
if (used_zone_pos)
|
||||
@@ -425,7 +451,7 @@ switch_to_data1_zone: search_zone = 2;
|
||||
search_zone = 1;
|
||||
zone_start = vol->mft_zone_pos;
|
||||
zone_end = vol->mft_zone_end;
|
||||
if (!zone_start == vol->mft_zone_start)
|
||||
if (zone_start == vol->mft_zone_start)
|
||||
pass = 2;
|
||||
break;
|
||||
}
|
||||
@@ -455,13 +481,15 @@ done_ret:
|
||||
goto err_ret;
|
||||
}
|
||||
done_err_ret:
|
||||
ntfs_log_debug("At done_err_ret (follows done_ret).\n");
|
||||
free(buf);
|
||||
if (!err)
|
||||
return rl;
|
||||
ntfs_log_trace("Failed to allocate clusters (%d)", errno);
|
||||
if (err) {
|
||||
errno = err;
|
||||
return NULL;
|
||||
ntfs_log_perror("Failed to allocate clusters");
|
||||
rl = NULL;
|
||||
}
|
||||
out:
|
||||
ntfs_log_leave("\n");
|
||||
return rl;
|
||||
|
||||
wb_err_ret:
|
||||
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].lcn = LCN_RL_NOT_MAPPED;
|
||||
rl[rlpos].length = 0;
|
||||
ntfs_debug_runlist_dump(rl);
|
||||
ntfs_cluster_free_from_rl(vol, rl);
|
||||
free(rl);
|
||||
rl = NULL;
|
||||
@@ -490,6 +519,9 @@ err_ret:
|
||||
*/
|
||||
int ntfs_cluster_free_from_rl(ntfs_volume *vol, runlist *rl)
|
||||
{
|
||||
s64 nr_freed = 0;
|
||||
int ret = -1;
|
||||
|
||||
ntfs_log_trace("Entering.\n");
|
||||
|
||||
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",
|
||||
(long long)rl->lcn, (long long)rl->length);
|
||||
|
||||
if (rl->lcn >= 0 && ntfs_bitmap_clear_run(vol->lcnbmp_na,
|
||||
rl->lcn, rl->length)) {
|
||||
int eo = errno;
|
||||
ntfs_log_trace("Eeek! Deallocation of clusters failed.\n");
|
||||
errno = eo;
|
||||
return -1;
|
||||
if (rl->lcn >= 0) {
|
||||
if (ntfs_bitmap_clear_run(vol->lcnbmp_na, rl->lcn,
|
||||
rl->length)) {
|
||||
ntfs_log_perror("Cluster deallocation failed "
|
||||
"(%lld, %lld)",
|
||||
(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)
|
||||
{
|
||||
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 ||
|
||||
(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;
|
||||
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,
|
||||
na->type, (long long)count, (long long)start_vcn);
|
||||
|
||||
rl = ntfs_attr_find_vcn(na, start_vcn);
|
||||
if (!rl) {
|
||||
if (errno == ENOENT)
|
||||
return 0;
|
||||
else
|
||||
return -1;
|
||||
ret = 0;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
if (rl->lcn < 0 && rl->lcn != LCN_HOLE) {
|
||||
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. */
|
||||
@@ -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. */
|
||||
if (ntfs_bitmap_clear_run(vol->lcnbmp_na, rl->lcn + delta,
|
||||
to_free))
|
||||
return -1;
|
||||
/* We have freed @to_free real clusters. */
|
||||
goto leave;
|
||||
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. */
|
||||
@@ -586,11 +629,10 @@ int ntfs_cluster_free(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn, s64 count)
|
||||
// list support! (AIA)
|
||||
if (rl->lcn < 0 && rl->lcn != LCN_HOLE) {
|
||||
// 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;
|
||||
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. */
|
||||
@@ -599,18 +641,13 @@ int ntfs_cluster_free(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn, s64 count)
|
||||
to_free = count;
|
||||
|
||||
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,
|
||||
to_free)) {
|
||||
int eo = errno;
|
||||
|
||||
// FIXME: Eeek! We need rollback! (AIA)
|
||||
ntfs_log_trace("Eeek! bitmap clear run failed. "
|
||||
"Leaving inconsistent metadata!\n");
|
||||
errno = eo;
|
||||
return -1;
|
||||
ntfs_log_perror("%s: Clearing bitmap run failed",
|
||||
__FUNCTION__);
|
||||
goto out;
|
||||
}
|
||||
/* We have freed @to_free real clusters. */
|
||||
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) {
|
||||
// FIXME: Eeek! BUG()
|
||||
ntfs_log_trace("Eeek! count still not zero (= %lli). Leaving "
|
||||
"inconsistent metadata!\n", (long long)count);
|
||||
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. */
|
||||
return nr_freed;
|
||||
ret = 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) 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
|
||||
* 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 &&
|
||||
!(ra->flags & RESTART_VOLUME_IS_CLEAN)) {
|
||||
ntfs_log_error("$LogFile indicates unclean shutdown (%d, %d)\n",
|
||||
le16_to_cpu(ra->client_in_use_list),
|
||||
ntfs_log_error("The disk contains an unclean file system (%d, "
|
||||
"%d).\n", le16_to_cpu(ra->client_in_use_list),
|
||||
le16_to_cpu(ra->flags));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* logging.c - Centralised logging. Originated from the Linux-NTFS project.
|
||||
*
|
||||
* 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
|
||||
* modify it under the terms of the GNU General Public License as published
|
||||
@@ -50,13 +50,16 @@
|
||||
#define PATH_SEP '/'
|
||||
#endif
|
||||
|
||||
/* Colour prefixes and a suffix */
|
||||
static const char *col_green = "\e[32m";
|
||||
static const char *col_cyan = "\e[36m";
|
||||
static const char *col_yellow = "\e[01;33m";
|
||||
static const char *col_red = "\e[01;31m";
|
||||
static const char *col_redinv = "\e[01;07;31m";
|
||||
static const char *col_end = "\e[0m";
|
||||
#ifdef DEBUG
|
||||
static int tab;
|
||||
#endif
|
||||
|
||||
/* Some gcc 3.x, 4.[01].X crash with internal compiler error. */
|
||||
#if __GNUC__ <= 3 || (__GNUC__ == 4 && __GNUC_MINOR__ <= 1)
|
||||
# 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
|
||||
@@ -67,7 +70,7 @@ static const char *col_end = "\e[0m";
|
||||
struct ntfs_logging {
|
||||
u32 levels;
|
||||
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 = {
|
||||
#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
|
||||
NTFS_LOG_LEVEL_INFO | NTFS_LOG_LEVEL_QUIET | NTFS_LOG_LEVEL_WARNING |
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
#ifndef __HAIKU__
|
||||
/**
|
||||
* ntfs_log_get_stream - Default output streams for logging levels
|
||||
* @level: Log level
|
||||
@@ -195,9 +199,6 @@ u32 ntfs_log_clear_flags(u32 flags)
|
||||
*/
|
||||
static FILE * ntfs_log_get_stream(u32 level)
|
||||
{
|
||||
#if defined(__BEOS__) || defined(__HAIKU__)
|
||||
return NULL;
|
||||
#else
|
||||
FILE *stream;
|
||||
|
||||
switch (level) {
|
||||
@@ -210,6 +211,8 @@ static FILE * ntfs_log_get_stream(u32 level)
|
||||
|
||||
case NTFS_LOG_LEVEL_DEBUG:
|
||||
case NTFS_LOG_LEVEL_TRACE:
|
||||
case NTFS_LOG_LEVEL_ENTER:
|
||||
case NTFS_LOG_LEVEL_LEAVE:
|
||||
case NTFS_LOG_LEVEL_WARNING:
|
||||
case NTFS_LOG_LEVEL_ERROR:
|
||||
case NTFS_LOG_LEVEL_CRITICAL:
|
||||
@@ -220,7 +223,6 @@ static FILE * ntfs_log_get_stream(u32 level)
|
||||
}
|
||||
|
||||
return stream;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -273,7 +275,7 @@ static const char * ntfs_log_get_prefix(u32 level)
|
||||
|
||||
return prefix;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* 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;
|
||||
#ifdef HAVE_SYSLOG_H
|
||||
if (handler == ntfs_log_handler_syslog)
|
||||
openlog("libntfs", LOG_PID, LOG_USER);
|
||||
openlog("ntfs-3g", LOG_PID, LOG_USER);
|
||||
#endif
|
||||
} else
|
||||
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)),
|
||||
const char *format, va_list args)
|
||||
{
|
||||
char log[LOG_LINE_LEN];
|
||||
char logbuf[LOG_LINE_LEN];
|
||||
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) {
|
||||
vsyslog(LOG_NOTICE, format, args);
|
||||
return 1;
|
||||
ret = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((LOG_LINE_LEN > ret + 3) && (level & NTFS_LOG_LEVEL_PERROR)) {
|
||||
strncat(log, ": ", LOG_LINE_LEN - ret - 1);
|
||||
strncat(log, strerror(olderr), LOG_LINE_LEN - (ret + 3));
|
||||
ret = strlen(log);
|
||||
strncat(logbuf, ": ", LOG_LINE_LEN - ret - 1);
|
||||
strncat(logbuf, strerror(olderr), LOG_LINE_LEN - (ret + 3));
|
||||
ret = strlen(logbuf);
|
||||
}
|
||||
|
||||
syslog(LOG_NOTICE, "%s", log);
|
||||
|
||||
syslog(LOG_NOTICE, "%s", logbuf);
|
||||
out:
|
||||
errno = olderr;
|
||||
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 line, u32 level, void *data, const char *format, va_list args)
|
||||
{
|
||||
#if defined(__BEOS__) || defined(__HAIKU__)
|
||||
#ifdef __HAIKU__
|
||||
return 0;
|
||||
#else
|
||||
#ifdef DEBUG
|
||||
int i;
|
||||
#endif
|
||||
int ret = 0;
|
||||
int olderr = errno;
|
||||
FILE *stream;
|
||||
const char *col_prefix = NULL;
|
||||
const char *col_suffix = NULL;
|
||||
|
||||
if (!data) /* Interpret data as a FILE stream. */
|
||||
return 0; /* If it's NULL, we can't do anything. */
|
||||
stream = (FILE*)data;
|
||||
|
||||
if (ntfs_log.flags & NTFS_LOG_FLAG_COLOUR) {
|
||||
/* Pick a colour determined by the log level */
|
||||
switch (level) {
|
||||
case NTFS_LOG_LEVEL_DEBUG:
|
||||
col_prefix = col_green;
|
||||
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;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
if (level == NTFS_LOG_LEVEL_LEAVE) {
|
||||
if (tab)
|
||||
tab--;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (col_prefix)
|
||||
ret += fprintf(stream, col_prefix);
|
||||
|
||||
for (i = 0; i < tab; i++)
|
||||
ret += fprintf(stream, " ");
|
||||
#endif
|
||||
if ((ntfs_log.flags & NTFS_LOG_FLAG_ONLYNAME) &&
|
||||
(strchr(file, PATH_SEP))) /* Abbreviate the filename */
|
||||
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);
|
||||
|
||||
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 += 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)
|
||||
ret += fprintf(stream, ": %s\n", strerror(olderr));
|
||||
|
||||
if (col_suffix)
|
||||
ret += fprintf(stream, col_suffix);
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
if (level == NTFS_LOG_LEVEL_ENTER)
|
||||
tab++;
|
||||
#endif
|
||||
fflush(stream);
|
||||
errno = olderr;
|
||||
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 line, u32 level, void *data, const char *format, va_list args)
|
||||
{
|
||||
#if defined(__BEOS__) || defined(__HAIKU__)
|
||||
#ifdef __HAIKU__
|
||||
return 0;
|
||||
#else
|
||||
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 line, u32 level, void *data, const char *format, va_list args)
|
||||
{
|
||||
#if defined(__BEOS__) || defined(__HAIKU__)
|
||||
#ifdef __HAIKU__
|
||||
return 0;
|
||||
#else
|
||||
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 line, u32 level, void *data, const char *format, va_list args)
|
||||
{
|
||||
#if defined(__BEOS__) || defined(__HAIKU__)
|
||||
#ifdef __HAIKU__
|
||||
return 0;
|
||||
#else
|
||||
if (!data)
|
||||
@@ -633,10 +621,6 @@ BOOL ntfs_log_parse_option(const char *option)
|
||||
} else if (strcmp(option, "--log-trace") == 0) {
|
||||
ntfs_log_set_levels(NTFS_LOG_LEVEL_TRACE);
|
||||
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);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* logging.h - Centralised logging. Originated from the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2005 Richard Russon
|
||||
* Copyright (c) 2007-2008 Szabolcs Szakacsits
|
||||
*
|
||||
* 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
|
||||
@@ -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);
|
||||
|
||||
/* Set the logging handler from one of the functions, below. */
|
||||
#ifdef __HAIKU__
|
||||
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 */
|
||||
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_PERROR (1 << 8) /* Message : standard error description */
|
||||
#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 */
|
||||
#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_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_COLOUR (1 << 5) /* Colour highlight some messages */
|
||||
|
||||
/* Macros to simplify logging. One for each level defined above.
|
||||
* 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
|
||||
#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_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
|
||||
#define ntfs_log_debug(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 /* _LOGGING_H_ */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (c) 2000-2002 Anton Altaparmakov
|
||||
* 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
|
||||
* modify it under the terms of the GNU General Public License as published
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "volume.h"
|
||||
#include "inode.h"
|
||||
#include "layout.h"
|
||||
#include "logging.h"
|
||||
|
||||
extern int ntfs_mft_records_read(const ntfs_volume *vol, const MFT_REF mref,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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;
|
||||
}
|
||||
|
||||
#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_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_ */
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* mst.c - Multi sector fixup handling code. Originated from the Linux-NTFS project.
|
||||
*
|
||||
* 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
|
||||
* 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 ||
|
||||
(size >> NTFS_BLOCK_SIZE_BITS) != usa_count) {
|
||||
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;
|
||||
}
|
||||
/* 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.
|
||||
* Note that magic_BAAD is already converted to le32.
|
||||
*/
|
||||
b->magic = magic_BAAD;
|
||||
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;
|
||||
}
|
||||
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) ||
|
||||
ntfs_is_hole_record(b->magic)) {
|
||||
errno = EINVAL;
|
||||
ntfs_log_perror("%s: bad argument", __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
/* 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 ||
|
||||
(size >> NTFS_BLOCK_SIZE_BITS) != usa_count) {
|
||||
errno = EINVAL;
|
||||
ntfs_log_perror("%s", __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
/* Position of usn in update sequence array. */
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (c) 2002-2005 Anton Altaparmakov
|
||||
* Copyright (c) 2002-2005 Richard Russon
|
||||
* Copyright (c) 2002-2006 Szabolcs Szakacsits
|
||||
* Copyright (c) 2002-2008 Szabolcs Szakacsits
|
||||
* Copyright (c) 2004 Yura Pakhuchiy
|
||||
*
|
||||
* 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
|
||||
* @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.
|
||||
* ntfs_runlists_merge_i - see ntfs_runlists_merge
|
||||
*/
|
||||
runlist_element *ntfs_runlists_merge(runlist_element *drl,
|
||||
static runlist_element *ntfs_runlists_merge_i(runlist_element *drl,
|
||||
runlist_element *srl)
|
||||
{
|
||||
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. */
|
||||
if (!srl[si].length) {
|
||||
ntfs_log_debug("Eeek! ntfs_runlists_merge() received entirely "
|
||||
"unmapped source runlist.\n");
|
||||
errno = EINVAL;
|
||||
ntfs_log_perror("%s: unmapped source runlist", __FUNCTION__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -567,8 +537,8 @@ runlist_element *ntfs_runlists_merge(runlist_element *drl,
|
||||
/* Sanity check for illegal overlaps. */
|
||||
if ((drl[di].vcn == srl[si].vcn) && (drl[di].lcn >= 0) &&
|
||||
(srl[si].lcn >= 0)) {
|
||||
ntfs_log_debug("Run lists overlap. Cannot merge!\n");
|
||||
errno = ERANGE;
|
||||
ntfs_log_perror("Run lists overlap. Cannot merge");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -702,6 +672,49 @@ critical_error:
|
||||
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
|
||||
* @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
|
||||
* 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)
|
||||
{
|
||||
VCN vcn; /* Current vcn. */
|
||||
@@ -953,6 +966,17 @@ err_out:
|
||||
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
|
||||
* @rl: runlist to use for conversion
|
||||
@@ -1642,16 +1666,16 @@ int ntfs_rl_sparse(runlist *rl)
|
||||
runlist *rlc;
|
||||
|
||||
if (!rl) {
|
||||
ntfs_log_trace("Invalid argument passed.\n");
|
||||
errno = EINVAL;
|
||||
ntfs_log_perror("%s: ", __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (rlc = rl; rlc->length; rlc++)
|
||||
if (rlc->lcn < 0) {
|
||||
if (rlc->lcn != LCN_HOLE) {
|
||||
ntfs_log_trace("Received unmapped runlist.\n");
|
||||
errno = EINVAL;
|
||||
ntfs_log_perror("%s: bad runlist", __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
@@ -1672,16 +1696,16 @@ s64 ntfs_rl_get_compressed_size(ntfs_volume *vol, runlist *rl)
|
||||
s64 ret = 0;
|
||||
|
||||
if (!rl) {
|
||||
ntfs_log_trace("Invalid argument passed.\n");
|
||||
errno = EINVAL;
|
||||
ntfs_log_perror("%s: ", __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (rlc = rl; rlc->length; rlc++) {
|
||||
if (rlc->lcn < 0) {
|
||||
if (rlc->lcn != LCN_HOLE) {
|
||||
ntfs_log_trace("Received unmapped runlist.\n");
|
||||
errno = EINVAL;
|
||||
ntfs_log_perror("%s: bad runlist", __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
} else
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
#include "attrib.h"
|
||||
#include "security.h"
|
||||
#include "misc.h"
|
||||
#include "bitmap.h"
|
||||
|
||||
/*
|
||||
* The zero GUID.
|
||||
@@ -338,3 +339,32 @@ int ntfs_sd_add_everyone(ntfs_inode *ni)
|
||||
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 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 */
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
* unistr.c - Unicode string handling. Originated from the Linux-NTFS project.
|
||||
*
|
||||
* 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
|
||||
* modify it under the terms of the GNU General Public License as published
|
||||
@@ -39,7 +41,11 @@
|
||||
#ifdef HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#ifdef HAVE_LOCALE_H
|
||||
#include <locale.h>
|
||||
#endif
|
||||
|
||||
#include "compat.h"
|
||||
#include "attrib.h"
|
||||
#include "types.h"
|
||||
#include "unistr.h"
|
||||
@@ -47,6 +53,8 @@
|
||||
#include "logging.h"
|
||||
#include "misc.h"
|
||||
|
||||
#define NOREVBOM 0 /* JPA rejecting U+FFFE and U+FFFF, open to debate */
|
||||
|
||||
/*
|
||||
* IMPORTANT
|
||||
* =========
|
||||
@@ -54,7 +62,9 @@
|
||||
* All these routines assume that the Unicode characters are in little endian
|
||||
* 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
|
||||
* 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);
|
||||
}
|
||||
|
||||
#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.
|
||||
* 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.
|
||||
* 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 out_len = outs_len;
|
||||
int out_len = 0;
|
||||
if(ntfs_duputf82uni((unsigned char*)ins,in_len,outs,&out_len)==0)
|
||||
return out_len;
|
||||
else
|
||||
@@ -620,6 +949,8 @@ int ntfs_ucstombs(const ntfschar *ins, const int ins_len, char **outs,
|
||||
errno = ENAMETOOLONG;
|
||||
return -1;
|
||||
}
|
||||
if (use_utf8)
|
||||
return ntfs_utf16_to_utf8(ins, ins_len, outs, outs_len);
|
||||
if (!mbs) {
|
||||
mbs_len = (ins_len + 1) * MB_CUR_MAX;
|
||||
mbs = ntfs_malloc(mbs_len);
|
||||
@@ -692,17 +1023,16 @@ err_out:
|
||||
* ntfs_mbstoucs - convert a multibyte string to a little endian Unicode string
|
||||
* @ins: input multibyte string buffer
|
||||
* @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
|
||||
* corresponding little endian, 2-byte Unicode string.
|
||||
*
|
||||
* If *@outs is NULL, the function allocates the string and the caller is
|
||||
* responsible for calling free(*@outs); when finished with it.
|
||||
* The function allocates the string and the caller is responsible for calling
|
||||
* free(*@outs); when finished with it.
|
||||
*
|
||||
* On success the function returns the number of Unicode characters written to
|
||||
* 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
|
||||
* error codes can be expected:
|
||||
@@ -712,7 +1042,7 @@ err_out:
|
||||
* ENAMETOOLONG Destination buffer is too small for input string.
|
||||
* 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;
|
||||
const char *s;
|
||||
@@ -726,12 +1056,10 @@ int ntfs_mbstoucs(const char *ins, ntfschar **outs, int outs_len)
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
ucs = *outs;
|
||||
ucs_len = outs_len;
|
||||
if (ucs && !ucs_len) {
|
||||
errno = ENAMETOOLONG;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (use_utf8)
|
||||
return ntfs_utf8_to_utf16(ins, outs);
|
||||
|
||||
/* Determine the size of the multi-byte string in bytes. */
|
||||
ins_size = strlen(ins);
|
||||
/* 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. */
|
||||
ins_len++;
|
||||
if (!ucs) {
|
||||
ucs_len = ins_len;
|
||||
ucs = ntfs_malloc(ucs_len * sizeof(ntfschar));
|
||||
if (!ucs)
|
||||
return -1;
|
||||
}
|
||||
#ifdef HAVE_MBSINIT
|
||||
memset(&mbstate, 0, sizeof(mbstate));
|
||||
#else
|
||||
mbtowc(NULL, NULL, 0);
|
||||
#endif
|
||||
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) {
|
||||
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;
|
||||
tc = (ntfschar*)realloc(ucs, ucs_len);
|
||||
tc = realloc(ucs, ucs_len);
|
||||
if (!tc)
|
||||
goto err_out;
|
||||
ucs = tc;
|
||||
@@ -827,19 +1145,14 @@ int ntfs_mbstoucs(const char *ins, ntfschar **outs, int outs_len)
|
||||
#endif
|
||||
/* Now write the NULL character. */
|
||||
ucs[o] = cpu_to_le16(L'\0');
|
||||
if (*outs != ucs)
|
||||
*outs = ucs;
|
||||
return o;
|
||||
err_out:
|
||||
if (ucs != *outs) {
|
||||
int eo = errno;
|
||||
free(ucs);
|
||||
errno = eo;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif // defined(__BEOS__) || defined(__HAIKU__)
|
||||
#endif //__HAIKU__
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
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);
|
||||
return NULL;
|
||||
}
|
||||
@@ -958,3 +1271,26 @@ void ntfs_ucsfree(ntfschar *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,
|
||||
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);
|
||||
|
||||
|
||||
@@ -112,8 +112,6 @@ static int ntfs_device_unix_io_open(struct ntfs_device *dev, int flags)
|
||||
if ((flags & O_RDWR) != O_RDWR)
|
||||
NDevSetReadOnly(dev);
|
||||
|
||||
/* locking not implemented in BeOS */
|
||||
#if !defined(__BEOS__) && !defined(__HAIKU__)
|
||||
memset(&flk, 0, sizeof(flk));
|
||||
if (NDevReadOnly(dev))
|
||||
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);
|
||||
goto err_out;
|
||||
}
|
||||
#endif
|
||||
|
||||
NDevSetOpen(dev);
|
||||
return 0;
|
||||
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);
|
||||
return -1;
|
||||
}
|
||||
/* locking not implemented in BeOS */
|
||||
#if !defined(__BEOS__) && !defined(__HAIKU__)
|
||||
|
||||
memset(&flk, 0, sizeof(flk));
|
||||
flk.l_type = F_UNLCK;
|
||||
flk.l_whence = SEEK_SET;
|
||||
flk.l_start = flk.l_len = 0LL;
|
||||
if (fcntl(DEV_FD(dev), F_SETLK, &flk))
|
||||
ntfs_log_perror("Could not unlock %s", dev->d_name);
|
||||
#endif
|
||||
if (close(DEV_FD(dev))) {
|
||||
ntfs_log_perror("Failed to close device %s", dev->d_name);
|
||||
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,
|
||||
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);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -273,11 +265,7 @@ static s64 ntfs_device_unix_io_pwrite(struct ntfs_device *dev, const void *buf,
|
||||
return -1;
|
||||
}
|
||||
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);
|
||||
#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.
|
||||
*
|
||||
* Copyright (c) 2000-2006 Anton Altaparmakov
|
||||
* Copyright (c) 2002-2006 Szabolcs Szakacsits
|
||||
* Copyright (c) 2002-2009 Szabolcs Szakacsits
|
||||
* Copyright (c) 2004-2005 Richard Russon
|
||||
*
|
||||
* This program/include file is free software; you can redistribute it and/or
|
||||
@@ -49,7 +49,11 @@
|
||||
#ifdef HAVE_LIMITS_H
|
||||
#include <limits.h>
|
||||
#endif
|
||||
#ifdef HAVE_LOCALE_H
|
||||
#include <locale.h>
|
||||
#endif
|
||||
|
||||
#include "compat.h"
|
||||
#include "volume.h"
|
||||
#include "attrib.h"
|
||||
#include "mft.h"
|
||||
@@ -63,9 +67,51 @@
|
||||
#include "logging.h"
|
||||
#include "misc.h"
|
||||
|
||||
#ifndef PATH_MAX
|
||||
#define PATH_MAX 4096
|
||||
#endif
|
||||
const char *ntfs_home =
|
||||
"Ntfs-3g news, support and information: http://ntfs-3g.org\n";
|
||||
|
||||
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
|
||||
@@ -76,17 +122,15 @@
|
||||
*/
|
||||
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)
|
||||
{
|
||||
if (na && *na) {
|
||||
ntfs_attr_close(*na);
|
||||
*na = NULL;
|
||||
} else
|
||||
ntfs_log_error("Tried to free NULL attribute pointer (%p)\n", na);
|
||||
}
|
||||
}
|
||||
|
||||
static int ntfs_inode_free(ntfs_inode **ni)
|
||||
@@ -96,8 +140,7 @@ static int ntfs_inode_free(ntfs_inode **ni)
|
||||
if (ni && *ni) {
|
||||
ret = ntfs_inode_close(*ni);
|
||||
*ni = NULL;
|
||||
} else
|
||||
ntfs_log_error("Tried to free NULL inode pointer (%p)\n", ni);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -211,25 +254,14 @@ static int ntfs_mft_load(ntfs_volume *vol)
|
||||
ntfs_log_perror("Error reading $MFT");
|
||||
goto error_exit;
|
||||
}
|
||||
if (ntfs_is_baad_record(mb->magic)) {
|
||||
ntfs_log_error("Incomplete multi sector transfer detected in "
|
||||
"$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");
|
||||
|
||||
if (ntfs_mft_record_check(vol, 0, mb))
|
||||
goto error_exit;
|
||||
}
|
||||
if (p2n(ctx->attr) < p2n(mb) ||
|
||||
(char*)ctx->attr > (char*)mb + vol->mft_record_size) {
|
||||
ntfs_log_error("$MFT is corrupt.\n");
|
||||
goto io_error_exit;
|
||||
}
|
||||
|
||||
ctx = ntfs_attr_get_search_ctx(vol->mft_ni, NULL);
|
||||
if (!ctx)
|
||||
goto error_exit;
|
||||
|
||||
/* Find the $ATTRIBUTE_LIST attribute in $MFT if present. */
|
||||
if (ntfs_attr_lookup(AT_ATTRIBUTE_LIST, AT_UNNAMED, 0, 0, 0, NULL, 0,
|
||||
ctx)) {
|
||||
@@ -429,13 +461,10 @@ ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev, unsigned long flags)
|
||||
ntfs_volume *vol;
|
||||
NTFS_BOOT_SECTOR *bs;
|
||||
int eo;
|
||||
#ifdef DEBUG
|
||||
const char *OK = "OK\n";
|
||||
const char *FAILED = "FAILED\n";
|
||||
#endif
|
||||
|
||||
if (!dev || !dev->d_ops || !dev->d_name) {
|
||||
errno = EINVAL;
|
||||
ntfs_log_perror("%s: dev = %p", __FUNCTION__, dev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -447,6 +476,7 @@ ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev, unsigned long flags)
|
||||
vol = ntfs_volume_alloc();
|
||||
if (!vol)
|
||||
goto error_exit;
|
||||
|
||||
/* Create the default upcase table. */
|
||||
vol->upcase_len = 65536;
|
||||
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,
|
||||
vol->upcase_len * sizeof(ntfschar));
|
||||
|
||||
if (flags & MS_RDONLY)
|
||||
NVolSetReadOnly(vol);
|
||||
if (flags & MS_NOATIME)
|
||||
NVolSetNoATime(vol);
|
||||
ntfs_log_debug("Reading bootsector... ");
|
||||
if (dev->d_ops->open(dev, NVolReadOnly(vol) ? O_RDONLY: O_RDWR)) {
|
||||
ntfs_log_debug(FAILED);
|
||||
ntfs_log_perror("Error opening partition device");
|
||||
|
||||
/* ...->open needs bracketing to compile with glibc 2.7 */
|
||||
if ((dev->d_ops->open)(dev, NVolReadOnly(vol) ? O_RDONLY: O_RDWR)) {
|
||||
ntfs_log_perror("Error opening '%s'", dev->d_name);
|
||||
goto error_exit;
|
||||
}
|
||||
/* Attach the device to the volume. */
|
||||
vol->dev = dev;
|
||||
|
||||
/* Now read the bootsector. */
|
||||
br = ntfs_pread(dev, 0, sizeof(NTFS_BOOT_SECTOR), bs);
|
||||
if (br != sizeof(NTFS_BOOT_SECTOR)) {
|
||||
ntfs_log_debug(FAILED);
|
||||
if (br != -1)
|
||||
errno = EINVAL;
|
||||
if (!br)
|
||||
ntfs_log_error("Partition is smaller than bootsector "
|
||||
"size.\n");
|
||||
ntfs_log_error("Failed to read bootsector (size=0)\n");
|
||||
else
|
||||
ntfs_log_perror("Error reading bootsector");
|
||||
goto error_exit;
|
||||
}
|
||||
ntfs_log_debug(OK);
|
||||
if (!ntfs_boot_sector_is_ntfs(bs)) {
|
||||
errno = EINVAL;
|
||||
goto error_exit;
|
||||
@@ -498,9 +525,7 @@ ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev, unsigned long flags)
|
||||
"%s\n", strerror(errno));
|
||||
|
||||
/* We now initialize the cluster allocator. */
|
||||
|
||||
mft_zone_size = min(vol->nr_clusters >> 3, /* 12.5% */
|
||||
200 * 1000 * 1024 >> vol->cluster_size_bits);
|
||||
mft_zone_size = vol->nr_clusters >> 3; /* 12.5% */
|
||||
|
||||
/* Setup the mft zone. */
|
||||
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.
|
||||
*/
|
||||
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;
|
||||
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. */
|
||||
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. */
|
||||
ntfs_log_debug("Loading $MFT... ");
|
||||
if (ntfs_mft_load(vol) < 0) {
|
||||
ntfs_log_debug(FAILED);
|
||||
ntfs_log_perror("Failed to load $MFT");
|
||||
goto error_exit;
|
||||
}
|
||||
ntfs_log_debug(OK);
|
||||
|
||||
/* Need to setup $MFTMirr so we can use the write functions, too. */
|
||||
ntfs_log_debug("Loading $MFTMirr... ");
|
||||
if (ntfs_mftmirr_load(vol) < 0) {
|
||||
ntfs_log_debug(FAILED);
|
||||
ntfs_log_perror("Failed to load $MFTMirr");
|
||||
goto error_exit;
|
||||
}
|
||||
ntfs_log_debug(OK);
|
||||
return vol;
|
||||
error_exit:
|
||||
eo = errno;
|
||||
@@ -646,7 +665,7 @@ static ntfs_inode *ntfs_hiberfile_open(ntfs_volume *vol)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
unicode_len = ntfs_mbstoucs(hiberfile, &unicode, 0);
|
||||
unicode_len = ntfs_mbstoucs(hiberfile, &unicode);
|
||||
if (unicode_len < 0) {
|
||||
ntfs_log_perror("Couldn't convert 'hiberfil.sys' to Unicode");
|
||||
goto out;
|
||||
@@ -684,11 +703,11 @@ out:
|
||||
* Return: 0 if Windows isn't hibernated for sure
|
||||
* -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_attr *na = NULL;
|
||||
int i, bytes_read, err;
|
||||
int bytes_read, err;
|
||||
char *buf = NULL;
|
||||
|
||||
ni = ntfs_hiberfile_open(vol);
|
||||
@@ -714,23 +733,18 @@ static int ntfs_volume_check_hiberfile(ntfs_volume *vol)
|
||||
goto out;
|
||||
}
|
||||
if (bytes_read < NTFS_HIBERFILE_HEADER_SIZE) {
|
||||
ntfs_log_error("Hibernated non-system partition, refused to "
|
||||
"mount.\n");
|
||||
if (verbose)
|
||||
ntfs_log_error("Hibernated non-system partition, "
|
||||
"refused to mount.\n");
|
||||
errno = EPERM;
|
||||
goto out;
|
||||
}
|
||||
if (memcmp(buf, "hibr", 4) == 0) {
|
||||
if (verbose)
|
||||
ntfs_log_error("Windows is hibernated, refused to mount.\n");
|
||||
errno = EPERM;
|
||||
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 */
|
||||
errno = 0;
|
||||
out:
|
||||
@@ -753,10 +767,9 @@ out:
|
||||
* to mount as the ntfs volume.
|
||||
*
|
||||
* @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
|
||||
* are implemented:
|
||||
* the mount system call (man 2 mount). Currently only the following flag
|
||||
* is implemented:
|
||||
* 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
|
||||
* 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)
|
||||
{
|
||||
s64 l;
|
||||
#ifdef DEBUG
|
||||
const char *OK = "OK\n";
|
||||
const char *FAILED = "FAILED\n";
|
||||
#endif
|
||||
ntfs_volume *vol;
|
||||
u8 *m = NULL, *m2 = 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;
|
||||
|
||||
vol = ntfs_volume_startup(dev, flags);
|
||||
if (!vol) {
|
||||
ntfs_log_perror("Failed to startup volume");
|
||||
if (!vol)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Load data from $MFT and $MFTMirr and compare the contents. */
|
||||
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;
|
||||
}
|
||||
ntfs_log_debug("Comparing $MFTMirr to $MFT... ");
|
||||
ntfs_log_debug("Comparing $MFTMirr to $MFT...\n");
|
||||
for (i = 0; i < vol->mftmirr_size; ++i) {
|
||||
MFT_RECORD *mrec, *mrec2;
|
||||
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);
|
||||
if (mrec->flags & MFT_RECORD_IN_USE) {
|
||||
if (ntfs_is_baad_recordp(mrec)) {
|
||||
ntfs_log_debug("FAILED\n");
|
||||
ntfs_log_error("$MFT error: Incomplete multi "
|
||||
"sector transfer detected in "
|
||||
"'%s'.\n", s);
|
||||
goto io_error_exit;
|
||||
}
|
||||
if (!ntfs_is_mft_recordp(mrec)) {
|
||||
ntfs_log_debug("FAILED\n");
|
||||
ntfs_log_error("$MFT error: Invalid mft "
|
||||
"record for '%s'.\n", s);
|
||||
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);
|
||||
if (mrec2->flags & MFT_RECORD_IN_USE) {
|
||||
if (ntfs_is_baad_recordp(mrec2)) {
|
||||
ntfs_log_debug("FAILED\n");
|
||||
ntfs_log_error("$MFTMirr error: Incomplete "
|
||||
"multi sector transfer "
|
||||
"detected in '%s'.\n", s);
|
||||
goto io_error_exit;
|
||||
}
|
||||
if (!ntfs_is_mft_recordp(mrec2)) {
|
||||
ntfs_log_debug("FAILED\n");
|
||||
ntfs_log_error("$MFTMirr error: Invalid mft "
|
||||
"record for '%s'.\n", s);
|
||||
goto io_error_exit;
|
||||
}
|
||||
}
|
||||
if (memcmp(mrec, mrec2, ntfs_mft_record_get_data_size(mrec))) {
|
||||
ntfs_log_debug(FAILED);
|
||||
ntfs_log_error("$MFTMirr does not match $MFT (record "
|
||||
"%d).\n", i);
|
||||
goto io_error_exit;
|
||||
}
|
||||
}
|
||||
ntfs_log_debug(OK);
|
||||
|
||||
free(m2);
|
||||
free(m);
|
||||
m = m2 = NULL;
|
||||
|
||||
/* 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);
|
||||
if (!vol->lcnbmp_ni) {
|
||||
ntfs_log_debug(FAILED);
|
||||
ntfs_log_perror("Failed to open inode");
|
||||
ntfs_log_perror("Failed to open inode FILE_Bitmap");
|
||||
goto error_exit;
|
||||
}
|
||||
/* Get an ntfs attribute for $Bitmap/$DATA. */
|
||||
|
||||
vol->lcnbmp_na = ntfs_attr_open(vol->lcnbmp_ni, AT_DATA, AT_UNNAMED, 0);
|
||||
if (!vol->lcnbmp_na) {
|
||||
ntfs_log_debug(FAILED);
|
||||
ntfs_log_perror("Failed to open ntfs attribute");
|
||||
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. */
|
||||
ntfs_log_debug("Loading $UpCase... ");
|
||||
ntfs_log_debug("Loading $UpCase...\n");
|
||||
ni = ntfs_inode_open(vol, FILE_UpCase);
|
||||
if (!ni) {
|
||||
ntfs_log_debug(FAILED);
|
||||
ntfs_log_perror("Failed to open inode");
|
||||
ntfs_log_perror("Failed to open inode FILE_UpCase");
|
||||
goto error_exit;
|
||||
}
|
||||
/* Get an ntfs attribute for $UpCase/$DATA. */
|
||||
na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
|
||||
if (!na) {
|
||||
ntfs_log_debug(FAILED);
|
||||
ntfs_log_perror("Failed to open ntfs attribute");
|
||||
goto error_exit;
|
||||
}
|
||||
@@ -919,7 +921,6 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags)
|
||||
* characters.
|
||||
*/
|
||||
if (na->data_size & ~0x1ffffffffULL) {
|
||||
ntfs_log_debug(FAILED);
|
||||
ntfs_log_error("Error: Upcase table is too big (max 32-bit "
|
||||
"allowed).\n");
|
||||
errno = EINVAL;
|
||||
@@ -930,15 +931,12 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags)
|
||||
/* Throw away default table. */
|
||||
free(vol->upcase);
|
||||
vol->upcase = ntfs_malloc(na->data_size);
|
||||
if (!vol->upcase) {
|
||||
ntfs_log_debug(FAILED);
|
||||
if (!vol->upcase)
|
||||
goto error_exit;
|
||||
}
|
||||
}
|
||||
/* Read in the $DATA attribute value into the buffer. */
|
||||
l = ntfs_attr_pread(na, 0, na->data_size, vol->upcase);
|
||||
if (l != na->data_size) {
|
||||
ntfs_log_debug(FAILED);
|
||||
ntfs_log_error("Failed to read $UpCase, unexpected length "
|
||||
"(%lld != %lld).\n", (long long)l,
|
||||
(long long)na->data_size);
|
||||
@@ -946,7 +944,6 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags)
|
||||
goto error_exit;
|
||||
}
|
||||
/* Done with the $UpCase mft record. */
|
||||
ntfs_log_debug(OK);
|
||||
ntfs_attr_close(na);
|
||||
if (ntfs_inode_close(ni)) {
|
||||
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
|
||||
* vol structure accordingly.
|
||||
*/
|
||||
ntfs_log_debug("Loading $Volume... ");
|
||||
ntfs_log_debug("Loading $Volume...\n");
|
||||
vol->vol_ni = ntfs_inode_open(vol, FILE_Volume);
|
||||
if (!vol->vol_ni) {
|
||||
ntfs_log_debug(FAILED);
|
||||
ntfs_log_perror("Failed to open inode");
|
||||
ntfs_log_perror("Failed to open inode FILE_Volume");
|
||||
goto error_exit;
|
||||
}
|
||||
/* Get a search context for the $Volume/$VOLUME_INFORMATION lookup. */
|
||||
ctx = ntfs_attr_get_search_ctx(vol->vol_ni, NULL);
|
||||
if (!ctx) {
|
||||
ntfs_log_debug(FAILED);
|
||||
ntfs_log_perror("Failed to allocate attribute search context");
|
||||
if (!ctx)
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
/* Find the $VOLUME_INFORMATION attribute. */
|
||||
if (ntfs_attr_lookup(AT_VOLUME_INFORMATION, AT_UNNAMED, 0, 0, 0, NULL,
|
||||
0, ctx)) {
|
||||
ntfs_log_debug(FAILED);
|
||||
ntfs_log_perror("$VOLUME_INFORMATION attribute not found in "
|
||||
"$Volume");
|
||||
goto error_exit;
|
||||
@@ -982,7 +975,6 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags)
|
||||
a = ctx->attr;
|
||||
/* Has to be resident. */
|
||||
if (a->non_resident) {
|
||||
ntfs_log_debug(FAILED);
|
||||
ntfs_log_error("Attribute $VOLUME_INFORMATION must be "
|
||||
"resident but it isn't.\n");
|
||||
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) ||
|
||||
le16_to_cpu(a->value_offset) + le32_to_cpu(
|
||||
a->value_length) > le32_to_cpu(a->length)) {
|
||||
ntfs_log_debug(FAILED);
|
||||
ntfs_log_error("$VOLUME_INFORMATION in $Volume is corrupt.\n");
|
||||
errno = EIO;
|
||||
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,
|
||||
ctx)) {
|
||||
if (errno != ENOENT) {
|
||||
ntfs_log_debug(FAILED);
|
||||
ntfs_log_perror("Failed to lookup of $VOLUME_NAME in "
|
||||
"$Volume failed");
|
||||
goto error_exit;
|
||||
@@ -1024,16 +1014,13 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags)
|
||||
* had zero length.
|
||||
*/
|
||||
vol->vol_name = ntfs_malloc(1);
|
||||
if (!vol->vol_name) {
|
||||
ntfs_log_debug(FAILED);
|
||||
if (!vol->vol_name)
|
||||
goto error_exit;
|
||||
}
|
||||
vol->vol_name[0] = '\0';
|
||||
} else {
|
||||
a = ctx->attr;
|
||||
/* Has to be resident. */
|
||||
if (a->non_resident) {
|
||||
ntfs_log_debug(FAILED);
|
||||
ntfs_log_error("$VOLUME_NAME must be resident.\n");
|
||||
errno = EIO;
|
||||
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 "
|
||||
"non-ASCII characters with underscores.\n");
|
||||
vol->vol_name = ntfs_malloc(u + 1);
|
||||
if (!vol->vol_name) {
|
||||
ntfs_log_debug(FAILED);
|
||||
if (!vol->vol_name)
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
for (j = 0; j < (s32)u; j++) {
|
||||
ntfschar uc = le16_to_cpu(vname[j]);
|
||||
if (uc > 0xff)
|
||||
@@ -1065,27 +1051,23 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags)
|
||||
vol->vol_name[u] = '\0';
|
||||
}
|
||||
}
|
||||
ntfs_log_debug(OK);
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
ctx = NULL;
|
||||
/* 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);
|
||||
if (!ni) {
|
||||
ntfs_log_debug(FAILED);
|
||||
ntfs_log_perror("Failed to open $AttrDef");
|
||||
goto error_exit;
|
||||
}
|
||||
/* Get an ntfs attribute for $AttrDef/$DATA. */
|
||||
na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
|
||||
if (!na) {
|
||||
ntfs_log_debug(FAILED);
|
||||
ntfs_log_perror("Failed to open ntfs attribute");
|
||||
goto error_exit;
|
||||
}
|
||||
/* Check we don't overflow 32-bits. */
|
||||
if (na->data_size > 0xffffffffLL) {
|
||||
ntfs_log_debug(FAILED);
|
||||
ntfs_log_error("Attribute definition table is too big (max "
|
||||
"32-bit allowed).\n");
|
||||
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 = ntfs_malloc(na->data_size);
|
||||
if (!vol->attrdef) {
|
||||
ntfs_log_debug(FAILED);
|
||||
if (!vol->attrdef)
|
||||
goto error_exit;
|
||||
}
|
||||
/* Read in the $DATA attribute value into the buffer. */
|
||||
l = ntfs_attr_pread(na, 0, na->data_size, vol->attrdef);
|
||||
if (l != na->data_size) {
|
||||
ntfs_log_debug(FAILED);
|
||||
ntfs_log_error("Failed to read $AttrDef, unexpected length "
|
||||
"(%lld != %lld).\n", (long long)l,
|
||||
(long long)na->data_size);
|
||||
@@ -1108,7 +1087,6 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags)
|
||||
goto error_exit;
|
||||
}
|
||||
/* Done with the $AttrDef mft record. */
|
||||
ntfs_log_debug(OK);
|
||||
ntfs_attr_close(na);
|
||||
if (ntfs_inode_close(ni)) {
|
||||
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.
|
||||
*/
|
||||
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;
|
||||
if (ntfs_volume_check_logfile(vol) < 0) {
|
||||
if (!(flags & MS_FORCE))
|
||||
if (!(flags & MS_RECOVER))
|
||||
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))
|
||||
goto error_exit;
|
||||
}
|
||||
@@ -1154,9 +1134,8 @@ error_exit:
|
||||
*
|
||||
* @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
|
||||
* are implemented:
|
||||
* is implemented:
|
||||
* 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
|
||||
* 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. */
|
||||
ctx = ntfs_attr_get_search_ctx(vol->vol_ni, NULL);
|
||||
if (!ctx) {
|
||||
ntfs_log_perror("Failed to allocate attribute search context");
|
||||
if (!ctx)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ntfs_attr_lookup(AT_VOLUME_INFORMATION, AT_UNNAMED, 0, 0, 0, NULL,
|
||||
0, ctx)) {
|
||||
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;
|
||||
/* Write them to disk. */
|
||||
ntfs_inode_mark_dirty(vol->vol_ni);
|
||||
if (ntfs_inode_sync(vol->vol_ni)) {
|
||||
ntfs_log_perror("Error writing $Volume");
|
||||
if (ntfs_inode_sync(vol->vol_ni))
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
ret = 0; /* success */
|
||||
err_out:
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
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) 2004-2005 Richard Russon
|
||||
* 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
|
||||
* modify it under the terms of the GNU General Public License as published
|
||||
@@ -43,30 +43,21 @@
|
||||
#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.
|
||||
*/
|
||||
#ifndef MS_RDONLY
|
||||
#define MS_RDONLY 1
|
||||
#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
|
||||
|
||||
#ifndef MS_FORCE
|
||||
#define MS_FORCE 0x10000000
|
||||
#ifndef MS_RECOVER
|
||||
#define MS_RECOVER 0x10000000
|
||||
#endif
|
||||
|
||||
#define MS_IGNORE_HIBERFILE 0x20000000
|
||||
|
||||
/* Forward declaration */
|
||||
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);
|
||||
|
||||
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 -
|
||||
*
|
||||
@@ -98,7 +105,6 @@ typedef enum {
|
||||
NV_ReadOnly, /* 1: Volume is read-only. */
|
||||
NV_CaseSensitive, /* 1: Volume is mounted case-sensitive. */
|
||||
NV_LogFileEmpty, /* 1: $logFile journal is empty. */
|
||||
NV_NoATime, /* 1: Do not update access time. */
|
||||
} ntfs_volume_state_bits;
|
||||
|
||||
#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 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 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
|
||||
bytes. */
|
||||
|
||||
/* Temp: for directory handling */
|
||||
void *private_data; /* ntfs_dir for . */
|
||||
void *private_bmp1; /* ntfs_bmp for $MFT/$BITMAP */
|
||||
void *private_bmp2; /* ntfs_bmp for $Bitmap */
|
||||
s64 free_clusters; /* Track the number of free clusters which
|
||||
greatly improves statfs() performance */
|
||||
s64 free_mft_records; /* Same for free mft records (see above) */
|
||||
};
|
||||
|
||||
extern const char *ntfs_home;
|
||||
|
||||
extern ntfs_volume *ntfs_volume_alloc(void);
|
||||
|
||||
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_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_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 */
|
||||
|
||||
|
||||
@@ -52,6 +52,10 @@ typedef struct ntfs_volume ntfs_volume;
|
||||
#include "types.h"
|
||||
#include "device.h"
|
||||
|
||||
#ifndef MAX_PATH
|
||||
#define MAX_PATH 1024
|
||||
#endif
|
||||
|
||||
#ifndef NTFS_BLOCK_SIZE
|
||||
#define NTFS_BLOCK_SIZE 512
|
||||
#define NTFS_BLOCK_SIZE_BITS 9
|
||||
|
||||
@@ -5,54 +5,9 @@
|
||||
|
||||
#include <lock.h>
|
||||
|
||||
#ifdef __HAIKU__
|
||||
|
||||
typedef recursive_lock lock;
|
||||
|
||||
#define LOCK(l) recursive_lock_lock(&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
|
||||
|
||||
@@ -24,8 +24,6 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef __HAIKU__
|
||||
|
||||
#include <fs_interface.h>
|
||||
#include <kernel/lock.h>
|
||||
#include <fs_info.h>
|
||||
@@ -38,15 +36,6 @@ extern "C" {
|
||||
#include <NodeMonitor.h>
|
||||
#include <util/kernel_cpp.h>
|
||||
|
||||
#else
|
||||
|
||||
#include "fsproto.h"
|
||||
#include "lock.h"
|
||||
|
||||
#define publish_vnode new_vnode
|
||||
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
#include "attrib.h"
|
||||
#include "inode.h"
|
||||
@@ -56,7 +45,6 @@ extern "C" {
|
||||
#include "layout.h"
|
||||
#include "index.h"
|
||||
#include "utils.h"
|
||||
#include "version.h"
|
||||
#include "ntfstime.h"
|
||||
#include "misc.h"
|
||||
#include "utils.h"
|
||||
@@ -111,16 +99,10 @@ typedef struct nspace
|
||||
{
|
||||
ntfs_volume *ntvol;
|
||||
char devicePath[MAX_PATH];
|
||||
#ifdef __HAIKU__
|
||||
dev_t id;
|
||||
#else
|
||||
nspace_id id;
|
||||
#endif
|
||||
int free_cluster_count;
|
||||
char volumeLabel[MAX_PATH];
|
||||
|
||||
ulong flags;
|
||||
|
||||
int state;
|
||||
s64 free_clusters;
|
||||
long free_mft;
|
||||
@@ -131,10 +113,7 @@ typedef struct nspace
|
||||
BOOL debug;
|
||||
BOOL noatime;
|
||||
BOOL no_detach;
|
||||
|
||||
|
||||
lock vlock;
|
||||
|
||||
} nspace;
|
||||
|
||||
|
||||
|
||||
@@ -38,10 +38,6 @@
|
||||
#include "ntfsdir.h"
|
||||
|
||||
//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,
|
||||
const int name_len, const int name_type, const s64 pos,
|
||||
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;
|
||||
return -1;
|
||||
} else {
|
||||
if (ntfs_ucstombs(name, name_len, &filename, 0) < 0)
|
||||
return -1;
|
||||
if (ntfs_ucstombs(name, name_len, &filename, 0) >= 0) {
|
||||
if(filename) {
|
||||
strcpy(cookie->name,filename);
|
||||
cookie->ino=MREF(mref);
|
||||
cookie->readed = 1;
|
||||
free(filename);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -114,6 +114,7 @@ fs_opendir( fs_volume *_vol, fs_vnode *_node, void** _cookie )
|
||||
cookie->pos = 0;
|
||||
cookie->ino = 0;
|
||||
cookie->readed = 0;
|
||||
cookie->last = 0;
|
||||
cookie->name[0] = 0;
|
||||
cookie->show_sys_files = ns->show_sys_files;
|
||||
*_cookie = (void*)cookie;
|
||||
@@ -159,36 +160,37 @@ fs_readdir( fs_volume *_vol, fs_vnode *_node, void *_cookie, struct dirent *buf,
|
||||
|
||||
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)) {
|
||||
result = EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if(cookie->readed == 1) {
|
||||
if(cookie->readed == 1 || cookie->last == 1) {
|
||||
result = ENOENT;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ni = ntfs_inode_open(ns->ntvol, node->vnid);
|
||||
if(ni==NULL) {
|
||||
ERRPRINT("fs_readdir - Dir not opened\n");
|
||||
ERRPRINT("fs_readdir - dir not opened\n");
|
||||
result = ENOENT;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
result = ntfs_readdir(ni, &cookie->pos, cookie, (ntfs_filldir_t)_ntfs_dirent_filler);
|
||||
if(result==0) {
|
||||
|
||||
realLen = nameLength>255?255:nameLength;
|
||||
buf->d_dev = ns->id;
|
||||
buf->d_ino = cookie->ino;
|
||||
memcpy(buf->d_name,cookie->name, realLen+1);
|
||||
buf->d_reclen = sizeof(buf) + realLen - 1;
|
||||
|
||||
if(result==0)
|
||||
cookie->last = 1;
|
||||
|
||||
result = B_NO_ERROR;
|
||||
}
|
||||
else
|
||||
result = ENOENT;
|
||||
|
||||
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->ino = 0;
|
||||
cookie->readed = 0;
|
||||
cookie->last = 0;
|
||||
cookie->name[0] = 0;
|
||||
result = B_NO_ERROR;
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ typedef struct dircookie
|
||||
{
|
||||
u64 pos;
|
||||
int readed;
|
||||
int last;
|
||||
ino_t ino;
|
||||
BOOL show_sys_files;
|
||||
char name[MAX_PATH];
|
||||
|
||||
@@ -4,5 +4,5 @@
|
||||
# /boot/home/config/settings/kernel/drivers/
|
||||
#
|
||||
hide_sys_files true
|
||||
read_only true
|
||||
read_only false
|
||||
no_atime true
|
||||
|
||||
@@ -69,12 +69,10 @@
|
||||
#include "volume.h"
|
||||
#include "debug.h"
|
||||
#include "dir.h"
|
||||
#include "version.h"
|
||||
#include "logging.h"
|
||||
#include "misc.h"
|
||||
|
||||
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 "
|
||||
"General Public License\nand you are welcome to redistribute it under "
|
||||
"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"
|
||||
"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
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
#include "inode.h"
|
||||
#include "runlist.h"
|
||||
#include "utils.h"
|
||||
#include "version.h"
|
||||
#include "ntfs.h"
|
||||
#include "volume_util.h"
|
||||
|
||||
@@ -166,7 +165,7 @@ int ntfs_change_label(ntfs_volume *vol, char *label)
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
label_len = ntfs_mbstoucs(label, &new_label, 0);
|
||||
label_len = ntfs_mbstoucs(label, &new_label);
|
||||
if (label_len == -1) {
|
||||
ntfs_log_perror("Unable to convert label string to Unicode");
|
||||
goto err_out;
|
||||
|
||||
Reference in New Issue
Block a user