Adapted to ntfs-3g.1.2216
parent
427c0dc48f
commit
a38b79897d
|
@ -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;
|
||||
|
@ -118,7 +115,7 @@ extern INDEX_ENTRY *ntfs_index_next(INDEX_ENTRY *ie,
|
|||
|
||||
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);
|
||||
|
||||
|
|
|
@ -1,3 +1,26 @@
|
|||
/*
|
||||
* misc.h : miscellaneous exports
|
||||
* - memory allocation
|
||||
* - LRU caches
|
||||
*
|
||||
* Copyright (c) 2008 Jean-Pierre Andre
|
||||
*
|
||||
* 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_MISC_H_
|
||||
#define _NTFS_MISC_H_
|
||||
|
||||
|
|
|
@ -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-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
|
||||
|
@ -60,6 +60,8 @@
|
|||
#define MS_FORCE 0x10000000
|
||||
#endif
|
||||
|
||||
#define MS_IGNORE_HIBERFILE 0x20000000
|
||||
|
||||
/* Forward declaration */
|
||||
typedef struct _ntfs_volume ntfs_volume;
|
||||
|
||||
|
@ -95,7 +97,8 @@ typedef enum {
|
|||
NTFS_VOLUME_UNKNOWN_REASON = 18,
|
||||
NTFS_VOLUME_NO_PRIVILEGE = 19,
|
||||
NTFS_VOLUME_OUT_OF_MEMORY = 20,
|
||||
NTFS_VOLUME_FUSE_ERROR = 21
|
||||
NTFS_VOLUME_FUSE_ERROR = 21,
|
||||
NTFS_VOLUME_INSECURE = 22
|
||||
} ntfs_volume_status;
|
||||
|
||||
/**
|
||||
|
@ -254,6 +257,7 @@ 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);
|
||||
|
|
|
@ -1493,7 +1493,6 @@ int ntfs_delete(ntfs_volume *vol, const char *pathname,
|
|||
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;
|
||||
|
@ -1593,19 +1592,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))
|
||||
|
@ -1676,8 +1663,6 @@ ok:
|
|||
out:
|
||||
if (actx)
|
||||
ntfs_attr_put_search_ctx(actx);
|
||||
if (ictx)
|
||||
ntfs_index_ctx_put(ictx);
|
||||
if (ntfs_inode_close(dir_ni) && !err)
|
||||
err = errno;
|
||||
if (ntfs_inode_close(ni) && !err)
|
||||
|
@ -1774,22 +1759,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,8 +4,8 @@
|
|||
* 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) 2007-2008 Jean-Pierre Andre
|
||||
* Copyright (c) 2005-2008 Szabolcs Szakacsits
|
||||
* Copyright (c) 2007 Jean-Pierre Andre
|
||||
*
|
||||
* 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
|
||||
|
@ -79,14 +79,14 @@ 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);
|
||||
|
||||
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, inode %llu",
|
||||
(long long)vcn, (unsigned long long)icx->ni->mft_no);
|
||||
|
@ -98,7 +98,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 +148,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->ib_dirty) {
|
||||
/* FIXME: Error handling!!! */
|
||||
ntfs_ib_write(icx, icx->ib_vcn, icx->ib);
|
||||
if (!icx->is_in_root) {
|
||||
if (icx->ib_dirty) {
|
||||
/* FIXME: Error handling!!! */
|
||||
ntfs_ib_write(icx, icx->ib);
|
||||
}
|
||||
free(icx->ib);
|
||||
}
|
||||
|
||||
free(icx->ib);
|
||||
ntfs_attr_close(icx->ia_na);
|
||||
}
|
||||
|
||||
|
@ -452,8 +448,10 @@ 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;
|
||||
}
|
||||
|
||||
|
@ -660,15 +658,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");
|
||||
|
@ -679,7 +675,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;
|
||||
|
@ -691,7 +687,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)
|
||||
|
@ -718,7 +714,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) {
|
||||
|
@ -764,7 +759,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;
|
||||
}
|
||||
|
||||
|
@ -777,20 +772,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;
|
||||
|
@ -1061,13 +1051,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;
|
||||
|
@ -1075,8 +1065,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)
|
||||
|
@ -1084,10 +1074,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;
|
||||
|
@ -1149,7 +1139,7 @@ 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);
|
||||
|
@ -1376,7 +1366,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;
|
||||
|
@ -1386,7 +1376,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.
|
||||
|
@ -1417,8 +1407,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;
|
||||
|
@ -1557,7 +1545,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);
|
||||
|
@ -1587,9 +1575,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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1667,7 +1652,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;
|
||||
|
@ -1689,6 +1674,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))
|
||||
|
@ -1706,9 +1692,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;
|
||||
}
|
||||
|
||||
|
@ -1730,18 +1715,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;
|
||||
}
|
||||
}
|
||||
|
@ -1752,7 +1737,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;
|
||||
|
@ -1763,7 +1747,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;
|
||||
|
@ -1784,10 +1768,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");
|
||||
|
||||
|
@ -1803,8 +1787,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)) {
|
||||
|
||||
|
@ -1821,16 +1804,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");
|
||||
return -1;
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -291,7 +291,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;
|
||||
|
|
|
@ -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-2008 Szabolcs Szakacsits
|
||||
* Copyright (c) 2004-2005 Richard Russon
|
||||
*
|
||||
* This program/include file is free software; you can redistribute it and/or
|
||||
|
@ -676,7 +676,7 @@ 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;
|
||||
|
@ -706,13 +706,15 @@ 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) {
|
||||
ntfs_log_error("Windows is hibernated, refused to mount.\n");
|
||||
if (verbose)
|
||||
ntfs_log_error("Windows is hibernated, refused to mount.\n");
|
||||
errno = EPERM;
|
||||
goto out;
|
||||
}
|
||||
|
@ -1099,7 +1101,8 @@ 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))
|
||||
|
|
412
src/ntfs-3g.c
412
src/ntfs-3g.c
|
@ -70,7 +70,6 @@
|
|||
#include <getopt.h>
|
||||
#include <syslog.h>
|
||||
#include <sys/wait.h>
|
||||
#include <pwd.h>
|
||||
|
||||
#ifdef HAVE_SETXATTR
|
||||
#include <sys/xattr.h>
|
||||
|
@ -130,6 +129,7 @@ typedef struct {
|
|||
BOOL show_sys_files;
|
||||
BOOL silent;
|
||||
BOOL force;
|
||||
BOOL hiberfile;
|
||||
BOOL debug;
|
||||
BOOL no_detach;
|
||||
BOOL blkdev;
|
||||
|
@ -167,13 +167,39 @@ static const char *usage_msg =
|
|||
"\n"
|
||||
"Usage: %s <device|image_file> <mount_point> [-o option[,...]]\n"
|
||||
"\n"
|
||||
"Options: ro, force, locale=, uid=, gid=, umask=, fmask=, dmask=,\n"
|
||||
" streams_interface=. Please see details in the manual.\n"
|
||||
"Options: ro (read-only mount), force, remove_hiberfile, locale=,\n"
|
||||
" uid=, gid=, umask=, fmask=, dmask=, streams_interface=.\n"
|
||||
" Please see the details in the manual.\n"
|
||||
"\n"
|
||||
"Example: ntfs-3g /dev/sda1 /mnt/win -o force\n"
|
||||
"\n"
|
||||
"%s";
|
||||
|
||||
#ifdef FUSE_INTERNAL
|
||||
int drop_privs(void);
|
||||
int restore_privs(void);
|
||||
#else
|
||||
/*
|
||||
* setuid and setgid root ntfs-3g denies to start with external FUSE,
|
||||
* therefore the below functions are no-op in such case.
|
||||
*/
|
||||
static int drop_privs(void) { return 0; }
|
||||
static int restore_privs(void) { return 0; }
|
||||
|
||||
static const char *setuid_msg =
|
||||
"Mount is denied because setuid and setgid root ntfs-3g is insecure with the\n"
|
||||
"external FUSE library. Either remove the setuid/setgid bit from the binary\n"
|
||||
"or rebuild NTFS-3G with integrated FUSE support and make it setuid root.\n"
|
||||
"Please see more information at http://ntfs-3g.org/support.html#unprivileged\n";
|
||||
|
||||
static const char *unpriv_fuseblk_msg =
|
||||
"Unprivileged user can not mount NTFS block devices using the external FUSE\n"
|
||||
"library. Either mount the volume as root, or rebuild NTFS-3G with integrated\n"
|
||||
"FUSE support and make it setuid root. Please see more information at\n"
|
||||
"http://ntfs-3g.org/support.html#unprivileged\n";
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* ntfs_fuse_is_named_data_stream - check path to be to named data stream
|
||||
* @path: path to check
|
||||
|
@ -1934,6 +1960,8 @@ static int ntfs_open(const char *device)
|
|||
flags |= MS_RDONLY;
|
||||
if (ctx->force)
|
||||
flags |= MS_FORCE;
|
||||
if (ctx->hiberfile)
|
||||
flags |= MS_IGNORE_HIBERFILE;
|
||||
|
||||
ctx->vol = ntfs_mount(device, flags);
|
||||
if (!ctx->vol) {
|
||||
|
@ -1953,81 +1981,111 @@ static int ntfs_open(const char *device)
|
|||
goto err_out;
|
||||
}
|
||||
|
||||
if (ctx->hiberfile && ntfs_volume_check_hiberfile(ctx->vol, 0)) {
|
||||
if (errno != EPERM)
|
||||
goto err_out;
|
||||
if (ntfs_fuse_rm("/hiberfil.sys"))
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
err_out:
|
||||
return ntfs_volume_error(errno);
|
||||
|
||||
}
|
||||
|
||||
#define STRAPPEND_MAX_INSIZE 8192
|
||||
#define strappend_is_large(x) ((x) > STRAPPEND_MAX_INSIZE)
|
||||
|
||||
static int strappend(char **dest, const char *append)
|
||||
{
|
||||
char *p;
|
||||
size_t size_append, size_dest = 0;
|
||||
|
||||
if (!dest)
|
||||
return -1;
|
||||
if (!append)
|
||||
return 0;
|
||||
|
||||
size_append = strlen(append);
|
||||
if (*dest)
|
||||
size_dest = strlen(*dest);
|
||||
|
||||
if (strappend_is_large(size_dest) || strappend_is_large(size_append)) {
|
||||
errno = EOVERFLOW;
|
||||
ntfs_log_perror("%s: Too large input buffer", EXEC_NAME);
|
||||
return -1;
|
||||
}
|
||||
|
||||
p = realloc(*dest, size_dest + size_append + 1);
|
||||
if (!p) {
|
||||
ntfs_log_perror("%s: Memory realloction failed", EXEC_NAME);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*dest = p;
|
||||
strcpy(*dest + size_dest, append);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bogus_option_value(char *val, const char *s)
|
||||
{
|
||||
if (val) {
|
||||
ntfs_log_error("'%s' option shouldn't have value.\n", s);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int missing_option_value(char *val, const char *s)
|
||||
{
|
||||
if (!val) {
|
||||
ntfs_log_error("'%s' option should have a value.\n", s);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *parse_mount_options(const char *orig_opts)
|
||||
{
|
||||
char *options, *s, *opt, *val, *ret;
|
||||
char *options, *s, *opt, *val, *ret = NULL;
|
||||
BOOL no_def_opts = FALSE;
|
||||
int default_permissions = 0;
|
||||
|
||||
/*
|
||||
* FIXME: This is not pretty ...
|
||||
* +7 fsname=
|
||||
* +1 comma
|
||||
* +1 null-terminator
|
||||
* +21 ,blkdev,blksize=65536
|
||||
* +20 ,default_permissions
|
||||
* +70 ,user=<max_64_chars>
|
||||
* +PATH_MAX resolved realpath() device name
|
||||
*/
|
||||
ret = ntfs_malloc(strlen(def_opts) + strlen(orig_opts) + 256 + PATH_MAX);
|
||||
if (!ret)
|
||||
return NULL;
|
||||
|
||||
*ret = 0;
|
||||
options = strdup(orig_opts);
|
||||
options = strdup(orig_opts ? orig_opts : "");
|
||||
if (!options) {
|
||||
ntfs_log_perror("strdup failed");
|
||||
ntfs_log_perror("%s: strdup failed", EXEC_NAME);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ctx->silent = TRUE;
|
||||
|
||||
ctx->atime = ATIME_RELATIVE;
|
||||
|
||||
ctx->atime = ATIME_RELATIVE;
|
||||
|
||||
s = options;
|
||||
while (s && *s && (val = strsep(&s, ","))) {
|
||||
opt = strsep(&val, "=");
|
||||
if (!strcmp(opt, "ro")) { /* Read-only mount. */
|
||||
if (val) {
|
||||
ntfs_log_error("'ro' option should not have "
|
||||
"value.\n");
|
||||
if (bogus_option_value(val, "ro"))
|
||||
goto err_exit;
|
||||
}
|
||||
ctx->ro = TRUE;
|
||||
strcat(ret, "ro,");
|
||||
} else if (!strcmp(opt, "noatime")) {
|
||||
if (val) {
|
||||
ntfs_log_error("'noatime' option should not "
|
||||
"have value.\n");
|
||||
if (strappend(&ret, "ro,"))
|
||||
goto err_exit;
|
||||
} else if (!strcmp(opt, "noatime")) {
|
||||
if (bogus_option_value(val, "noatime"))
|
||||
goto err_exit;
|
||||
}
|
||||
ctx->atime = ATIME_DISABLED;
|
||||
} else if (!strcmp(opt, "atime")) {
|
||||
if (val) {
|
||||
ntfs_log_error("'atime' option should not "
|
||||
"have value.\n");
|
||||
if (bogus_option_value(val, "atime"))
|
||||
goto err_exit;
|
||||
}
|
||||
ctx->atime = ATIME_ENABLED;
|
||||
} else if (!strcmp(opt, "relatime")) {
|
||||
if (val) {
|
||||
ntfs_log_error("'relatime' option should not "
|
||||
"have value.\n");
|
||||
if (bogus_option_value(val, "relatime"))
|
||||
goto err_exit;
|
||||
}
|
||||
ctx->atime = ATIME_RELATIVE;
|
||||
} else if (!strcmp(opt, "fake_rw")) {
|
||||
if (val) {
|
||||
ntfs_log_error("'fake_rw' option should not "
|
||||
"have value.\n");
|
||||
if (bogus_option_value(val, "fake_rw"))
|
||||
goto err_exit;
|
||||
}
|
||||
ctx->ro = TRUE;
|
||||
} else if (!strcmp(opt, "fsname")) { /* Filesystem name. */
|
||||
/*
|
||||
|
@ -2037,93 +2095,64 @@ static char *parse_mount_options(const char *orig_opts)
|
|||
ntfs_log_error("'fsname' is unsupported option.\n");
|
||||
goto err_exit;
|
||||
} else if (!strcmp(opt, "no_def_opts")) {
|
||||
if (val) {
|
||||
ntfs_log_error("'no_def_opts' option should "
|
||||
"not have value.\n");
|
||||
if (bogus_option_value(val, "no_def_opts"))
|
||||
goto err_exit;
|
||||
}
|
||||
no_def_opts = TRUE; /* Don't add default options. */
|
||||
} else if (!strcmp(opt, "default_permissions")) {
|
||||
default_permissions = 1;
|
||||
} else if (!strcmp(opt, "umask")) {
|
||||
if (!val) {
|
||||
ntfs_log_error("'umask' option should have "
|
||||
"value.\n");
|
||||
if (missing_option_value(val, "umask"))
|
||||
goto err_exit;
|
||||
}
|
||||
sscanf(val, "%o", &ctx->fmask);
|
||||
ctx->dmask = ctx->fmask;
|
||||
if (ctx->fmask)
|
||||
default_permissions = 1;
|
||||
} else if (!strcmp(opt, "fmask")) {
|
||||
if (!val) {
|
||||
ntfs_log_error("'fmask' option should have "
|
||||
"value.\n");
|
||||
if (missing_option_value(val, "fmask"))
|
||||
goto err_exit;
|
||||
}
|
||||
sscanf(val, "%o", &ctx->fmask);
|
||||
if (ctx->fmask)
|
||||
default_permissions = 1;
|
||||
} else if (!strcmp(opt, "dmask")) {
|
||||
if (!val) {
|
||||
ntfs_log_error("'dmask' option should have "
|
||||
"value.\n");
|
||||
if (missing_option_value(val, "dmask"))
|
||||
goto err_exit;
|
||||
}
|
||||
sscanf(val, "%o", &ctx->dmask);
|
||||
if (ctx->dmask)
|
||||
default_permissions = 1;
|
||||
} else if (!strcmp(opt, "uid")) {
|
||||
if (!val) {
|
||||
ntfs_log_error("'uid' option should have "
|
||||
"value.\n");
|
||||
if (missing_option_value(val, "uid"))
|
||||
goto err_exit;
|
||||
}
|
||||
sscanf(val, "%i", &ctx->uid);
|
||||
default_permissions = 1;
|
||||
} else if (!strcmp(opt, "gid")) {
|
||||
if (!val) {
|
||||
ntfs_log_error("'gid' option should have "
|
||||
"value.\n");
|
||||
if (missing_option_value(val, "gid"))
|
||||
goto err_exit;
|
||||
}
|
||||
sscanf(val, "%i", &ctx->gid);
|
||||
default_permissions = 1;
|
||||
} else if (!strcmp(opt, "show_sys_files")) {
|
||||
if (val) {
|
||||
ntfs_log_error("'show_sys_files' option should "
|
||||
"not have value.\n");
|
||||
if (bogus_option_value(val, "show_sys_files"))
|
||||
goto err_exit;
|
||||
}
|
||||
ctx->show_sys_files = TRUE;
|
||||
} else if (!strcmp(opt, "silent")) {
|
||||
if (val) {
|
||||
ntfs_log_error("'silent' option should "
|
||||
"not have value.\n");
|
||||
if (bogus_option_value(val, "silent"))
|
||||
goto err_exit;
|
||||
}
|
||||
ctx->silent = TRUE;
|
||||
} else if (!strcmp(opt, "force")) {
|
||||
if (val) {
|
||||
ntfs_log_error("'force' option should not "
|
||||
"have value.\n");
|
||||
if (bogus_option_value(val, "force"))
|
||||
goto err_exit;
|
||||
}
|
||||
ctx->force = TRUE;
|
||||
} else if (!strcmp(opt, "locale")) {
|
||||
if (!val) {
|
||||
ntfs_log_error("'locale' option should have "
|
||||
"value.\n");
|
||||
} else if (!strcmp(opt, "remove_hiberfile")) {
|
||||
if (bogus_option_value(val, "remove_hiberfile"))
|
||||
goto err_exit;
|
||||
ctx->hiberfile = TRUE;
|
||||
} else if (!strcmp(opt, "locale")) {
|
||||
if (missing_option_value(val, "locale"))
|
||||
goto err_exit;
|
||||
}
|
||||
if (!setlocale(LC_ALL, val))
|
||||
ntfs_log_error(locale_msg, val);
|
||||
} else if (!strcmp(opt, "streams_interface")) {
|
||||
if (!val) {
|
||||
ntfs_log_error("'streams_interface' option "
|
||||
"should have value.\n");
|
||||
if (missing_option_value(val, "streams_interface"))
|
||||
goto err_exit;
|
||||
}
|
||||
if (!strcmp(val, "none"))
|
||||
ctx->streams = NF_STREAMS_INTERFACE_NONE;
|
||||
else if (!strcmp(val, "xattr"))
|
||||
|
@ -2138,20 +2167,14 @@ static char *parse_mount_options(const char *orig_opts)
|
|||
} else if (!strcmp(opt, "noauto")) {
|
||||
/* Don't pass noauto option to fuse. */
|
||||
} else if (!strcmp(opt, "debug")) {
|
||||
if (val) {
|
||||
ntfs_log_error("'debug' option should not have "
|
||||
"value.\n");
|
||||
if (bogus_option_value(val, "debug"))
|
||||
goto err_exit;
|
||||
}
|
||||
ctx->debug = TRUE;
|
||||
ntfs_log_set_levels(NTFS_LOG_LEVEL_DEBUG);
|
||||
ntfs_log_set_levels(NTFS_LOG_LEVEL_TRACE);
|
||||
} else if (!strcmp(opt, "no_detach")) {
|
||||
if (val) {
|
||||
ntfs_log_error("'no_detach' option should not "
|
||||
"have value.\n");
|
||||
if (bogus_option_value(val, "no_detach"))
|
||||
goto err_exit;
|
||||
}
|
||||
ctx->no_detach = TRUE;
|
||||
} else if (!strcmp(opt, "remount")) {
|
||||
ntfs_log_error("Remounting is not supported at present."
|
||||
|
@ -2186,28 +2209,34 @@ static char *parse_mount_options(const char *orig_opts)
|
|||
goto err_exit;
|
||||
}
|
||||
} else { /* Probably FUSE option. */
|
||||
strcat(ret, opt);
|
||||
if (strappend(&ret, opt))
|
||||
goto err_exit;
|
||||
if (val) {
|
||||
strcat(ret, "=");
|
||||
strcat(ret, val);
|
||||
if (strappend(&ret, "="))
|
||||
goto err_exit;
|
||||
if (strappend(&ret, val))
|
||||
goto err_exit;
|
||||
}
|
||||
strcat(ret, ",");
|
||||
if (strappend(&ret, ","))
|
||||
goto err_exit;
|
||||
}
|
||||
}
|
||||
if (!no_def_opts)
|
||||
strcat(ret, def_opts);
|
||||
if (default_permissions)
|
||||
strcat(ret, "default_permissions,");
|
||||
if (!no_def_opts && strappend(&ret, def_opts))
|
||||
goto err_exit;
|
||||
if (default_permissions && strappend(&ret, "default_permissions,"))
|
||||
goto err_exit;
|
||||
|
||||
if (ctx->atime == ATIME_RELATIVE)
|
||||
strcat(ret, "relatime,");
|
||||
else if (ctx->atime == ATIME_ENABLED)
|
||||
strcat(ret, "atime,");
|
||||
else
|
||||
strcat(ret, "noatime,");
|
||||
if (ctx->atime == ATIME_RELATIVE && strappend(&ret, "relatime,"))
|
||||
goto err_exit;
|
||||
else if (ctx->atime == ATIME_ENABLED && strappend(&ret, "atime,"))
|
||||
goto err_exit;
|
||||
else if (strappend(&ret, "noatime,"))
|
||||
goto err_exit;
|
||||
|
||||
strcat(ret, "fsname=");
|
||||
strcat(ret, opts.device);
|
||||
if (strappend(&ret, "fsname="))
|
||||
goto err_exit;
|
||||
if (strappend(&ret, opts.device))
|
||||
goto err_exit;
|
||||
exit:
|
||||
free(options);
|
||||
return ret;
|
||||
|
@ -2233,35 +2262,6 @@ static char *realpath(const char *path, char *resolved_path)
|
|||
}
|
||||
#endif
|
||||
|
||||
static int strappend(char **dest, const char *append)
|
||||
{
|
||||
char *p;
|
||||
size_t size;
|
||||
|
||||
if (!dest)
|
||||
return -1;
|
||||
if (!append)
|
||||
return 0;
|
||||
|
||||
size = strlen(append) + 1;
|
||||
if (*dest)
|
||||
size += strlen(*dest);
|
||||
|
||||
p = realloc(*dest, size);
|
||||
if (!p) {
|
||||
ntfs_log_perror("Memory realloction failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (*dest)
|
||||
strcat(p, append);
|
||||
else
|
||||
strcpy(p, append);
|
||||
*dest = p;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* parse_options - Read and validate the programs command line
|
||||
* Read the command line, verify the syntax and parse the options.
|
||||
|
@ -2290,18 +2290,14 @@ static int parse_options(int argc, char *argv[])
|
|||
if (!opts.device)
|
||||
return -1;
|
||||
|
||||
/* We don't want relative path in /etc/mtab. */
|
||||
if (optarg[0] != '/') {
|
||||
if (!realpath(optarg, opts.device)) {
|
||||
ntfs_log_perror("%s: "
|
||||
"Cannot mount '%s'",
|
||||
EXEC_NAME, optarg);
|
||||
free(opts.device);
|
||||
opts.device = NULL;
|
||||
return -1;
|
||||
}
|
||||
} else
|
||||
strcpy(opts.device, optarg);
|
||||
/* Canonicalize device name (mtab, etc) */
|
||||
if (!realpath(optarg, opts.device)) {
|
||||
ntfs_log_perror("%s: Failed to access "
|
||||
"volume '%s'", EXEC_NAME, optarg);
|
||||
free(opts.device);
|
||||
opts.device = NULL;
|
||||
return -1;
|
||||
}
|
||||
} else if (!opts.mnt_point) {
|
||||
opts.mnt_point = optarg;
|
||||
} else {
|
||||
|
@ -2477,7 +2473,7 @@ free_args:
|
|||
|
||||
}
|
||||
|
||||
static void set_fuseblk_options(char *parsed_options)
|
||||
static int set_fuseblk_options(char **parsed_options)
|
||||
{
|
||||
char options[64];
|
||||
long pagesize;
|
||||
|
@ -2490,61 +2486,17 @@ static void set_fuseblk_options(char *parsed_options)
|
|||
if (blksize > (u32)pagesize)
|
||||
blksize = pagesize;
|
||||
|
||||
/* parsed_options already allocated enough space. */
|
||||
snprintf(options, sizeof(options), ",blkdev,blksize=%u", blksize);
|
||||
strcat(parsed_options, options);
|
||||
if (strappend(parsed_options, options))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void set_user_mount_option(char *parsed_options, uid_t uid)
|
||||
{
|
||||
struct passwd *pw;
|
||||
char option[64];
|
||||
|
||||
if (!uid)
|
||||
return;
|
||||
|
||||
errno = 0;
|
||||
pw = getpwuid(uid);
|
||||
if (!pw || !pw->pw_name) {
|
||||
ntfs_log_perror("WARNING: could not get username for uid %lld, "
|
||||
"unprivileged unmount may fail", (long long)uid);
|
||||
return;
|
||||
}
|
||||
|
||||
/* parsed_options already allocated enough space. */
|
||||
snprintf(option, sizeof(option), ",user=%s", pw->pw_name);
|
||||
strcat(parsed_options, option);
|
||||
}
|
||||
|
||||
#ifndef FUSE_INTERNAL
|
||||
static int set_uid(uid_t uid)
|
||||
{
|
||||
if (setuid(uid)) {
|
||||
ntfs_log_perror("Failed to set uid to %d", uid);
|
||||
return NTFS_VOLUME_NO_PRIVILEGE;
|
||||
}
|
||||
return NTFS_VOLUME_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct fuse *mount_fuse(char *parsed_options)
|
||||
{
|
||||
struct fuse *fh = NULL;
|
||||
struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
|
||||
#ifndef FUSE_INTERNAL
|
||||
uid_t uid, euid;
|
||||
|
||||
/*
|
||||
* We must raise privilege if possible, otherwise the user[s] fstab
|
||||
* option doesn't work because mount(8) always drops privilege what
|
||||
* the blkdev option requires.
|
||||
*/
|
||||
uid = getuid();
|
||||
euid = geteuid();
|
||||
|
||||
if (set_uid(euid))
|
||||
return NULL;
|
||||
#endif
|
||||
/* Libfuse can't always find fusermount, so let's help it. */
|
||||
if (setenv("PATH", ":/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin", 0))
|
||||
ntfs_log_perror("WARNING: Failed to set $PATH\n");
|
||||
|
@ -2576,15 +2528,6 @@ static struct fuse *mount_fuse(char *parsed_options)
|
|||
|
||||
if (fuse_set_signal_handlers(fuse_get_session(fh)))
|
||||
goto err_destory;
|
||||
/*
|
||||
* We can't drop privilege if internal FUSE is used because internal
|
||||
* unmount needs it. Kernel 2.6.25 may include unprivileged full
|
||||
* mount/unmount support.
|
||||
*/
|
||||
#ifndef FUSE_INTERNAL
|
||||
if (set_uid(uid))
|
||||
goto err_destory;
|
||||
#endif
|
||||
out:
|
||||
fuse_opt_free_args(&args);
|
||||
return fh;
|
||||
|
@ -2629,18 +2572,30 @@ int main(int argc, char *argv[])
|
|||
struct stat sbuf;
|
||||
int err;
|
||||
|
||||
#ifndef FUSE_INTERNAL
|
||||
if ((getuid() != geteuid()) || (getgid() != getegid())) {
|
||||
fprintf(stderr, "%s", setuid_msg);
|
||||
return NTFS_VOLUME_INSECURE;
|
||||
}
|
||||
#endif
|
||||
if (drop_privs())
|
||||
return NTFS_VOLUME_NO_PRIVILEGE;
|
||||
|
||||
utils_set_locale();
|
||||
ntfs_log_set_handler(ntfs_log_handler_stderr);
|
||||
|
||||
if (parse_options(argc, argv)) {
|
||||
usage();
|
||||
ntfs_log_error("Please type '%s --help' for more "
|
||||
"information.\n", argv[0]);
|
||||
return NTFS_VOLUME_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
if (ntfs_fuse_init())
|
||||
return NTFS_VOLUME_OUT_OF_MEMORY;
|
||||
if (ntfs_fuse_init()) {
|
||||
err = NTFS_VOLUME_OUT_OF_MEMORY;
|
||||
goto err2;
|
||||
}
|
||||
|
||||
parsed_options = parse_mount_options(opts.options ? opts.options : "");
|
||||
parsed_options = parse_mount_options(opts.options);
|
||||
if (!parsed_options) {
|
||||
err = NTFS_VOLUME_SYNTAX_ERROR;
|
||||
goto err_out;
|
||||
|
@ -2648,10 +2603,18 @@ int main(int argc, char *argv[])
|
|||
|
||||
#if defined(linux) || defined(__uClinux__)
|
||||
fstype = get_fuse_fstype();
|
||||
|
||||
err = NTFS_VOLUME_NO_PRIVILEGE;
|
||||
if (restore_privs())
|
||||
goto err_out;
|
||||
|
||||
if (fstype == FSTYPE_NONE || fstype == FSTYPE_UNKNOWN)
|
||||
fstype = load_fuse_module();
|
||||
|
||||
create_dev_fuse();
|
||||
|
||||
if (drop_privs())
|
||||
goto err_out;
|
||||
#endif
|
||||
|
||||
if (stat(opts.device, &sbuf)) {
|
||||
|
@ -2663,15 +2626,19 @@ int main(int argc, char *argv[])
|
|||
if (S_ISBLK(sbuf.st_mode) && (fstype != FSTYPE_FUSE))
|
||||
ctx->blkdev = TRUE;
|
||||
|
||||
#ifndef FUSE_INTERNAL
|
||||
if (getuid() && ctx->blkdev) {
|
||||
ntfs_log_error("%s", unpriv_fuseblk_msg);
|
||||
goto err2;
|
||||
}
|
||||
#endif
|
||||
err = ntfs_open(opts.device);
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
if (ctx->blkdev) {
|
||||
/* Must do after ntfs_open() to set the right blksize. */
|
||||
set_fuseblk_options(parsed_options);
|
||||
set_user_mount_option(parsed_options, getuid());
|
||||
}
|
||||
/* We must do this after ntfs_open() to be able to set the blksize */
|
||||
if (ctx->blkdev && set_fuseblk_options(&parsed_options))
|
||||
goto err_out;
|
||||
|
||||
fh = mount_fuse(parsed_options);
|
||||
if (!fh) {
|
||||
|
@ -2711,6 +2678,7 @@ int main(int argc, char *argv[])
|
|||
fuse_destroy(fh);
|
||||
err_out:
|
||||
utils_mount_error(opts.device, opts.mnt_point, err);
|
||||
err2:
|
||||
ntfs_close();
|
||||
free(ctx);
|
||||
free(parsed_options);
|
||||
|
|
19
src/utils.c
19
src/utils.c
|
@ -4,7 +4,7 @@
|
|||
* Copyright (c) 2002-2005 Richard Russon
|
||||
* Copyright (c) 2003-2006 Anton Altaparmakov
|
||||
* Copyright (c) 2003 Lode Leroy
|
||||
* Copyright (c) 2005-2007 Szabolcs Szakacsits
|
||||
* Copyright (c) 2005-2008 Szabolcs Szakacsits
|
||||
*
|
||||
* A set of shared functions for ntfs utilities
|
||||
*
|
||||
|
@ -62,7 +62,12 @@ static const char *corrupt_volume_msg =
|
|||
|
||||
static const char *hibernated_volume_msg =
|
||||
"The NTFS partition is hibernated. Please resume and shutdown Windows\n"
|
||||
"properly, so mounting could be done safely.\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 %s %s -o remove_hiberfile\n"
|
||||
"\n";
|
||||
|
||||
static const char *unclean_journal_msg =
|
||||
"Mount is denied because NTFS is marked to be in use. Choose one action:\n"
|
||||
|
@ -85,9 +90,9 @@ static const char *fakeraid_msg =
|
|||
"to mount NTFS. Please see the 'dmraid' documentation for help.\n";
|
||||
|
||||
static const char *access_denied_msg =
|
||||
"Please check the device and the ntfs-3g binary permissions, the mounting\n"
|
||||
"user and group ID, and the mount options. You can find more explanation\n"
|
||||
"at http://ntfs-3g.org/support.html#useroption\n";
|
||||
"Please check the volume 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";
|
||||
|
||||
static const char *forced_mount_msg =
|
||||
"\n"
|
||||
|
@ -95,7 +100,7 @@ static const char *forced_mount_msg =
|
|||
"\n"
|
||||
" Or add the option to the relevant row in the /etc/fstab file:\n"
|
||||
"\n"
|
||||
" %s %s ntfs-3g defaults,force 0 0\n";
|
||||
" %s %s ntfs-3g force 0 0\n";
|
||||
|
||||
/**
|
||||
* utils_set_locale
|
||||
|
@ -124,7 +129,7 @@ void utils_mount_error(const char *volume, const char *mntpoint, int err)
|
|||
ntfs_log_error("%s", corrupt_volume_msg);
|
||||
break;
|
||||
case NTFS_VOLUME_HIBERNATED:
|
||||
ntfs_log_error("%s", hibernated_volume_msg);
|
||||
ntfs_log_error(hibernated_volume_msg, volume, mntpoint);
|
||||
break;
|
||||
case NTFS_VOLUME_UNCLEAN_UNMOUNT:
|
||||
ntfs_log_error(unclean_journal_msg);
|
||||
|
|
Loading…
Reference in New Issue