diff --git a/include/ntfs-3g/attrib.h b/include/ntfs-3g/attrib.h index f8db5dec..027305e4 100644 --- a/include/ntfs-3g/attrib.h +++ b/include/ntfs-3g/attrib.h @@ -205,30 +205,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 @@ -358,6 +343,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 */ diff --git a/libntfs-3g/attrib.c b/libntfs-3g/attrib.c index dadf3435..c9bf1ec8 100644 --- a/libntfs-3g/attrib.c +++ b/libntfs-3g/attrib.c @@ -65,6 +65,37 @@ ntfschar STREAM_SDS[] = { const_cpu_to_le16('$'), const_cpu_to_le16('S'), const_cpu_to_le16('\0') }; +static int NAttrFlag(ntfs_attr *na, FILE_ATTR_FLAGS flag) +{ + if (na->type == AT_DATA && na->name == AT_UNNAMED) + return (na->ni->flags & flag); + return 0; +} + +static void NAttrSetFlag(ntfs_attr *na, FILE_ATTR_FLAGS flag) +{ + if (na->type == AT_DATA && na->name == AT_UNNAMED) + na->ni->flags |= flag; + else + ntfs_log_trace("Denied setting flag %d for not unnamed data " + "attribute\n", flag); +} + +static void NAttrClearFlag(ntfs_attr *na, FILE_ATTR_FLAGS flag) +{ + if (na->type == AT_DATA && na->name == AT_UNNAMED) + na->ni->flags &= ~flag; +} + +#define GenNAttrIno(func_name, flag) \ +int NAttr##func_name(ntfs_attr *na) { return NAttrFlag (na, flag); } \ +void NAttrSet##func_name(ntfs_attr *na) { NAttrSetFlag (na, flag); } \ +void NAttrClear##func_name(ntfs_attr *na){ NAttrClearFlag(na, flag); } + +GenNAttrIno(Compressed, FILE_ATTR_COMPRESSED) +GenNAttrIno(Encrypted, FILE_ATTR_ENCRYPTED) +GenNAttrIno(Sparse, FILE_ATTR_SPARSE_FILE) + /** * ntfs_get_attribute_value_length - Find the length of an attribute * @a: @@ -4743,8 +4774,8 @@ static int ntfs_non_resident_attr_expand(ntfs_attr *na, const s64 newsize) ntfs_log_perror("Cluster allocation failed " "(%lld)", (long long)first_free_vcn - - ((long long)na->allocated_size - >> vol->cluster_size_bits)); + ((long long)na->allocated_size >> + vol->cluster_size_bits)); return -1; } } @@ -5017,3 +5048,30 @@ int ntfs_attr_remove(ntfs_inode *ni, const ATTR_TYPES type, ntfschar *name, return ret; } +s64 ntfs_attr_get_free_bits(ntfs_attr *na) +{ + u8 *buf; + s64 nr_free = 0; + s64 br, total = 0; + + buf = ntfs_malloc(na->ni->vol->cluster_size); + if (!buf) + return -1; + while (1) { + int i, j; + + br = ntfs_attr_pread(na, total, na->ni->vol->cluster_size, buf); + if (br <= 0) + break; + total += br; + for (i = 0; i < br; i++) + for (j = 0; j < 8; j++) + if (!((buf[i] >> j) & 1)) + nr_free++; + } + free(buf); + if (!total || br < 0) + return -1; + return nr_free; +} + diff --git a/libntfs-3g/index.c b/libntfs-3g/index.c index a95716e1..1d23e32d 100644 --- a/libntfs-3g/index.c +++ b/libntfs-3g/index.c @@ -1218,7 +1218,7 @@ static int ntfs_ir_truncate(ntfs_index_context *icx, int data_size) icx->ir->index.allocated_size = cpu_to_le32(data_size); - } else + } else if (ret == STATUS_ERROR) ntfs_log_perror("Failed to truncate INDEX_ROOT"); ntfs_attr_close(na); diff --git a/libntfs-3g/inode.c b/libntfs-3g/inode.c index 369c4189..1fe64027 100644 --- a/libntfs-3g/inode.c +++ b/libntfs-3g/inode.c @@ -500,8 +500,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; } diff --git a/libntfs-3g/logging.c b/libntfs-3g/logging.c index 228e90e0..6d85bcf2 100644 --- a/libntfs-3g/logging.c +++ b/libntfs-3g/logging.c @@ -58,6 +58,13 @@ static const char *col_red = "\e[01;31m"; static const char *col_redinv = "\e[01;07;31m"; static const char *col_end = "\e[0m"; +/* gcc 3.3.3 crashes with internal compiler error. 4.x seems to be ok. */ +#if __GNUC__ <= 3 +# 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 * @levels: Bitfield of logging levels @@ -67,7 +74,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; }; /** diff --git a/libntfs-3g/mft.c b/libntfs-3g/mft.c index f95f65cd..d4d280f8 100644 --- a/libntfs-3g/mft.c +++ b/libntfs-3g/mft.c @@ -81,12 +81,12 @@ int ntfs_mft_records_read(const ntfs_volume *vol, const MFT_REF mref, s64 br; VCN m; - ntfs_log_trace("Entering for inode %lld\n", MREF(mref)); + ntfs_log_trace("inode %llu\n", (unsigned long long)MREF(mref)); if (!vol || !vol->mft_na || !b || count < 0) { errno = EINVAL; - ntfs_log_perror("%s: b=%p count=%lld mft=%lld", __FUNCTION__, - b, (long long)count, (long long)MREF(mref)); + ntfs_log_perror("%s: b=%p count=%lld mft=%llu", __FUNCTION__, + b, (long long)count, (unsigned long long)MREF(mref)); return -1; } m = MREF(mref); @@ -265,19 +265,20 @@ int ntfs_file_record_read(const ntfs_volume *vol, const MFT_REF mref, } err = EIO; if (!ntfs_is_file_record(m->magic)) { - ntfs_log_perror("Record %llu has no FILE magic", - (unsigned long long)MREF(mref)); + ntfs_log_error("Record %llu has no FILE magic (0x%x)\n", + (unsigned long long)MREF(mref), *(le32 *)m); goto err_out; } if (MSEQNO(mref) && MSEQNO(mref) != le16_to_cpu(m->sequence_number)) { - ntfs_log_perror("Record %llu has wrong SeqNo", - (unsigned long long)MREF(mref)); + ntfs_log_error("Record %llu has wrong SeqNo (%d <> %d)\n", + (unsigned long long)MREF(mref), MSEQNO(mref), + le16_to_cpu(m->sequence_number)); goto err_out; } a = (ATTR_RECORD*)((char*)m + le16_to_cpu(m->attrs_offset)); if (p2n(a) < p2n(m) || (char*)a > (char*)m + vol->mft_record_size) { - ntfs_log_perror("Record %llu is corrupt", - (unsigned long long)MREF(mref)); + ntfs_log_error("Record %llu is corrupt\n", + (unsigned long long)MREF(mref)); goto err_out; } *mrec = m; diff --git a/libntfs-3g/security.c b/libntfs-3g/security.c index d2dffea0..1a6661d9 100644 --- a/libntfs-3g/security.c +++ b/libntfs-3g/security.c @@ -500,13 +500,15 @@ void ntfs_generate_guid(GUID *guid) */ 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; + 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); - return cpu_to_le32(hash); + while (pos < end) { + hash = le32_to_cpup(pos) + ntfs_rol32(hash, 3); + pos++; + } + return cpu_to_le32(hash); } @@ -3487,8 +3489,8 @@ int ntfs_set_owner(struct SECURITY_CONTEXT *scx, static int inherit_acl(const ACL *oldacl, ACL *newacl, BOOL fordir) { - int src; - int dst; + unsigned int src; + unsigned int dst; int oldcnt; int newcnt; unsigned int selection; @@ -3508,7 +3510,7 @@ static int inherit_acl(const ACL *oldacl, ACL *newacl, BOOL fordir) newcnt = 0; oldcnt = le16_to_cpu(oldacl->ace_count); for (nace = 0; nace < oldcnt; nace++) { - poldace = (const ACCESS_ALLOWED_ACE*)((char*)oldacl + src); + poldace = (const ACCESS_ALLOWED_ACE*)((const char*)oldacl + src); acesz = le16_to_cpu(poldace->size); if (poldace->flags & selection) { pnewace = (ACCESS_ALLOWED_ACE*) @@ -3540,8 +3542,7 @@ static int inherit_acl(const ACL *oldacl, ACL *newacl, BOOL fordir) */ static le32 build_inherited_id(struct SECURITY_CONTEXT *scx, - const char *parentattr, - ntfs_inode *dir_ni, BOOL fordir) + const char *parentattr, BOOL fordir) { const SECURITY_DESCRIPTOR_RELATIVE *pphead; const ACL *ppacl; @@ -3684,8 +3685,7 @@ le32 ntfs_inherited_id(struct SECURITY_CONTEXT *scx, parentattr = getsecurityattr(scx->vol, dir_path, dir_ni); if (parentattr) { securid = build_inherited_id(scx, - parentattr, - dir_ni, fordir); + parentattr, fordir); free(parentattr); /* * Store the result into cache for further use @@ -3865,6 +3865,10 @@ static void free_mapping(struct SECURITY_CONTEXT *scx) /* * Build the user mapping list * user identification may be given in symbolic or numeric format + * + * ! Note ! : does getpwnam() read /etc/passwd or some other file ? + * if so there is a possible recursion into fuse if this + * file is on NTFS, and fuse is not recursion safe. */ static struct MAPPING *ntfs_do_user_mapping(struct MAPLIST *firstitem) @@ -3917,6 +3921,10 @@ static struct MAPPING *ntfs_do_user_mapping(struct MAPLIST *firstitem) * * gid not associated to a uid are processed first in order * to favour real groups + * + * ! Note ! : does getgrnam() read /etc/group or some other file ? + * if so there is a possible recursion into fuse if this + * file is on NTFS, and fuse is not recursion safe. */ static struct MAPPING *ntfs_do_group_mapping(struct MAPLIST *firstitem) diff --git a/src/ntfs-3g.c b/src/ntfs-3g.c index fba2fe2b..07a13ec8 100644 --- a/src/ntfs-3g.c +++ b/src/ntfs-3g.c @@ -120,6 +120,9 @@ typedef struct { BOOL debug; BOOL noatime; BOOL no_detach; + BOOL blkdev; + BOOL mounted; + struct fuse_chan *fc; BOOL inherit; BOOL addsecurids; struct SECURITY_CACHE *seccache; @@ -142,10 +145,6 @@ static const char *locale_msg = " be correct or visible. Please see the potential solution at\n" " http://ntfs-3g.org/support.html#locale\n"; -static const char *dev_fuse_msg = -"HINT: You should be root, or make ntfs-3g setuid root, or load the FUSE\n" -" kernel module as root (modprobe fuse) and make sure /dev/fuse exist.\n"; - static const char *usage_msg = "\n" "%s %s - Third Generation NTFS Driver\n" @@ -169,40 +168,20 @@ static const char *usage_msg = * * Returns 1 if path is to named data stream or 0 otherwise. */ -static __inline__ int ntfs_fuse_is_named_data_stream(const char *path) +static int ntfs_fuse_is_named_data_stream(const char *path) { if (strchr(path, ':') && ctx->streams == NF_STREAMS_INTERFACE_WINDOWS) return 1; return 0; } -static long ntfs_get_nr_free_mft_records(ntfs_volume *vol) +static s64 ntfs_get_nr_free_mft_records(ntfs_volume *vol) { - u8 *buf; - long nr_free = 0; - s64 br, total = 0; + ntfs_attr *na = vol->mftbmp_na; + s64 nr_free = ntfs_attr_get_free_bits(na); - buf = ntfs_malloc(vol->cluster_size); - if (!buf) - return -errno; - while (1) { - int i, j; - - br = ntfs_attr_pread(vol->mftbmp_na, total, - vol->cluster_size, buf); - if (br <= 0) - break; - total += br; - for (i = 0; i < br; i++) - for (j = 0; j < 8; j++) - if (!((buf[i] >> j) & 1)) - nr_free++; - } - free(buf); - if (!total || br < 0) - return -errno; - - nr_free += (vol->mftbmp_na->allocated_size - vol->mftbmp_na->data_size) << 3; + if (nr_free >= 0) + nr_free += (na->allocated_size - na->data_size) << 3; return nr_free; } @@ -229,34 +208,6 @@ static BOOL ntfs_fuse_fill_security_context(struct SECURITY_CONTEXT *scx) return (ctx->security.usermapping != (struct MAPPING*)NULL); } -static long ntfs_get_nr_free_clusters(ntfs_volume *vol) -{ - u8 *buf; - long nr_free = 0; - s64 br, total = 0; - - buf = ntfs_malloc(vol->cluster_size); - if (!buf) - return -errno; - while (1) { - int i, j; - - br = ntfs_attr_pread(vol->lcnbmp_na, total, - vol->cluster_size, buf); - if (br <= 0) - break; - total += br; - for (i = 0; i < br; i++) - for (j = 0; j < 8; j++) - if (!((buf[i] >> j) & 1)) - nr_free++; - } - free(buf); - if (!total || br < 0) - return -errno; - return nr_free; -} - /** * ntfs_fuse_statfs - return information about mounted NTFS volume * @path: ignored (but fuse requires it) @@ -275,7 +226,7 @@ static long ntfs_get_nr_free_clusters(ntfs_volume *vol) * Returns 0 on success or -errno on error. */ static int ntfs_fuse_statfs(const char *path __attribute__((unused)), - struct statvfs *sfs) + struct statvfs *sfs) { s64 size; int delta_bits; @@ -285,22 +236,23 @@ static int ntfs_fuse_statfs(const char *path __attribute__((unused)), if (!vol) return -ENODEV; - /* Optimal transfer block size. */ + /* File system block size, used for optimal transfer block size. */ sfs->f_bsize = vol->cluster_size; + + /* Fundamental file system block size, used as the unit. */ sfs->f_frsize = vol->cluster_size; + /* - * Total data blocks in file system in units of f_bsize and since - * inodes are also stored in data blocs ($MFT is a file) this is just - * the total clusters. + * Total number of blocks on file system in units of f_frsize. + * Since inodes are also stored in blocks ($MFT is a file) hence + * this is the number of clusters on the volume. */ sfs->f_blocks = vol->nr_clusters; - /* Free data blocks in file system in units of f_bsize. */ + /* Free blocks available for all and for non-privileged processes. */ size = vol->free_clusters; if (size < 0) size = 0; - - /* Free blocks avail to non-superuser, same as above on NTFS. */ sfs->f_bavail = sfs->f_bfree = size; /* Free inodes on the free space */ @@ -310,15 +262,14 @@ static int ntfs_fuse_statfs(const char *path __attribute__((unused)), else size >>= -delta_bits; - /* Number of inodes in file system (at this point in time). */ + /* Number of inodes at this point in time. */ sfs->f_files = (vol->mftbmp_na->allocated_size << 3) + size; - /* Free inodes in fs (based on current total count). */ + /* Free inodes available for all and for non-privileged processes. */ size += vol->free_mft_records; if (size < 0) size = 0; - sfs->f_ffree = size; - sfs->f_favail = 0; + sfs->f_ffree = sfs->f_favail = size; /* Maximum length of filenames. */ sfs->f_namemax = NTFS_MAX_NAME_LEN; @@ -606,7 +557,7 @@ static int ntfs_fuse_filler(ntfs_fuse_fill_context_t *fill_ctx, if (MREF(mref) == FILE_root || MREF(mref) >= FILE_first_user || ctx->show_sys_files) { struct stat st = { .st_ino = MREF(mref) }; - + if (dt_type == NTFS_DT_REG) st.st_mode = S_IFREG | (0777 & ~ctx->fmask); else if (dt_type == NTFS_DT_DIR) @@ -701,7 +652,8 @@ static int ntfs_fuse_read(const char *org_path, char *buf, size_t size, ntfs_attr *na = NULL; char *path = NULL; ntfschar *stream_name; - int stream_name_len, res, total = 0; + int stream_name_len, res; + s64 total = 0; stream_name_len = ntfs_fuse_parse_path(org_path, &path, &stream_name); if (stream_name_len < 0) @@ -717,21 +669,26 @@ static int ntfs_fuse_read(const char *org_path, char *buf, size_t size, res = -errno; goto exit; } - if (offset + size > (size_t)na->data_size) - size = na->data_size - offset; - while (size) { - res = ntfs_attr_pread(na, offset, size, buf); - if (res < (s64)size) - ntfs_log_perror("ntfs_attr_pread partial write (%lld: " - "%lld <> %d)", (long long)offset, - (long long)size, res); - if (res <= 0) { - res = -errno; + if (offset + (off_t)size > na->data_size) { + if (na->data_size < offset) { + res = -EINVAL; goto exit; } - size -= res; - offset += res; - total += res; + size = na->data_size - offset; + } + while (size > 0) { + s64 ret = ntfs_attr_pread(na, offset, size, buf); + if (ret != (s64)size) + ntfs_log_perror("ntfs_attr_pread error reading '%s' at " + "offset %lld: %lld <> %lld", org_path, + (long long)offset, (long long)size, (long long)ret); + if (ret <= 0 || ret > (s64)size) { + res = (ret <= 0) ? -errno : -EIO; + goto exit; + } + size -= ret; + offset += ret; + total += ret; } res = total; exit: @@ -1809,15 +1766,18 @@ exit: #endif /* HAVE_SETXATTR */ -static void ntfs_fuse_destroy(void) +static void ntfs_close(void) { struct SECURITY_CONTEXT security; if (!ctx) return; - if (ctx->vol) { - ntfs_log_info("Unmounting %s (%s)\n", opts.device, + if (!ctx->vol) + return; + + if (ctx->mounted) { + ntfs_log_info("Unmounting %s (%s)\n", opts.device, ctx->vol->vol_name); if (ntfs_fuse_fill_security_context(&security)) { if (ctx->seccache && ctx->seccache->head.p_reads) { @@ -1847,21 +1807,20 @@ static void ntfs_fuse_destroy(void) } } ntfs_close_secure(&security); - if (ntfs_umount(ctx->vol, FALSE)) - ntfs_log_perror("Failed to cleanly unmount volume %s", - opts.device); } - free(ctx); - ctx = NULL; - free(opts.device); + + if (ntfs_umount(ctx->vol, FALSE)) + ntfs_log_perror("Failed to close volume %s", opts.device); + + ctx->vol = NULL; } static void ntfs_fuse_destroy2(void *unused __attribute__((unused))) { - ntfs_fuse_destroy(); + ntfs_close(); } -static struct fuse_operations ntfs_fuse_oper = { +static struct fuse_operations ntfs_3g_ops = { .getattr = ntfs_fuse_getattr, .readlink = ntfs_fuse_readlink, .readdir = ntfs_fuse_readdir, @@ -1894,25 +1853,23 @@ static struct fuse_operations ntfs_fuse_oper = { static int ntfs_fuse_init(void) { - ctx = ntfs_malloc(sizeof(ntfs_fuse_context_t)); + ctx = ntfs_calloc(sizeof(ntfs_fuse_context_t)); if (!ctx) return -1; *ctx = (ntfs_fuse_context_t) { .uid = getuid(), .gid = getgid(), - .fmask = 0, - .dmask = 0, .streams = NF_STREAMS_INTERFACE_NONE, }; return 0; } -static ntfs_volume *ntfs_open(const char *device, char *mntpoint, int blkdev) +static int ntfs_open(const char *device, char *mntpoint) { unsigned long flags = 0; - if (!blkdev) + if (!ctx->blkdev) flags |= MS_EXCLUSIVE; if (ctx->ro) flags |= MS_RDONLY; @@ -1922,7 +1879,22 @@ static ntfs_volume *ntfs_open(const char *device, char *mntpoint, int blkdev) flags |= MS_FORCE; ctx->vol = utils_mount_volume(device, mntpoint, flags); - return ctx->vol; + if (!ctx->vol) + return -1; + + ctx->vol->free_clusters = ntfs_attr_get_free_bits(ctx->vol->lcnbmp_na); + if (ctx->vol->free_clusters < 0) { + ntfs_log_perror("Failed to read NTFS $Bitmap"); + return -1; + } + + ctx->vol->free_mft_records = ntfs_get_nr_free_mft_records(ctx->vol); + if (ctx->vol->free_mft_records < 0) { + ntfs_log_perror("Failed to calculate free MFT records"); + return -1; + } + + return 0; } static void signal_handler(int arg __attribute__((unused))) @@ -2286,7 +2258,13 @@ static int parse_options(int argc, char *argv[]) return 0; } -#ifdef linux +#if defined(linux) || defined(__uClinux__) + +static const char *dev_fuse_msg = +"HINT: You should be root, or make ntfs-3g setuid root, or load the FUSE\n" +" kernel module as root ('modprobe fuse' or 'insmod /fuse.ko'" +" or insmod /fuse.o'). Make also sure that the fuse device" +" exists. It's usually either /dev/fuse or /dev/misc/fuse."; static const char *fuse26_kmod_msg = "WARNING: Deficient Linux kernel detected. Some driver features are\n" @@ -2299,19 +2277,39 @@ static const char *fuse26_kmod_msg = " http://ntfs-3g.org/support.html#fuse26\n" "\n"; -static void create_dev_fuse(void) +static void mknod_dev_fuse(const char *dev) { struct stat st; - if (stat("/dev/fuse", &st) && (errno == ENOENT)) { - if (mknod("/dev/fuse", S_IFCHR | 0666, makedev(10, 229))) { - ntfs_log_perror("Failed to create /dev/fuse"); + if (stat(dev, &st) && (errno == ENOENT)) { + mode_t mask = umask(0); + if (mknod(dev, S_IFCHR | 0666, makedev(10, 229))) { + ntfs_log_perror("Failed to create '%s'", dev); if (errno == EPERM) ntfs_log_error(dev_fuse_msg); } + umask(mask); } } +static void create_dev_fuse(void) +{ + mknod_dev_fuse("/dev/fuse"); + +#ifdef __UCLIBC__ + { + struct stat st; + /* The fuse device is under /dev/misc using devfs. */ + if (stat("/dev/misc", &st) && (errno == ENOENT)) { + mode_t mask = umask(0); + mkdir("/dev/misc", 0775); + umask(mask); + } + mknod_dev_fuse("/dev/misc/fuse"); + } +#endif +} + static fuse_fstype get_fuse_fstype(void) { char buf[256]; @@ -2430,15 +2428,46 @@ static void set_user_mount_option(char *parsed_options, uid_t uid) strcat(parsed_options, option); } +static struct fuse *mount_fuse(char *parsed_options) +{ + struct fuse *fh = NULL; + struct fuse_args args = FUSE_ARGS_INIT(0, NULL); + + /* 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"); + + ctx->fc = try_fuse_mount(parsed_options); + if (!ctx->fc) + return NULL; + + if (fuse_opt_add_arg(&args, "") == -1) + goto err; + if (fuse_opt_add_arg(&args, "-ouse_ino,kernel_cache") == -1) + goto err; + if (ctx->debug) + if (fuse_opt_add_arg(&args, "-odebug") == -1) + goto err; + + fh = fuse_new(ctx->fc, &args , &ntfs_3g_ops, sizeof(ntfs_3g_ops), NULL); + if (!fh) + goto err; + + ctx->mounted = TRUE; +out: + fuse_opt_free_args(&args); + return fh; +err: + fuse_unmount(opts.mnt_point, ctx->fc); + goto out; +} + int main(int argc, char *argv[]) { char *parsed_options = NULL; - struct fuse_args margs = FUSE_ARGS_INIT(0, NULL); struct fuse *fh; - struct fuse_chan *fc; fuse_fstype fstype = FSTYPE_UNKNOWN; struct stat sbuf; - int use_blkdev = 0; uid_t uid, euid; int err = 10; @@ -2467,7 +2496,7 @@ int main(int argc, char *argv[]) goto err_out; } -#ifdef linux +#if defined(linux) || defined(__uClinux__) fstype = get_fuse_fstype(); if (fstype == FSTYPE_NONE || fstype == FSTYPE_UNKNOWN) fstype = load_fuse_module(); @@ -2481,64 +2510,27 @@ int main(int argc, char *argv[]) } /* Always use fuseblk for block devices unless it's surely missing. */ if (S_ISBLK(sbuf.st_mode) && (fstype != FSTYPE_FUSE)) - use_blkdev = 1; + ctx->blkdev = TRUE; - if (!ntfs_open(opts.device, opts.mnt_point, use_blkdev)) + if (ntfs_open(opts.device, opts.mnt_point)) goto err_out; - ctx->vol->free_clusters = ntfs_get_nr_free_clusters(ctx->vol); - if (ctx->vol->free_clusters < 0) { - ntfs_log_perror("Failed to read NTFS $Bitmap"); + if (ctx->blkdev) { + /* Must do after ntfs_open() to set the right blksize. */ + set_fuseblk_options(parsed_options); + set_user_mount_option(parsed_options, uid); + } + + fh = mount_fuse(parsed_options); + if (!fh) goto err_out; - } - - ctx->vol->free_mft_records = ntfs_get_nr_free_mft_records(ctx->vol); - if (ctx->vol->free_mft_records < 0) { - ntfs_log_perror("Failed to calculate free MFT records"); - goto err_out; - } - - if (use_blkdev) { - set_fuseblk_options(parsed_options); - set_user_mount_option(parsed_options, uid); - } - - /* 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"); - - fc = try_fuse_mount(parsed_options); - if (!fc) - goto err_out; - - fh = (struct fuse *)1; /* Cast anything except NULL to handle errors. */ - if (fuse_opt_add_arg(&margs, "") == -1 || - fuse_opt_add_arg(&margs, "-o") == -1) - fh = NULL; - if (!ctx->debug && !ctx->no_detach) { - if (fuse_opt_add_arg(&margs, "use_ino,kernel_cache") == -1) - fh = NULL; - } else { - if (fuse_opt_add_arg(&margs, "use_ino,kernel_cache,debug") == -1) - fh = NULL; - } - if (fh) - fh = fuse_new(fc, &margs , &ntfs_fuse_oper, - sizeof(ntfs_fuse_oper), NULL); - fuse_opt_free_args(&margs); - if (!fh) { - ntfs_log_error("fuse_new failed.\n"); - fuse_unmount(opts.mnt_point, fc); - goto err_out; - } - + if (setuid(uid)) { ntfs_log_perror("Failed to set user ID to %d", uid); - fuse_unmount(opts.mnt_point, fc); - goto err_out; + goto err_umount; } -#ifdef linux +#if defined(linux) || defined(__uClinux__) if (S_ISBLK(sbuf.st_mode) && (fstype == FSTYPE_FUSE)) ntfs_log_info(fuse26_kmod_msg); #endif @@ -2580,12 +2572,15 @@ int main(int argc, char *argv[]) fuse_loop(fh); - fuse_unmount(opts.mnt_point, fc); - fuse_destroy(fh); err = 0; +err_umount: + fuse_unmount(opts.mnt_point, ctx->fc); + fuse_destroy(fh); err_out: - free(opts.options); + ntfs_close(); + free(ctx); free(parsed_options); - ntfs_fuse_destroy(); + free(opts.options); + free(opts.device); return err; }