1/**
2 * ntfs-3g - Third Generation NTFS Driver
3 *
4 * Copyright (c) 2005-2007 Yura Pakhuchiy
5 * Copyright (c) 2005 Yuval Fledel
6 * Copyright (c) 2006-2009 Szabolcs Szakacsits
7 * Copyright (c) 2007-2009 Jean-Pierre Andre
8 * Copyright (c) 2009 Erik Larsson
9 *
10 * This file is originated from the Linux-NTFS project.
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program (in the main directory of the NTFS-3G
24 * distribution in the file COPYING); if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26 */
27
28#include "config.h"
29
30#include <fuse.h>
31
32#if !defined(FUSE_VERSION) || (FUSE_VERSION < 26)
33#error "***********************************************************"
34#error "*                                                         *"
35#error "*     Compilation requires at least FUSE version 2.6.0!   *"
36#error "*                                                         *"
37#error "***********************************************************"
38#endif
39
40#ifdef FUSE_INTERNAL
41#define FUSE_TYPE	"integrated FUSE"
42#else
43#define FUSE_TYPE	"external FUSE"
44#endif
45
46#ifdef HAVE_STDIO_H
47#include <stdio.h>
48#endif
49#ifdef HAVE_STRING_H
50#include <string.h>
51#endif
52#ifdef HAVE_ERRNO_H
53#include <errno.h>
54#endif
55#ifdef HAVE_FCNTL_H
56#include <fcntl.h>
57#endif
58#ifdef HAVE_UNISTD_H
59#include <unistd.h>
60#endif
61#ifdef HAVE_STDLIB_H
62#include <stdlib.h>
63#endif
64#ifdef HAVE_LOCALE_H
65#include <locale.h>
66#endif
67#include <signal.h>
68#ifdef HAVE_LIMITS_H
69#include <limits.h>
70#endif
71#include <getopt.h>
72#include <syslog.h>
73#include <sys/wait.h>
74
75#ifdef HAVE_SETXATTR
76#include <sys/xattr.h>
77#endif
78
79#ifdef HAVE_SYS_TYPES_H
80#include <sys/types.h>
81#endif
82#ifdef HAVE_SYS_MKDEV_H
83#include <sys/mkdev.h>
84#endif
85
86#include "compat.h"
87#include "attrib.h"
88#include "inode.h"
89#include "volume.h"
90#include "dir.h"
91#include "unistr.h"
92#include "layout.h"
93#include "index.h"
94#include "ntfstime.h"
95#include "misc.h"
96
97typedef enum {
98	FSTYPE_NONE,
99	FSTYPE_UNKNOWN,
100	FSTYPE_FUSE,
101	FSTYPE_FUSEBLK
102} fuse_fstype;
103
104typedef enum {
105	ATIME_ENABLED,
106	ATIME_DISABLED,
107	ATIME_RELATIVE
108} ntfs_atime_t;
109
110typedef struct {
111	fuse_fill_dir_t filler;
112	void *buf;
113} ntfs_fuse_fill_context_t;
114
115typedef enum {
116	NF_STREAMS_INTERFACE_NONE,	/* No access to named data streams. */
117	NF_STREAMS_INTERFACE_XATTR,	/* Map named data streams to xattrs. */
118	NF_STREAMS_INTERFACE_WINDOWS,	/* "file:stream" interface. */
119} ntfs_fuse_streams_interface;
120
121typedef struct {
122	ntfs_volume *vol;
123	unsigned int uid;
124	unsigned int gid;
125	unsigned int fmask;
126	unsigned int dmask;
127	ntfs_fuse_streams_interface streams;
128	ntfs_atime_t atime;
129	BOOL ro;
130	BOOL show_sys_files;
131	BOOL silent;
132	BOOL recover;
133	BOOL hiberfile;
134	BOOL debug;
135	BOOL no_detach;
136	BOOL blkdev;
137	BOOL mounted;
138	struct fuse_chan *fc;
139} ntfs_fuse_context_t;
140
141static struct options {
142	char	*mnt_point;	/* Mount point */
143	char	*options;	/* Mount options */
144	char	*device;	/* Device to mount */
145} opts;
146
147static const char *EXEC_NAME = "ntfs-3g";
148static char def_opts[] = "silent,allow_other,nonempty,";
149static ntfs_fuse_context_t *ctx;
150static u32 ntfs_sequence;
151
152static const char *usage_msg =
153"\n"
154"%s %s %s %d - Third Generation NTFS Driver\n"
155"\n"
156"Copyright (C) 2005-2007 Yura Pakhuchiy\n"
157"Copyright (C) 2006-2009 Szabolcs Szakacsits\n"
158"Copyright (C) 2007-2009 Jean-Pierre Andre\n"
159"Copyright (C) 2009 Erik Larsson\n"
160"\n"
161"Usage:    %s [-o option[,...]] <device|image_file> <mount_point>\n"
162"\n"
163"Options:  ro (read-only mount), remove_hiberfile, uid=, gid=,\n"
164"          umask=, fmask=, dmask=, streams_interface=.\n"
165"          Please see the details in the manual (type: man ntfs-3g).\n"
166"\n"
167"Example: ntfs-3g /dev/sda1 /mnt/windows\n"
168"\n"
169"%s";
170
171#ifdef FUSE_INTERNAL
172int drop_privs(void);
173int restore_privs(void);
174#else
175/*
176 * setuid and setgid root ntfs-3g denies to start with external FUSE,
177 * therefore the below functions are no-op in such case.
178 */
179static int drop_privs(void)    { return 0; }
180static int restore_privs(void) { return 0; }
181
182static const char *setuid_msg =
183"Mount is denied because setuid and setgid root ntfs-3g is insecure with the\n"
184"external FUSE library. Either remove the setuid/setgid bit from the binary\n"
185"or rebuild NTFS-3G with integrated FUSE support and make it setuid root.\n"
186"Please see more information at http://ntfs-3g.org/support.html#unprivileged\n";
187
188static const char *unpriv_fuseblk_msg =
189"Unprivileged user can not mount NTFS block devices using the external FUSE\n"
190"library. Either mount the volume as root, or rebuild NTFS-3G with integrated\n"
191"FUSE support and make it setuid root. Please see more information at\n"
192"http://ntfs-3g.org/support.html#unprivileged\n";
193#endif
194
195#define USB_VOL_NAME_FILE   "/tmp/usb_vol_name/%s"  /* Foxconn added pling 05/05/2009 */
196
197/**
198 * ntfs_fuse_is_named_data_stream - check path to be to named data stream
199 * @path:	path to check
200 *
201 * Returns 1 if path is to named data stream or 0 otherwise.
202 */
203static int ntfs_fuse_is_named_data_stream(const char *path)
204{
205	if (strchr(path, ':') && ctx->streams == NF_STREAMS_INTERFACE_WINDOWS)
206		return 1;
207	return 0;
208}
209
210static void ntfs_fuse_update_times(ntfs_inode *ni, ntfs_time_update_flags mask)
211{
212	if (ctx->atime == ATIME_DISABLED)
213		mask &= ~NTFS_UPDATE_ATIME;
214	else if (ctx->atime == ATIME_RELATIVE && mask == NTFS_UPDATE_ATIME &&
215			ni->last_access_time >= ni->last_data_change_time &&
216			ni->last_access_time >= ni->last_mft_change_time)
217		return;
218	ntfs_inode_update_times(ni, mask);
219}
220
221static s64 ntfs_get_nr_free_mft_records(ntfs_volume *vol)
222{
223	ntfs_attr *na = vol->mftbmp_na;
224	s64 nr_free = ntfs_attr_get_free_bits(na);
225
226	if (nr_free >= 0)
227		nr_free += (na->allocated_size - na->data_size) << 3;
228	return nr_free;
229}
230
231/**
232 * ntfs_fuse_statfs - return information about mounted NTFS volume
233 * @path:	ignored (but fuse requires it)
234 * @sfs:	statfs structure in which to return the information
235 *
236 * Return information about the mounted NTFS volume @sb in the statfs structure
237 * pointed to by @sfs (this is initialized with zeros before ntfs_statfs is
238 * called). We interpret the values to be correct of the moment in time at
239 * which we are called. Most values are variable otherwise and this isn't just
240 * the free values but the totals as well. For example we can increase the
241 * total number of file nodes if we run out and we can keep doing this until
242 * there is no more space on the volume left at all.
243 *
244 * This code based on ntfs_statfs from ntfs kernel driver.
245 *
246 * Returns 0 on success or -errno on error.
247 */
248static int ntfs_fuse_statfs(const char *path __attribute__((unused)),
249			    struct statvfs *sfs)
250{
251	s64 size;
252	int delta_bits;
253	ntfs_volume *vol;
254
255	vol = ctx->vol;
256	if (!vol)
257		return -ENODEV;
258
259	/*
260	 * File system block size. Used to calculate used/free space by df.
261	 * Incorrectly documented as "optimal transfer block size".
262	 */
263	sfs->f_bsize = vol->cluster_size;
264
265	/* Fundamental file system block size, used as the unit. */
266	sfs->f_frsize = vol->cluster_size;
267
268	/*
269	 * Total number of blocks on file system in units of f_frsize.
270	 * Since inodes are also stored in blocks ($MFT is a file) hence
271	 * this is the number of clusters on the volume.
272	 */
273	sfs->f_blocks = vol->nr_clusters;
274
275	/* Free blocks available for all and for non-privileged processes. */
276	size = vol->free_clusters;
277	if (size < 0)
278		size = 0;
279	sfs->f_bavail = sfs->f_bfree = size;
280
281	/* Free inodes on the free space */
282	delta_bits = vol->cluster_size_bits - vol->mft_record_size_bits;
283	if (delta_bits >= 0)
284		size <<= delta_bits;
285	else
286		size >>= -delta_bits;
287
288	/* Number of inodes at this point in time. */
289	sfs->f_files = (vol->mftbmp_na->allocated_size << 3) + size;
290
291	/* Free inodes available for all and for non-privileged processes. */
292	size += vol->free_mft_records;
293	if (size < 0)
294		size = 0;
295	sfs->f_ffree = sfs->f_favail = size;
296
297	/* Maximum length of filenames. */
298	sfs->f_namemax = NTFS_MAX_NAME_LEN;
299	return 0;
300}
301
302/**
303 * ntfs_fuse_parse_path - split path to path and stream name.
304 * @org_path:		path to split
305 * @path:		pointer to buffer in which parsed path saved
306 * @stream_name:	pointer to buffer where stream name in unicode saved
307 *
308 * This function allocates buffers for @*path and @*stream, user must free them
309 * after use.
310 *
311 * Return values:
312 *	<0	Error occurred, return -errno;
313 *	 0	No stream name, @*stream is not allocated and set to AT_UNNAMED.
314 *	>0	Stream name length in unicode characters.
315 */
316static int ntfs_fuse_parse_path(const char *org_path, char **path,
317		ntfschar **stream_name)
318{
319	char *stream_name_mbs;
320	int res;
321
322	stream_name_mbs = strdup(org_path);
323	if (!stream_name_mbs)
324		return -errno;
325	if (ctx->streams == NF_STREAMS_INTERFACE_WINDOWS) {
326		*path = strsep(&stream_name_mbs, ":");
327		if (stream_name_mbs) {
328			*stream_name = NULL;
329			res = ntfs_mbstoucs(stream_name_mbs, stream_name);
330			if (res < 0)
331				return -errno;
332			return res;
333		}
334	} else
335		*path = stream_name_mbs;
336	*stream_name = AT_UNNAMED;
337	return 0;
338}
339
340static void set_fuse_error(int *err)
341{
342	if (!*err)
343		*err = -errno;
344}
345
346#if defined(__APPLE__) || defined(__DARWIN__)
347static void *ntfs_macfuse_init(struct fuse_conn_info *conn)
348{
349	FUSE_ENABLE_XTIMES(conn);
350	return NULL;
351}
352
353static int ntfs_macfuse_getxtimes(const char *org_path,
354		struct timespec *bkuptime, struct timespec *crtime)
355{
356	int res = 0;
357	ntfs_inode *ni;
358	char *path = NULL;
359	ntfschar *stream_name;
360	int stream_name_len;
361
362	stream_name_len = ntfs_fuse_parse_path(org_path, &path, &stream_name);
363	if (stream_name_len < 0)
364		return stream_name_len;
365	memset(bkuptime, 0, sizeof(struct timespec));
366	memset(crtime, 0, sizeof(struct timespec));
367	ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
368	if (!ni) {
369		res = -errno;
370		goto exit;
371	}
372
373	/* We have no backup timestamp in NTFS. */
374	crtime->tv_sec = ni->creation_time;
375exit:
376	if (ntfs_inode_close(ni))
377		set_fuse_error(&res);
378	free(path);
379	if (stream_name_len)
380		free(stream_name);
381	return res;
382}
383
384int ntfs_macfuse_setcrtime(const char *path, const struct timespec *tv)
385{
386	ntfs_inode *ni;
387	int res = 0;
388
389	if (ntfs_fuse_is_named_data_stream(path))
390		return -EINVAL; /* n/a for named data streams. */
391	ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
392	if (!ni)
393		return -errno;
394
395	if (tv) {
396		ni->creation_time = tv->tv_sec;
397		ntfs_fuse_update_times(ni, NTFS_UPDATE_CTIME);
398	}
399
400	if (ntfs_inode_close(ni))
401		set_fuse_error(&res);
402	return res;
403}
404
405int ntfs_macfuse_setbkuptime(const char *path, const struct timespec *tv)
406{
407	ntfs_inode *ni;
408	int res = 0;
409
410	if (ntfs_fuse_is_named_data_stream(path))
411		return -EINVAL; /* n/a for named data streams. */
412	ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
413	if (!ni)
414		return -errno;
415
416	/*
417	 * Doing nothing while pretending to do something. NTFS has no backup
418	 * time. If this function is not implemented then some apps break.
419	 */
420
421	if (ntfs_inode_close(ni))
422		set_fuse_error(&res);
423	return res;
424}
425#endif /* defined(__APPLE__) || defined(__DARWIN__) */
426
427static int ntfs_fuse_getattr(const char *org_path, struct stat *stbuf)
428{
429	int res = 0;
430	ntfs_inode *ni;
431	ntfs_attr *na;
432	char *path = NULL;
433	ntfschar *stream_name;
434	int stream_name_len;
435
436	stream_name_len = ntfs_fuse_parse_path(org_path, &path, &stream_name);
437	if (stream_name_len < 0)
438		return stream_name_len;
439	memset(stbuf, 0, sizeof(struct stat));
440	ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
441	if (!ni) {
442		res = -errno;
443		goto exit;
444	}
445	if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY && !stream_name_len) {
446		/* Directory. */
447		stbuf->st_mode = S_IFDIR | (0777 & ~ctx->dmask);
448		na = ntfs_attr_open(ni, AT_INDEX_ALLOCATION, NTFS_INDEX_I30, 4);
449		if (na) {
450			stbuf->st_size = na->data_size;
451			stbuf->st_blocks = na->allocated_size >> 9;
452			ntfs_attr_close(na);
453		}
454		stbuf->st_nlink = 1;	/* Make find(1) work */
455	} else {
456		/* Regular or Interix (INTX) file. */
457		stbuf->st_mode = S_IFREG;
458		stbuf->st_size = ni->data_size;
459		/*
460		 * Temporary fix to make ActiveSync work via Samba 3.0.
461		 * See more on the ntfs-3g-devel list.
462		 */
463		stbuf->st_blocks = (ni->allocated_size + 511) >> 9;
464		stbuf->st_nlink = le16_to_cpu(ni->mrec->link_count);
465		if (ni->flags & FILE_ATTR_SYSTEM || stream_name_len) {
466			na = ntfs_attr_open(ni, AT_DATA, stream_name,
467					stream_name_len);
468			if (!na) {
469				if (stream_name_len)
470					res = -ENOENT;
471				goto exit;
472			}
473			if (stream_name_len) {
474				stbuf->st_size = na->data_size;
475				stbuf->st_blocks = na->allocated_size >> 9;
476			}
477			/* Check whether it's Interix FIFO or socket. */
478			if (!(ni->flags & FILE_ATTR_HIDDEN) &&
479					!stream_name_len) {
480				/* FIFO. */
481				if (na->data_size == 0)
482					stbuf->st_mode = S_IFIFO;
483				/* Socket link. */
484				if (na->data_size == 1)
485					stbuf->st_mode = S_IFSOCK;
486			}
487			/*
488			 * Check whether it's Interix symbolic link, block or
489			 * character device.
490			 */
491			if (na->data_size <= sizeof(INTX_FILE_TYPES) +
492			    sizeof(ntfschar) * PATH_MAX &&
493			    na->data_size > sizeof(INTX_FILE_TYPES) &&
494			    !stream_name_len) {
495
496				INTX_FILE *intx_file;
497
498				intx_file = ntfs_malloc(na->data_size);
499				if (!intx_file) {
500					res = -errno;
501					ntfs_attr_close(na);
502					goto exit;
503				}
504				if (ntfs_attr_pread(na, 0, na->data_size,
505						intx_file) != na->data_size) {
506					res = -errno;
507					free(intx_file);
508					ntfs_attr_close(na);
509					goto exit;
510				}
511				if (intx_file->magic == INTX_BLOCK_DEVICE &&
512						na->data_size == offsetof(
513						INTX_FILE, device_end)) {
514					stbuf->st_mode = S_IFBLK;
515					stbuf->st_rdev = makedev(le64_to_cpu(
516							intx_file->major),
517							le64_to_cpu(
518							intx_file->minor));
519				}
520				if (intx_file->magic == INTX_CHARACTER_DEVICE &&
521						na->data_size == offsetof(
522						INTX_FILE, device_end)) {
523					stbuf->st_mode = S_IFCHR;
524					stbuf->st_rdev = makedev(le64_to_cpu(
525							intx_file->major),
526							le64_to_cpu(
527							intx_file->minor));
528				}
529				if (intx_file->magic == INTX_SYMBOLIC_LINK)
530					stbuf->st_mode = S_IFLNK;
531				free(intx_file);
532			}
533			ntfs_attr_close(na);
534		}
535		stbuf->st_mode |= (0777 & ~ctx->fmask);
536	}
537	stbuf->st_uid = ctx->uid;
538	stbuf->st_gid = ctx->gid;
539	stbuf->st_ino = ni->mft_no;
540	stbuf->st_atime = ni->last_access_time;
541	stbuf->st_ctime = ni->last_mft_change_time;
542	stbuf->st_mtime = ni->last_data_change_time;
543exit:
544	if (ntfs_inode_close(ni))
545		set_fuse_error(&res);
546	free(path);
547	if (stream_name_len)
548		free(stream_name);
549	return res;
550}
551
552static int ntfs_fuse_readlink(const char *org_path, char *buf, size_t buf_size)
553{
554	char *path;
555	ntfschar *stream_name;
556	ntfs_inode *ni = NULL;
557	ntfs_attr *na = NULL;
558	INTX_FILE *intx_file = NULL;
559	int stream_name_len, res = 0;
560
561	/* Get inode. */
562	stream_name_len = ntfs_fuse_parse_path(org_path, &path, &stream_name);
563	if (stream_name_len < 0)
564		return stream_name_len;
565	if (stream_name_len > 0) {
566		res = -EINVAL;
567		goto exit;
568	}
569	ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
570	if (!ni) {
571		res = -errno;
572		goto exit;
573	}
574	/* Sanity checks. */
575	if (!(ni->flags & FILE_ATTR_SYSTEM)) {
576		res = -EINVAL;
577		goto exit;
578	}
579	na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
580	if (!na) {
581		res = -errno;
582		goto exit;
583	}
584	if (na->data_size <= sizeof(INTX_FILE_TYPES)) {
585		res = -EINVAL;
586		goto exit;
587	}
588	if (na->data_size > sizeof(INTX_FILE_TYPES) +
589			sizeof(ntfschar) * PATH_MAX) {
590		res = -ENAMETOOLONG;
591		goto exit;
592	}
593	/* Receive file content. */
594	intx_file = ntfs_malloc(na->data_size);
595	if (!intx_file) {
596		res = -errno;
597		goto exit;
598	}
599	if (ntfs_attr_pread(na, 0, na->data_size, intx_file) != na->data_size) {
600		res = -errno;
601		goto exit;
602	}
603	/* Sanity check. */
604	if (intx_file->magic != INTX_SYMBOLIC_LINK) {
605		res = -EINVAL;
606		goto exit;
607	}
608	/* Convert link from unicode to local encoding. */
609	if (ntfs_ucstombs(intx_file->target, (na->data_size -
610			offsetof(INTX_FILE, target)) / sizeof(ntfschar),
611			&buf, buf_size) < 0) {
612		res = -errno;
613		goto exit;
614	}
615exit:
616	if (intx_file)
617		free(intx_file);
618	if (na)
619		ntfs_attr_close(na);
620	if (ntfs_inode_close(ni))
621		set_fuse_error(&res);
622	free(path);
623	if (stream_name_len)
624		free(stream_name);
625	return res;
626}
627
628static int ntfs_fuse_filler(ntfs_fuse_fill_context_t *fill_ctx,
629		const ntfschar *name, const int name_len, const int name_type,
630		const s64 pos __attribute__((unused)), const MFT_REF mref,
631		const unsigned dt_type __attribute__((unused)))
632{
633	char *filename = NULL;
634	int ret = 0;
635
636	if (name_type == FILE_NAME_DOS)
637		return 0;
638
639	if (ntfs_ucstombs(name, name_len, &filename, 0) < 0) {
640		ntfs_log_perror("Skipping unrepresentable filename (inode %llu)",
641				(unsigned long long)MREF(mref));
642		return -1;
643	}
644
645	if (ntfs_fuse_is_named_data_stream(filename)) {
646		ntfs_log_error("Unable to access '%s' (inode %llu) with "
647				"current named streams access interface.\n",
648				filename, (unsigned long long)MREF(mref));
649		free(filename);
650		return 0;
651	}
652
653	if (MREF(mref) == FILE_root || MREF(mref) >= FILE_first_user ||
654			ctx->show_sys_files) {
655		struct stat st = { .st_ino = MREF(mref) };
656
657		if (dt_type == NTFS_DT_REG)
658			st.st_mode = S_IFREG | (0777 & ~ctx->fmask);
659		else if (dt_type == NTFS_DT_DIR)
660			st.st_mode = S_IFDIR | (0777 & ~ctx->dmask);
661
662		ret = fill_ctx->filler(fill_ctx->buf, filename, &st, 0);
663	}
664
665	free(filename);
666	return ret;
667}
668
669static int ntfs_fuse_readdir(const char *path, void *buf,
670		fuse_fill_dir_t filler, off_t offset __attribute__((unused)),
671		struct fuse_file_info *fi __attribute__((unused)))
672{
673	ntfs_fuse_fill_context_t fill_ctx;
674	ntfs_inode *ni;
675	s64 pos = 0;
676	int err = 0;
677
678	fill_ctx.filler = filler;
679	fill_ctx.buf = buf;
680	ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
681	if (!ni)
682		return -errno;
683	if (ntfs_readdir(ni, &pos, &fill_ctx,
684			(ntfs_filldir_t)ntfs_fuse_filler))
685		err = -errno;
686	ntfs_fuse_update_times(ni, NTFS_UPDATE_ATIME);
687	if (ntfs_inode_close(ni))
688		set_fuse_error(&err);
689	return err;
690}
691
692static int ntfs_fuse_open(const char *org_path,
693		struct fuse_file_info *fi __attribute__((unused)))
694{
695	ntfs_inode *ni;
696	ntfs_attr *na;
697	int res = 0;
698	char *path = NULL;
699	ntfschar *stream_name;
700	int stream_name_len;
701
702	stream_name_len = ntfs_fuse_parse_path(org_path, &path, &stream_name);
703	if (stream_name_len < 0)
704		return stream_name_len;
705	ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
706	if (ni) {
707		na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len);
708		if (na) {
709			if (NAttrEncrypted(na))
710				res = -EACCES;
711			ntfs_attr_close(na);
712		} else
713			res = -errno;
714		if (ntfs_inode_close(ni))
715			set_fuse_error(&res);
716	} else
717		res = -errno;
718	free(path);
719	if (stream_name_len)
720		free(stream_name);
721	return res;
722}
723
724static int ntfs_fuse_read(const char *org_path, char *buf, size_t size,
725		off_t offset, struct fuse_file_info *fi __attribute__((unused)))
726{
727	ntfs_inode *ni = NULL;
728	ntfs_attr *na = NULL;
729	char *path = NULL;
730	ntfschar *stream_name;
731	int stream_name_len, res;
732	s64 total = 0;
733
734	if (!size)
735		return 0;
736
737	stream_name_len = ntfs_fuse_parse_path(org_path, &path, &stream_name);
738	if (stream_name_len < 0)
739		return stream_name_len;
740	ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
741	if (!ni) {
742		res = -errno;
743		goto exit;
744	}
745	na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len);
746	if (!na) {
747		res = -errno;
748		goto exit;
749	}
750	if (offset + size > na->data_size) {
751		if (na->data_size < offset)
752			goto ok;
753		size = na->data_size - offset;
754	}
755	while (size > 0) {
756		s64 ret = ntfs_attr_pread(na, offset, size, buf);
757		if (ret != (s64)size)
758			ntfs_log_perror("ntfs_attr_pread error reading '%s' at "
759				"offset %lld: %lld <> %lld", org_path,
760				(long long)offset, (long long)size, (long long)ret);
761		if (ret <= 0 || ret > (s64)size) {
762			res = (ret < 0) ? -errno : -EIO;
763			goto exit;
764		}
765		size -= ret;
766		offset += ret;
767		total += ret;
768	}
769ok:
770	ntfs_fuse_update_times(na->ni, NTFS_UPDATE_ATIME);
771	res = total;
772exit:
773	if (na)
774		ntfs_attr_close(na);
775	if (ntfs_inode_close(ni))
776		set_fuse_error(&res);
777	free(path);
778	if (stream_name_len)
779		free(stream_name);
780	return res;
781}
782
783static int ntfs_fuse_write(const char *org_path, const char *buf, size_t size,
784		off_t offset, struct fuse_file_info *fi __attribute__((unused)))
785{
786	ntfs_inode *ni = NULL;
787	ntfs_attr *na = NULL;
788	char *path = NULL;
789	ntfschar *stream_name;
790	int stream_name_len, res, total = 0;
791
792	stream_name_len = ntfs_fuse_parse_path(org_path, &path, &stream_name);
793	if (stream_name_len < 0) {
794		res = stream_name_len;
795		goto out;
796	}
797	ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
798	if (!ni) {
799		res = -errno;
800		goto exit;
801	}
802	na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len);
803	if (!na) {
804		res = -errno;
805		goto exit;
806	}
807	while (size) {
808		s64 ret = ntfs_attr_pwrite(na, offset, size, buf);
809		if (0 <= ret && ret < (s64)size)
810			ntfs_log_perror("ntfs_attr_pwrite partial write to '%s'"
811				" (%lld: %lld <> %lld)", path, (long long)offset,
812				(long long)size, (long long)ret);
813		if (ret <= 0) {
814			res = -errno;
815			goto exit;
816		}
817		size   -= ret;
818		offset += ret;
819		total  += ret;
820	}
821	res = total;
822	if (res > 0)
823		ntfs_fuse_update_times(na->ni, NTFS_UPDATE_MCTIME);
824exit:
825	if (na)
826		ntfs_attr_close(na);
827	if (ntfs_inode_close(ni))
828		set_fuse_error(&res);
829	free(path);
830	if (stream_name_len)
831		free(stream_name);
832out:
833	return res;
834}
835
836static int ntfs_fuse_truncate(const char *org_path, off_t size)
837{
838	ntfs_inode *ni = NULL;
839	ntfs_attr *na = NULL;
840	int res;
841	char *path = NULL;
842	ntfschar *stream_name;
843	int stream_name_len;
844
845	stream_name_len = ntfs_fuse_parse_path(org_path, &path, &stream_name);
846	if (stream_name_len < 0)
847		return stream_name_len;
848	ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
849	if (!ni)
850		goto exit;
851
852	na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len);
853	if (!na)
854		goto exit;
855
856	if (ntfs_attr_truncate(na, size))
857		goto exit;
858
859	ntfs_fuse_update_times(na->ni, NTFS_UPDATE_MCTIME);
860	errno = 0;
861exit:
862	res = -errno;
863	ntfs_attr_close(na);
864	if (ntfs_inode_close(ni))
865		set_fuse_error(&res);
866	free(path);
867	if (stream_name_len)
868		free(stream_name);
869	return res;
870}
871
872static int ntfs_fuse_chmod(const char *path,
873		mode_t mode __attribute__((unused)))
874{
875	if (ntfs_fuse_is_named_data_stream(path))
876		return -EINVAL; /* n/a for named data streams. */
877	if (ctx->silent)
878		return 0;
879	return -EOPNOTSUPP;
880}
881
882static int ntfs_fuse_chown(const char *path, uid_t uid, gid_t gid)
883{
884	if (ntfs_fuse_is_named_data_stream(path))
885		return -EINVAL; /* n/a for named data streams. */
886	if (ctx->silent)
887		return 0;
888	if (uid == ctx->uid && gid == ctx->gid)
889		return 0;
890	return -EOPNOTSUPP;
891}
892
893static int ntfs_fuse_create(const char *org_path, dev_t type, dev_t dev,
894		const char *target)
895{
896	char *name;
897	ntfschar *uname = NULL, *utarget = NULL;
898	ntfs_inode *dir_ni = NULL, *ni;
899	char *path;
900	int res = 0, uname_len, utarget_len;
901
902	path = strdup(org_path);
903	if (!path)
904		return -errno;
905	/* Generate unicode filename. */
906	name = strrchr(path, '/');
907	name++;
908	uname_len = ntfs_mbstoucs(name, &uname);
909	if (uname_len < 0) {
910		res = -errno;
911		goto exit;
912	}
913	/* Open parent directory. */
914	*name = 0;
915	dir_ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
916	if (!dir_ni) {
917		res = -errno;
918		goto exit;
919	}
920	/* Create object specified in @type. */
921	switch (type) {
922		case S_IFCHR:
923		case S_IFBLK:
924			ni = ntfs_create_device(dir_ni, uname, uname_len, type,
925					dev);
926			break;
927		case S_IFLNK:
928			utarget_len = ntfs_mbstoucs(target, &utarget);
929			if (utarget_len < 0) {
930				res = -errno;
931				goto exit;
932			}
933			ni = ntfs_create_symlink(dir_ni, uname, uname_len,
934					utarget, utarget_len);
935			break;
936		default:
937			ni = ntfs_create(dir_ni, uname, uname_len, type);
938			break;
939	}
940	if (ni) {
941		if (ntfs_inode_close(ni))
942			set_fuse_error(&res);
943		ntfs_fuse_update_times(dir_ni, NTFS_UPDATE_MCTIME);
944	} else
945		res = -errno;
946exit:
947	free(uname);
948	if (ntfs_inode_close(dir_ni))
949		set_fuse_error(&res);
950	if (utarget)
951		free(utarget);
952	free(path);
953	return res;
954}
955
956static int ntfs_fuse_create_stream(const char *path,
957		ntfschar *stream_name, const int stream_name_len)
958{
959	ntfs_inode *ni;
960	int res = 0;
961
962	ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
963	if (!ni) {
964		res = -errno;
965		if (res == -ENOENT) {
966			/*
967			 * If such file does not exist, create it and try once
968			 * again to add stream to it.
969			 */
970			res = ntfs_fuse_create(path, S_IFREG, 0, NULL);
971			if (!res)
972				return ntfs_fuse_create_stream(path,
973						stream_name, stream_name_len);
974			else
975				res = -errno;
976		}
977		return res;
978	}
979	if (ntfs_attr_add(ni, AT_DATA, stream_name, stream_name_len, NULL, 0))
980		res = -errno;
981	if (ntfs_inode_close(ni))
982		set_fuse_error(&res);
983	return res;
984}
985
986static int ntfs_fuse_mknod_common(const char *org_path, mode_t mode, dev_t dev)
987{
988	char *path = NULL;
989	ntfschar *stream_name;
990	int stream_name_len;
991	int res = 0;
992
993	stream_name_len = ntfs_fuse_parse_path(org_path, &path, &stream_name);
994	if (stream_name_len < 0)
995		return stream_name_len;
996	if (stream_name_len && !S_ISREG(mode)) {
997		res = -EINVAL;
998		goto exit;
999	}
1000	if (!stream_name_len)
1001		res = ntfs_fuse_create(path, mode & S_IFMT, dev, NULL);
1002	else
1003		res = ntfs_fuse_create_stream(path, stream_name,
1004				stream_name_len);
1005exit:
1006	free(path);
1007	if (stream_name_len)
1008		free(stream_name);
1009	return res;
1010}
1011
1012static int ntfs_fuse_mknod(const char *path, mode_t mode, dev_t dev)
1013{
1014	return ntfs_fuse_mknod_common(path, mode, dev);
1015}
1016
1017static int ntfs_fuse_create_file(const char *path, mode_t mode,
1018			    struct fuse_file_info *fi __attribute__((unused)))
1019{
1020	return ntfs_fuse_mknod_common(path, mode, 0);
1021}
1022
1023static int ntfs_fuse_symlink(const char *to, const char *from)
1024{
1025	if (ntfs_fuse_is_named_data_stream(from))
1026		return -EINVAL; /* n/a for named data streams. */
1027	return ntfs_fuse_create(from, S_IFLNK, 0, to);
1028}
1029
1030static int ntfs_fuse_link(const char *old_path, const char *new_path)
1031{
1032	char *name;
1033	ntfschar *uname = NULL;
1034	ntfs_inode *dir_ni = NULL, *ni;
1035	char *path;
1036	int res = 0, uname_len;
1037
1038	if (ntfs_fuse_is_named_data_stream(old_path))
1039		return -EINVAL; /* n/a for named data streams. */
1040	if (ntfs_fuse_is_named_data_stream(new_path))
1041		return -EINVAL; /* n/a for named data streams. */
1042	path = strdup(new_path);
1043	if (!path)
1044		return -errno;
1045	/* Open file for which create hard link. */
1046	ni = ntfs_pathname_to_inode(ctx->vol, NULL, old_path);
1047	if (!ni) {
1048		res = -errno;
1049		goto exit;
1050	}
1051
1052	/* Generate unicode filename. */
1053	name = strrchr(path, '/');
1054	name++;
1055	uname_len = ntfs_mbstoucs(name, &uname);
1056	if (uname_len < 0) {
1057		res = -errno;
1058		goto exit;
1059	}
1060	/* Open parent directory. */
1061	*name = 0;
1062	dir_ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
1063	if (!dir_ni) {
1064		res = -errno;
1065		goto exit;
1066	}
1067
1068	if (ntfs_link(ni, dir_ni, uname, uname_len)) {
1069		res = -errno;
1070		goto exit;
1071	}
1072
1073	ntfs_fuse_update_times(ni, NTFS_UPDATE_CTIME);
1074	ntfs_fuse_update_times(dir_ni, NTFS_UPDATE_MCTIME);
1075exit:
1076	/*
1077	 * Must close dir_ni first otherwise ntfs_inode_sync_file_name(ni)
1078	 * may fail because ni may not be in parent's index on the disk yet.
1079	 */
1080	if (ntfs_inode_close(dir_ni))
1081		set_fuse_error(&res);
1082	if (ntfs_inode_close(ni))
1083		set_fuse_error(&res);
1084	free(uname);
1085	free(path);
1086	return res;
1087}
1088
1089static int ntfs_fuse_rm(const char *org_path)
1090{
1091	char *name;
1092	ntfschar *uname = NULL;
1093	ntfs_inode *dir_ni = NULL, *ni;
1094	char *path;
1095	int res = 0, uname_len;
1096
1097	path = strdup(org_path);
1098	if (!path)
1099		return -errno;
1100	/* Open object for delete. */
1101	ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
1102	if (!ni) {
1103		res = -errno;
1104		goto exit;
1105	}
1106	/* Generate unicode filename. */
1107	name = strrchr(path, '/');
1108	name++;
1109	uname_len = ntfs_mbstoucs(name, &uname);
1110	if (uname_len < 0) {
1111		res = -errno;
1112		goto exit;
1113	}
1114	/* Open parent directory. */
1115	*name = 0;
1116	dir_ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
1117	if (!dir_ni) {
1118		res = -errno;
1119		goto exit;
1120	}
1121
1122	if (ntfs_delete(ni, dir_ni, uname, uname_len))
1123		res = -errno;
1124	/* ntfs_delete() always closes ni and dir_ni */
1125	ni = dir_ni = NULL;
1126exit:
1127	if (ntfs_inode_close(dir_ni))
1128		set_fuse_error(&res);
1129	if (ntfs_inode_close(ni))
1130		set_fuse_error(&res);
1131	free(uname);
1132	free(path);
1133	return res;
1134}
1135
1136static int ntfs_fuse_rm_stream(const char *path, ntfschar *stream_name,
1137		const int stream_name_len)
1138{
1139	ntfs_inode *ni;
1140	int res = 0;
1141
1142	ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
1143	if (!ni)
1144		return -errno;
1145
1146	if (ntfs_attr_remove(ni, AT_DATA, stream_name, stream_name_len))
1147		res = -errno;
1148
1149	if (ntfs_inode_close(ni))
1150		set_fuse_error(&res);
1151	return res;
1152}
1153
1154static int ntfs_fuse_unlink(const char *org_path)
1155{
1156	char *path = NULL;
1157	ntfschar *stream_name;
1158	int stream_name_len;
1159	int res = 0;
1160
1161	stream_name_len = ntfs_fuse_parse_path(org_path, &path, &stream_name);
1162	if (stream_name_len < 0)
1163		return stream_name_len;
1164	if (!stream_name_len)
1165		res = ntfs_fuse_rm(path);
1166	else
1167		res = ntfs_fuse_rm_stream(path, stream_name, stream_name_len);
1168	free(path);
1169	if (stream_name_len)
1170		free(stream_name);
1171	return res;
1172}
1173
1174static int ntfs_fuse_safe_rename(const char *old_path,
1175				 const char *new_path,
1176				 const char *tmp)
1177{
1178	int ret;
1179
1180	ntfs_log_trace("Entering\n");
1181
1182	ret = ntfs_fuse_link(new_path, tmp);
1183	if (ret)
1184		return ret;
1185
1186	ret = ntfs_fuse_unlink(new_path);
1187	if (!ret) {
1188
1189		ret = ntfs_fuse_link(old_path, new_path);
1190		if (ret)
1191			goto restore;
1192
1193		ret = ntfs_fuse_unlink(old_path);
1194		if (ret) {
1195			if (ntfs_fuse_unlink(new_path))
1196				goto err;
1197			goto restore;
1198		}
1199	}
1200
1201	goto cleanup;
1202restore:
1203	if (ntfs_fuse_link(tmp, new_path)) {
1204err:
1205		ntfs_log_perror("Rename failed. Existing file '%s' was renamed "
1206				"to '%s'", new_path, tmp);
1207	} else {
1208cleanup:
1209		ntfs_fuse_unlink(tmp);
1210	}
1211	return 	ret;
1212}
1213
1214static int ntfs_fuse_rename_existing_dest(const char *old_path, const char *new_path)
1215{
1216	int ret, len;
1217	char *tmp;
1218	const char *ext = ".ntfs-3g-";
1219
1220	ntfs_log_trace("Entering\n");
1221
1222	len = strlen(new_path) + strlen(ext) + 10 + 1; /* wc(str(2^32)) + \0 */
1223	tmp = ntfs_malloc(len);
1224	if (!tmp)
1225		return -errno;
1226
1227	ret = snprintf(tmp, len, "%s%s%010d", new_path, ext, ++ntfs_sequence);
1228	if (ret != len - 1) {
1229		ntfs_log_error("snprintf failed: %d != %d\n", ret, len - 1);
1230		ret = -EOVERFLOW;
1231	} else
1232		ret = ntfs_fuse_safe_rename(old_path, new_path, tmp);
1233
1234	free(tmp);
1235	return 	ret;
1236}
1237
1238static int ntfs_fuse_rename(const char *old_path, const char *new_path)
1239{
1240	int ret, stream_name_len;
1241	char *path = NULL;
1242	ntfschar *stream_name;
1243	ntfs_inode *ni;
1244
1245	ntfs_log_debug("rename: old: '%s'  new: '%s'\n", old_path, new_path);
1246
1247	/*
1248	 *  FIXME: Rename should be atomic.
1249	 */
1250	stream_name_len = ntfs_fuse_parse_path(new_path, &path, &stream_name);
1251	if (stream_name_len < 0)
1252		return stream_name_len;
1253
1254	ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
1255	if (ni) {
1256		ret = ntfs_check_empty_dir(ni);
1257		if (ret < 0) {
1258			ret = -errno;
1259			ntfs_inode_close(ni);
1260			goto out;
1261		}
1262
1263		if (ntfs_inode_close(ni)) {
1264			set_fuse_error(&ret);
1265			goto out;
1266		}
1267
1268		ret = ntfs_fuse_rename_existing_dest(old_path, new_path);
1269		goto out;
1270	}
1271
1272	ret = ntfs_fuse_link(old_path, new_path);
1273	if (ret)
1274		goto out;
1275
1276	ret = ntfs_fuse_unlink(old_path);
1277	if (ret)
1278		ntfs_fuse_unlink(new_path);
1279out:
1280	free(path);
1281	if (stream_name_len)
1282		free(stream_name);
1283	return ret;
1284}
1285
1286static int ntfs_fuse_mkdir(const char *path,
1287		mode_t mode __attribute__((unused)))
1288{
1289	if (ntfs_fuse_is_named_data_stream(path))
1290		return -EINVAL; /* n/a for named data streams. */
1291	return ntfs_fuse_create(path, S_IFDIR, 0, NULL);
1292}
1293
1294static int ntfs_fuse_rmdir(const char *path)
1295{
1296	if (ntfs_fuse_is_named_data_stream(path))
1297		return -EINVAL; /* n/a for named data streams. */
1298	return ntfs_fuse_rm(path);
1299}
1300
1301static int ntfs_fuse_utime(const char *path, struct utimbuf *buf)
1302{
1303	ntfs_inode *ni;
1304	int res = 0;
1305
1306	if (ntfs_fuse_is_named_data_stream(path))
1307		return -EINVAL; /* n/a for named data streams. */
1308	ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
1309	if (!ni)
1310		return -errno;
1311
1312	if (buf) {
1313		ni->last_access_time = buf->actime;
1314		ni->last_data_change_time = buf->modtime;
1315		ntfs_fuse_update_times(ni, NTFS_UPDATE_CTIME);
1316	} else
1317		ntfs_inode_update_times(ni, NTFS_UPDATE_AMCTIME);
1318
1319	if (ntfs_inode_close(ni))
1320		set_fuse_error(&res);
1321	return res;
1322}
1323
1324static int ntfs_fuse_bmap(const char *path, size_t blocksize, uint64_t *idx)
1325{
1326	ntfs_inode *ni;
1327	ntfs_attr *na;
1328	LCN lcn;
1329	int ret = 0;
1330	int cl_per_bl = ctx->vol->cluster_size / blocksize;
1331
1332	if (blocksize > ctx->vol->cluster_size)
1333		return -EINVAL;
1334
1335	if (ntfs_fuse_is_named_data_stream(path))
1336		return -EINVAL;
1337
1338	ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
1339	if (!ni)
1340		return -errno;
1341
1342	na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
1343	if (!na) {
1344		ret = -errno;
1345		goto close_inode;
1346	}
1347
1348	if (NAttrCompressed(na) || NAttrEncrypted(na) || !NAttrNonResident(na)){
1349		ret = -EINVAL;
1350		goto close_attr;
1351	}
1352
1353	if (ntfs_attr_map_whole_runlist(na)) {
1354		ret = -errno;
1355		goto close_attr;
1356	}
1357
1358	lcn = ntfs_rl_vcn_to_lcn(na->rl, *idx / cl_per_bl);
1359	*idx = (lcn > 0) ? lcn * cl_per_bl + *idx % cl_per_bl : 0;
1360
1361close_attr:
1362	ntfs_attr_close(na);
1363close_inode:
1364	if (ntfs_inode_close(ni))
1365		set_fuse_error(&ret);
1366	return ret;
1367}
1368
1369#ifdef HAVE_SETXATTR
1370
1371static const char nf_ns_xattr_preffix[] = "user.";
1372static const int nf_ns_xattr_preffix_len = 5;
1373
1374static int ntfs_fuse_listxattr(const char *path, char *list, size_t size)
1375{
1376	ntfs_attr_search_ctx *actx = NULL;
1377	ntfs_inode *ni;
1378	char *to = list;
1379	int ret = 0;
1380
1381	if (ctx->streams != NF_STREAMS_INTERFACE_XATTR)
1382		return -EOPNOTSUPP;
1383	ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
1384	if (!ni)
1385		return -errno;
1386	actx = ntfs_attr_get_search_ctx(ni, NULL);
1387	if (!actx) {
1388		ret = -errno;
1389		ntfs_inode_close(ni);
1390		goto exit;
1391	}
1392	while (!ntfs_attr_lookup(AT_DATA, NULL, 0, CASE_SENSITIVE,
1393				0, NULL, 0, actx)) {
1394		char *tmp_name = NULL;
1395		int tmp_name_len;
1396
1397		if (!actx->attr->name_length)
1398			continue;
1399		tmp_name_len = ntfs_ucstombs((ntfschar *)((u8*)actx->attr +
1400				le16_to_cpu(actx->attr->name_offset)),
1401				actx->attr->name_length, &tmp_name, 0);
1402		if (tmp_name_len < 0) {
1403			ret = -errno;
1404			goto exit;
1405		}
1406		ret += tmp_name_len + nf_ns_xattr_preffix_len + 1;
1407		if (size) {
1408			if ((size_t)ret <= size) {
1409				strcpy(to, nf_ns_xattr_preffix);
1410				to += nf_ns_xattr_preffix_len;
1411				strncpy(to, tmp_name, tmp_name_len);
1412				to += tmp_name_len;
1413				*to = 0;
1414				to++;
1415			} else {
1416				free(tmp_name);
1417				ret = -ERANGE;
1418				goto exit;
1419			}
1420		}
1421		free(tmp_name);
1422	}
1423	if (errno != ENOENT)
1424		ret = -errno;
1425exit:
1426	if (actx)
1427		ntfs_attr_put_search_ctx(actx);
1428	if (ntfs_inode_close(ni))
1429		set_fuse_error(&ret);
1430	return ret;
1431}
1432
1433static int ntfs_fuse_getxattr_windows(const char *path, const char *name,
1434				char *value, size_t size)
1435{
1436	ntfs_attr_search_ctx *actx = NULL;
1437	ntfs_inode *ni;
1438	char *to = value;
1439	int ret = 0;
1440
1441	if (strcmp(name, "ntfs.streams.list"))
1442		return -EOPNOTSUPP;
1443	ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
1444	if (!ni)
1445		return -errno;
1446	actx = ntfs_attr_get_search_ctx(ni, NULL);
1447	if (!actx) {
1448		ret = -errno;
1449		ntfs_inode_close(ni);
1450		goto exit;
1451	}
1452	while (!ntfs_attr_lookup(AT_DATA, NULL, 0, CASE_SENSITIVE,
1453				0, NULL, 0, actx)) {
1454		char *tmp_name = NULL;
1455		int tmp_name_len;
1456
1457		if (!actx->attr->name_length)
1458			continue;
1459		tmp_name_len = ntfs_ucstombs((ntfschar *)((u8*)actx->attr +
1460				le16_to_cpu(actx->attr->name_offset)),
1461				actx->attr->name_length, &tmp_name, 0);
1462		if (tmp_name_len < 0) {
1463			ret = -errno;
1464			goto exit;
1465		}
1466		if (ret)
1467			ret++; /* For space delimiter. */
1468		ret += tmp_name_len;
1469		if (size) {
1470			if ((size_t)ret <= size) {
1471				/* Don't add space to the beginning of line. */
1472				if (to != value) {
1473					*to = '\0';
1474					to++;
1475				}
1476				strncpy(to, tmp_name, tmp_name_len);
1477				to += tmp_name_len;
1478			} else {
1479				free(tmp_name);
1480				ret = -ERANGE;
1481				goto exit;
1482			}
1483		}
1484		free(tmp_name);
1485	}
1486	if (errno != ENOENT)
1487		ret = -errno;
1488exit:
1489	if (actx)
1490		ntfs_attr_put_search_ctx(actx);
1491	if (ntfs_inode_close(ni))
1492		set_fuse_error(&ret);
1493	return ret;
1494}
1495
1496static int ntfs_fuse_getxattr(const char *path, const char *name,
1497				char *value, size_t size)
1498{
1499	ntfs_inode *ni;
1500	ntfs_attr *na = NULL;
1501	ntfschar *lename = NULL;
1502	int res, lename_len;
1503
1504	if (ctx->streams == NF_STREAMS_INTERFACE_WINDOWS)
1505		return ntfs_fuse_getxattr_windows(path, name, value, size);
1506	if (ctx->streams != NF_STREAMS_INTERFACE_XATTR)
1507		return -EOPNOTSUPP;
1508	if (strncmp(name, nf_ns_xattr_preffix, nf_ns_xattr_preffix_len) ||
1509			strlen(name) == (size_t)nf_ns_xattr_preffix_len)
1510		return -ENODATA;
1511	ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
1512	if (!ni)
1513		return -errno;
1514	lename_len = ntfs_mbstoucs(name + nf_ns_xattr_preffix_len, &lename);
1515	if (lename_len == -1) {
1516		res = -errno;
1517		goto exit;
1518	}
1519	na = ntfs_attr_open(ni, AT_DATA, lename, lename_len);
1520	if (!na) {
1521		res = -ENODATA;
1522		goto exit;
1523	}
1524	if (size) {
1525		if (size >= na->data_size) {
1526			res = ntfs_attr_pread(na, 0, na->data_size, value);
1527			if (res != na->data_size)
1528				res = -errno;
1529		} else
1530			res = -ERANGE;
1531	} else
1532		res = na->data_size;
1533exit:
1534	if (na)
1535		ntfs_attr_close(na);
1536	free(lename);
1537	if (ntfs_inode_close(ni))
1538		set_fuse_error(&res);
1539	return res;
1540}
1541
1542static int ntfs_fuse_setxattr(const char *path, const char *name,
1543				const char *value, size_t size, int flags)
1544{
1545	ntfs_inode *ni;
1546	ntfs_attr *na = NULL;
1547	ntfschar *lename = NULL;
1548	int res, lename_len;
1549
1550	if (ctx->streams != NF_STREAMS_INTERFACE_XATTR)
1551		return -EOPNOTSUPP;
1552	if (strncmp(name, nf_ns_xattr_preffix, nf_ns_xattr_preffix_len) ||
1553			strlen(name) == (size_t)nf_ns_xattr_preffix_len)
1554		return -EOPNOTSUPP;
1555	ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
1556	if (!ni)
1557		return -errno;
1558	lename_len = ntfs_mbstoucs(name + nf_ns_xattr_preffix_len, &lename);
1559	if (lename_len == -1) {
1560		res = -errno;
1561		goto exit;
1562	}
1563	na = ntfs_attr_open(ni, AT_DATA, lename, lename_len);
1564	if (na && flags == XATTR_CREATE) {
1565		res = -EEXIST;
1566		goto exit;
1567	}
1568	if (!na) {
1569		if (flags == XATTR_REPLACE) {
1570			res = -ENODATA;
1571			goto exit;
1572		}
1573		if (ntfs_attr_add(ni, AT_DATA, lename, lename_len, NULL, 0)) {
1574			res = -errno;
1575			goto exit;
1576		}
1577		na = ntfs_attr_open(ni, AT_DATA, lename, lename_len);
1578		if (!na) {
1579			res = -errno;
1580			goto exit;
1581		}
1582	} else {
1583		if (ntfs_attr_truncate(na, (s64)size)) {
1584			res = -errno;
1585			goto exit;
1586		}
1587	}
1588	res = ntfs_attr_pwrite(na, 0, size, value);
1589	if (res != (s64) size)
1590		res = -errno;
1591	else
1592		res = 0;
1593exit:
1594	if (na)
1595		ntfs_attr_close(na);
1596	free(lename);
1597	if (ntfs_inode_close(ni))
1598		set_fuse_error(&res);
1599	return res;
1600}
1601
1602static int ntfs_fuse_removexattr(const char *path, const char *name)
1603{
1604	ntfs_inode *ni;
1605	ntfschar *lename = NULL;
1606	int res = 0, lename_len;
1607
1608
1609	if (ctx->streams != NF_STREAMS_INTERFACE_XATTR)
1610		return -EOPNOTSUPP;
1611	if (strncmp(name, nf_ns_xattr_preffix, nf_ns_xattr_preffix_len) ||
1612			strlen(name) == (size_t)nf_ns_xattr_preffix_len)
1613		return -ENODATA;
1614	ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
1615	if (!ni)
1616		return -errno;
1617	lename_len = ntfs_mbstoucs(name + nf_ns_xattr_preffix_len, &lename);
1618	if (lename_len == -1) {
1619		res = -errno;
1620		goto exit;
1621	}
1622	if (ntfs_attr_remove(ni, AT_DATA, lename, lename_len)) {
1623		if (errno == ENOENT)
1624			errno = ENODATA;
1625		res = -errno;
1626	}
1627
1628exit:
1629	free(lename);
1630	if (ntfs_inode_close(ni))
1631		set_fuse_error(&res);
1632	return res;
1633}
1634
1635#endif /* HAVE_SETXATTR */
1636
1637static void ntfs_close(void)
1638{
1639	if (!ctx)
1640		return;
1641
1642	if (!ctx->vol)
1643		return;
1644
1645	if (ctx->mounted)
1646		ntfs_log_info("Unmounting %s (%s)\n", opts.device,
1647			      ctx->vol->vol_name);
1648
1649	if (ntfs_umount(ctx->vol, FALSE))
1650		ntfs_log_perror("Failed to close volume %s", opts.device);
1651    /* Foxconn added start pling 05/05/2009 */
1652    /* Remove file that stores the volname */
1653    else {
1654        char *devname;
1655        char filename[64];
1656
1657        devname = strstr(opts.device, "sd");
1658        if (devname) {
1659            sprintf(filename, USB_VOL_NAME_FILE, devname);
1660            unlink(filename);
1661        }
1662    }
1663    /* Foxconn added end pling 05/05/2009 */
1664
1665	ctx->vol = NULL;
1666}
1667
1668static void ntfs_fuse_destroy2(void *unused __attribute__((unused)))
1669{
1670	ntfs_close();
1671}
1672
1673static struct fuse_operations ntfs_3g_ops = {
1674	.getattr	= ntfs_fuse_getattr,
1675	.readlink	= ntfs_fuse_readlink,
1676	.readdir	= ntfs_fuse_readdir,
1677	.open		= ntfs_fuse_open,
1678	.read		= ntfs_fuse_read,
1679	.write		= ntfs_fuse_write,
1680	.truncate	= ntfs_fuse_truncate,
1681	.statfs		= ntfs_fuse_statfs,
1682	.chmod		= ntfs_fuse_chmod,
1683	.chown		= ntfs_fuse_chown,
1684	.create		= ntfs_fuse_create_file,
1685	.mknod		= ntfs_fuse_mknod,
1686	.symlink	= ntfs_fuse_symlink,
1687	.link		= ntfs_fuse_link,
1688	.unlink		= ntfs_fuse_unlink,
1689	.rename		= ntfs_fuse_rename,
1690	.mkdir		= ntfs_fuse_mkdir,
1691	.rmdir		= ntfs_fuse_rmdir,
1692	.utime		= ntfs_fuse_utime,
1693	.bmap		= ntfs_fuse_bmap,
1694	.destroy        = ntfs_fuse_destroy2,
1695#ifdef HAVE_SETXATTR
1696	.getxattr	= ntfs_fuse_getxattr,
1697	.setxattr	= ntfs_fuse_setxattr,
1698	.removexattr	= ntfs_fuse_removexattr,
1699	.listxattr	= ntfs_fuse_listxattr,
1700#endif /* HAVE_SETXATTR */
1701#if defined(__APPLE__) || defined(__DARWIN__)
1702	.init		= ntfs_macfuse_init,
1703	/* MacFUSE extensions. */
1704	.getxtimes	= ntfs_macfuse_getxtimes,
1705	.setcrtime	= ntfs_macfuse_setcrtime,
1706	.setbkuptime	= ntfs_macfuse_setbkuptime
1707#endif /* defined(__APPLE__) || defined(__DARWIN__) */
1708};
1709
1710static int ntfs_fuse_init(void)
1711{
1712	ctx = ntfs_calloc(sizeof(ntfs_fuse_context_t));
1713	if (!ctx)
1714		return -1;
1715
1716	*ctx = (ntfs_fuse_context_t) {
1717		.uid     = getuid(),
1718		.gid     = getgid(),
1719#if defined(linux)
1720		.streams = NF_STREAMS_INTERFACE_XATTR,
1721#else
1722		.streams = NF_STREAMS_INTERFACE_NONE,
1723#endif
1724		.atime   = ATIME_RELATIVE,
1725		.silent  = TRUE,
1726		.recover = TRUE
1727	};
1728	return 0;
1729}
1730
1731static int ntfs_open(const char *device)
1732{
1733	unsigned long flags = 0;
1734
1735	if (!ctx->blkdev)
1736		flags |= MS_EXCLUSIVE;
1737	if (ctx->ro)
1738		flags |= MS_RDONLY;
1739	if (ctx->recover)
1740		flags |= MS_RECOVER;
1741	if (ctx->hiberfile)
1742		flags |= MS_IGNORE_HIBERFILE;
1743
1744	ctx->vol = ntfs_mount(device, flags);
1745	if (!ctx->vol) {
1746		ntfs_log_perror("Failed to mount '%s'", device);
1747		goto err_out;
1748	}
1749
1750	ctx->vol->free_clusters = ntfs_attr_get_free_bits(ctx->vol->lcnbmp_na);
1751	if (ctx->vol->free_clusters < 0) {
1752		ntfs_log_perror("Failed to read NTFS $Bitmap");
1753		goto err_out;
1754	}
1755
1756	ctx->vol->free_mft_records = ntfs_get_nr_free_mft_records(ctx->vol);
1757	if (ctx->vol->free_mft_records < 0) {
1758		ntfs_log_perror("Failed to calculate free MFT records");
1759		goto err_out;
1760	}
1761
1762	if (ctx->hiberfile && ntfs_volume_check_hiberfile(ctx->vol, 0)) {
1763		if (errno != EPERM)
1764			goto err_out;
1765		if (ntfs_fuse_rm("/hiberfil.sys"))
1766			goto err_out;
1767	}
1768
1769	errno = 0;
1770err_out:
1771	return ntfs_volume_error(errno);
1772
1773}
1774
1775#define STRAPPEND_MAX_INSIZE   8192
1776#define strappend_is_large(x) ((x) > STRAPPEND_MAX_INSIZE)
1777
1778static int strappend(char **dest, const char *append)
1779{
1780	char *p;
1781	size_t size_append, size_dest = 0;
1782
1783	if (!dest)
1784		return -1;
1785	if (!append)
1786		return 0;
1787
1788	size_append = strlen(append);
1789	if (*dest)
1790		size_dest = strlen(*dest);
1791
1792	if (strappend_is_large(size_dest) || strappend_is_large(size_append)) {
1793		errno = EOVERFLOW;
1794		ntfs_log_perror("%s: Too large input buffer", EXEC_NAME);
1795		return -1;
1796	}
1797
1798	p = realloc(*dest, size_dest + size_append + 1);
1799    	if (!p) {
1800		ntfs_log_perror("%s: Memory realloction failed", EXEC_NAME);
1801		return -1;
1802	}
1803
1804	*dest = p;
1805	strcpy(*dest + size_dest, append);
1806
1807	return 0;
1808}
1809
1810static int bogus_option_value(char *val, const char *s)
1811{
1812	if (val) {
1813		ntfs_log_error("'%s' option shouldn't have value.\n", s);
1814		return -1;
1815	}
1816	return 0;
1817}
1818
1819static int missing_option_value(char *val, const char *s)
1820{
1821	if (!val) {
1822		ntfs_log_error("'%s' option should have a value.\n", s);
1823		return -1;
1824	}
1825	return 0;
1826}
1827
1828static char *parse_mount_options(const char *orig_opts)
1829{
1830	char *options, *s, *opt, *val, *ret = NULL;
1831	BOOL no_def_opts = FALSE;
1832	int default_permissions = 0;
1833
1834	options = strdup(orig_opts ? orig_opts : "");
1835	if (!options) {
1836		ntfs_log_perror("%s: strdup failed", EXEC_NAME);
1837		return NULL;
1838	}
1839
1840	s = options;
1841	while (s && *s && (val = strsep(&s, ","))) {
1842		opt = strsep(&val, "=");
1843		if (!strcmp(opt, "ro")) { /* Read-only mount. */
1844			if (bogus_option_value(val, "ro"))
1845				goto err_exit;
1846			ctx->ro = TRUE;
1847			if (strappend(&ret, "ro,"))
1848				goto err_exit;
1849		} else if (!strcmp(opt, "noatime")) {
1850			if (bogus_option_value(val, "noatime"))
1851				goto err_exit;
1852			ctx->atime = ATIME_DISABLED;
1853		} else if (!strcmp(opt, "atime")) {
1854			if (bogus_option_value(val, "atime"))
1855				goto err_exit;
1856			ctx->atime = ATIME_ENABLED;
1857		} else if (!strcmp(opt, "relatime")) {
1858			if (bogus_option_value(val, "relatime"))
1859				goto err_exit;
1860			ctx->atime = ATIME_RELATIVE;
1861		} else if (!strcmp(opt, "fake_rw")) {
1862			if (bogus_option_value(val, "fake_rw"))
1863				goto err_exit;
1864			ctx->ro = TRUE;
1865		} else if (!strcmp(opt, "fsname")) { /* Filesystem name. */
1866			/*
1867			 * We need this to be able to check whether filesystem
1868			 * mounted or not.
1869			 */
1870			ntfs_log_error("'fsname' is unsupported option.\n");
1871			goto err_exit;
1872		} else if (!strcmp(opt, "no_def_opts")) {
1873			if (bogus_option_value(val, "no_def_opts"))
1874				goto err_exit;
1875			no_def_opts = TRUE; /* Don't add default options. */
1876		} else if (!strcmp(opt, "default_permissions")) {
1877			default_permissions = 1;
1878		} else if (!strcmp(opt, "umask")) {
1879			if (missing_option_value(val, "umask"))
1880				goto err_exit;
1881			sscanf(val, "%o", &ctx->fmask);
1882			ctx->dmask = ctx->fmask;
1883			if (ctx->fmask)
1884				default_permissions = 1;
1885		} else if (!strcmp(opt, "fmask")) {
1886			if (missing_option_value(val, "fmask"))
1887				goto err_exit;
1888			sscanf(val, "%o", &ctx->fmask);
1889			if (ctx->fmask)
1890				default_permissions = 1;
1891		} else if (!strcmp(opt, "dmask")) {
1892			if (missing_option_value(val, "dmask"))
1893				goto err_exit;
1894			sscanf(val, "%o", &ctx->dmask);
1895			if (ctx->dmask)
1896				default_permissions = 1;
1897		} else if (!strcmp(opt, "uid")) {
1898			if (missing_option_value(val, "uid"))
1899				goto err_exit;
1900			sscanf(val, "%i", &ctx->uid);
1901		       	default_permissions = 1;
1902		} else if (!strcmp(opt, "gid")) {
1903			if (missing_option_value(val, "gid"))
1904				goto err_exit;
1905			sscanf(val, "%i", &ctx->gid);
1906		       	default_permissions = 1;
1907		} else if (!strcmp(opt, "show_sys_files")) {
1908			if (bogus_option_value(val, "show_sys_files"))
1909				goto err_exit;
1910			ctx->show_sys_files = TRUE;
1911		} else if (!strcmp(opt, "silent")) {
1912			if (bogus_option_value(val, "silent"))
1913				goto err_exit;
1914			ctx->silent = TRUE;
1915		} else if (!strcmp(opt, "recover")) {
1916			if (bogus_option_value(val, "recover"))
1917				goto err_exit;
1918			ctx->recover = TRUE;
1919		} else if (!strcmp(opt, "norecover")) {
1920			if (bogus_option_value(val, "norecover"))
1921				goto err_exit;
1922			ctx->recover = FALSE;
1923		} else if (!strcmp(opt, "remove_hiberfile")) {
1924			if (bogus_option_value(val, "remove_hiberfile"))
1925				goto err_exit;
1926			ctx->hiberfile = TRUE;
1927		} else if (!strcmp(opt, "locale")) {
1928			if (missing_option_value(val, "locale"))
1929				goto err_exit;
1930			setlocale(LC_ALL, val);
1931		} else if (!strcmp(opt, "streams_interface")) {
1932			if (missing_option_value(val, "streams_interface"))
1933				goto err_exit;
1934			if (!strcmp(val, "none"))
1935				ctx->streams = NF_STREAMS_INTERFACE_NONE;
1936			else if (!strcmp(val, "xattr"))
1937				ctx->streams = NF_STREAMS_INTERFACE_XATTR;
1938			else if (!strcmp(val, "windows"))
1939				ctx->streams = NF_STREAMS_INTERFACE_WINDOWS;
1940			else {
1941				ntfs_log_error("Invalid named data streams "
1942						"access interface.\n");
1943				goto err_exit;
1944			}
1945		} else if (!strcmp(opt, "noauto")) {
1946			/* Don't pass noauto option to fuse. */
1947		} else if (!strcmp(opt, "debug")) {
1948			if (bogus_option_value(val, "debug"))
1949				goto err_exit;
1950			ctx->debug = TRUE;
1951			ntfs_log_set_levels(NTFS_LOG_LEVEL_DEBUG);
1952			ntfs_log_set_levels(NTFS_LOG_LEVEL_TRACE);
1953		} else if (!strcmp(opt, "no_detach")) {
1954			if (bogus_option_value(val, "no_detach"))
1955				goto err_exit;
1956			ctx->no_detach = TRUE;
1957		} else if (!strcmp(opt, "remount")) {
1958			ntfs_log_error("Remounting is not supported at present."
1959					" You have to umount volume and then "
1960					"mount it once again.\n");
1961			goto err_exit;
1962		} else if (!strcmp(opt, "blksize")) {
1963			ntfs_log_info("WARNING: blksize option is ignored "
1964				      "because ntfs-3g must calculate it.\n");
1965		} else { /* Probably FUSE option. */
1966			if (strappend(&ret, opt))
1967				goto err_exit;
1968			if (val) {
1969				if (strappend(&ret, "="))
1970					goto err_exit;
1971				if (strappend(&ret, val))
1972					goto err_exit;
1973			}
1974			if (strappend(&ret, ","))
1975				goto err_exit;
1976		}
1977	}
1978	if (!no_def_opts && strappend(&ret, def_opts))
1979		goto err_exit;
1980	if (default_permissions && strappend(&ret, "default_permissions,"))
1981		goto err_exit;
1982
1983	if (ctx->atime == ATIME_RELATIVE && strappend(&ret, "relatime,"))
1984		goto err_exit;
1985	else if (ctx->atime == ATIME_ENABLED && strappend(&ret, "atime,"))
1986		goto err_exit;
1987	else if (ctx->atime == ATIME_DISABLED && strappend(&ret, "noatime,"))
1988		goto err_exit;
1989
1990	if (strappend(&ret, "fsname="))
1991		goto err_exit;
1992	if (strappend(&ret, opts.device))
1993		goto err_exit;
1994exit:
1995	free(options);
1996	return ret;
1997err_exit:
1998	free(ret);
1999	ret = NULL;
2000	goto exit;
2001}
2002
2003static void usage(void)
2004{
2005	ntfs_log_info(usage_msg, EXEC_NAME, VERSION, FUSE_TYPE, fuse_version(),
2006		      EXEC_NAME, ntfs_home);
2007}
2008
2009#ifndef HAVE_REALPATH
2010/* If there is no realpath() on the system, provide a dummy one. */
2011static char *realpath(const char *path, char *resolved_path)
2012{
2013	strncpy(resolved_path, path, PATH_MAX);
2014	resolved_path[PATH_MAX] = '\0';
2015	return resolved_path;
2016}
2017#endif
2018
2019/**
2020 * parse_options - Read and validate the programs command line
2021 * Read the command line, verify the syntax and parse the options.
2022 *
2023 * Return:   0 success, -1 error.
2024 */
2025static int parse_options(int argc, char *argv[])
2026{
2027	int c;
2028
2029	static const char *sopt = "-o:hvV";
2030	static const struct option lopt[] = {
2031		{ "options",	 required_argument,	NULL, 'o' },
2032		{ "help",	 no_argument,		NULL, 'h' },
2033		{ "verbose",	 no_argument,		NULL, 'v' },
2034		{ "version",	 no_argument,		NULL, 'V' },
2035		{ NULL,		 0,			NULL,  0  }
2036	};
2037
2038	opterr = 0; /* We'll handle the errors, thank you. */
2039
2040	while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) {
2041		switch (c) {
2042		case 1:	/* A non-option argument */
2043			if (!opts.device) {
2044				opts.device = ntfs_malloc(PATH_MAX + 1);
2045				if (!opts.device)
2046					return -1;
2047
2048				/* Canonicalize device name (mtab, etc) */
2049				if (!realpath(optarg, opts.device)) {
2050					ntfs_log_perror("%s: Failed to access "
2051					     "volume '%s'", EXEC_NAME, optarg);
2052					free(opts.device);
2053					opts.device = NULL;
2054					return -1;
2055				}
2056			} else if (!opts.mnt_point) {
2057				opts.mnt_point = optarg;
2058			} else {
2059				ntfs_log_error("%s: You must specify exactly one "
2060						"device and exactly one mount "
2061						"point.\n", EXEC_NAME);
2062				return -1;
2063			}
2064			break;
2065		case 'o':
2066			if (opts.options)
2067				if (strappend(&opts.options, ","))
2068					return -1;
2069			if (strappend(&opts.options, optarg))
2070				return -1;
2071			break;
2072		case 'h':
2073			usage();
2074			exit(9);
2075		case 'v':
2076			/*
2077			 * We must handle the 'verbose' option even if
2078			 * we don't use it because mount(8) passes it.
2079			 */
2080			break;
2081		case 'V':
2082			ntfs_log_info("%s %s %s %d\n", EXEC_NAME, VERSION,
2083				      FUSE_TYPE, fuse_version());
2084			exit(0);
2085		default:
2086			ntfs_log_error("%s: Unknown option '%s'.\n", EXEC_NAME,
2087				       argv[optind - 1]);
2088			return -1;
2089		}
2090	}
2091
2092	if (!opts.device) {
2093		ntfs_log_error("%s: No device is specified.\n", EXEC_NAME);
2094		return -1;
2095	}
2096	if (!opts.mnt_point) {
2097		ntfs_log_error("%s: No mountpoint is specified.\n", EXEC_NAME);
2098		return -1;
2099	}
2100
2101	return 0;
2102}
2103
2104#if defined(linux) || defined(__uClinux__)
2105
2106static const char *dev_fuse_msg =
2107"HINT: You should be root, or make ntfs-3g setuid root, or load the FUSE\n"
2108"      kernel module as root ('modprobe fuse' or 'insmod <path_to>/fuse.ko'"
2109"      or insmod <path_to>/fuse.o'). Make also sure that the fuse device"
2110"      exists. It's usually either /dev/fuse or /dev/misc/fuse.";
2111
2112static const char *fuse26_kmod_msg =
2113"WARNING: Deficient Linux kernel detected. Some driver features are\n"
2114"         not available (swap file on NTFS, boot from NTFS by LILO), and\n"
2115"         unmount is not safe unless it's made sure the ntfs-3g process\n"
2116"         naturally terminates after calling 'umount'. If you wish this\n"
2117"         message to disappear then you should upgrade to at least kernel\n"
2118"         version 2.6.20, or request help from your distribution to fix\n"
2119"         the kernel problem. The below web page has more information:\n"
2120"         http://ntfs-3g.org/support.html#fuse26\n"
2121"\n";
2122
2123static void mknod_dev_fuse(const char *dev)
2124{
2125	struct stat st;
2126
2127	if (stat(dev, &st) && (errno == ENOENT)) {
2128		mode_t mask = umask(0);
2129		if (mknod(dev, S_IFCHR | 0666, makedev(10, 229))) {
2130			ntfs_log_perror("Failed to create '%s'", dev);
2131			if (errno == EPERM)
2132				ntfs_log_error("%s", dev_fuse_msg);
2133		}
2134		umask(mask);
2135	}
2136}
2137
2138static void create_dev_fuse(void)
2139{
2140	mknod_dev_fuse("/dev/fuse");
2141
2142#ifdef __UCLIBC__
2143	{
2144		struct stat st;
2145		/* The fuse device is under /dev/misc using devfs. */
2146		if (stat("/dev/misc", &st) && (errno == ENOENT)) {
2147			mode_t mask = umask(0);
2148			mkdir("/dev/misc", 0775);
2149			umask(mask);
2150		}
2151		mknod_dev_fuse("/dev/misc/fuse");
2152	}
2153#endif
2154}
2155
2156static fuse_fstype get_fuse_fstype(void)
2157{
2158	char buf[256];
2159	fuse_fstype fstype = FSTYPE_NONE;
2160
2161	FILE *f = fopen("/proc/filesystems", "r");
2162	if (!f) {
2163		ntfs_log_perror("Failed to open /proc/filesystems");
2164		return FSTYPE_UNKNOWN;
2165	}
2166
2167	while (fgets(buf, sizeof(buf), f)) {
2168		if (strstr(buf, "fuseblk\n")) {
2169			fstype = FSTYPE_FUSEBLK;
2170			break;
2171		}
2172		if (strstr(buf, "fuse\n"))
2173			fstype = FSTYPE_FUSE;
2174	}
2175
2176	fclose(f);
2177	return fstype;
2178}
2179
2180static fuse_fstype load_fuse_module(void)
2181{
2182	int i;
2183	struct stat st;
2184	pid_t pid;
2185	const char *cmd = "/sbin/modprobe";
2186	struct timespec req = { 0, 100000000 };   /* 100 msec */
2187	fuse_fstype fstype;
2188
2189	if (!stat(cmd, &st) && !geteuid()) {
2190		pid = fork();
2191		if (!pid) {
2192			execl(cmd, cmd, "fuse", NULL);
2193			_exit(1);
2194		} else if (pid != -1)
2195			waitpid(pid, NULL, 0);
2196	}
2197
2198	for (i = 0; i < 10; i++) {
2199		/*
2200		 * We sleep first because despite the detection of the loaded
2201		 * FUSE kernel module, fuse_mount() can still fail if it's not
2202		 * fully functional/initialized. Note, of course this is still
2203		 * unreliable but usually helps.
2204		 */
2205		nanosleep(&req, NULL);
2206		fstype = get_fuse_fstype();
2207		if (fstype != FSTYPE_NONE)
2208			break;
2209	}
2210	return fstype;
2211}
2212
2213#endif
2214
2215static struct fuse_chan *try_fuse_mount(char *parsed_options)
2216{
2217	struct fuse_chan *fc = NULL;
2218	struct fuse_args margs = FUSE_ARGS_INIT(0, NULL);
2219
2220	/* The fuse_mount() options get modified, so we always rebuild it */
2221	if ((fuse_opt_add_arg(&margs, EXEC_NAME) == -1 ||
2222	     fuse_opt_add_arg(&margs, "-o") == -1 ||
2223	     fuse_opt_add_arg(&margs, parsed_options) == -1)) {
2224		ntfs_log_error("Failed to set FUSE options.\n");
2225		goto free_args;
2226	}
2227
2228	fc = fuse_mount(opts.mnt_point, &margs);
2229free_args:
2230	fuse_opt_free_args(&margs);
2231	return fc;
2232
2233}
2234
2235static int set_fuseblk_options(char **parsed_options)
2236{
2237	char options[64];
2238	long pagesize;
2239	u32 blksize = ctx->vol->cluster_size;
2240
2241	pagesize = sysconf(_SC_PAGESIZE);
2242	if (pagesize < 1)
2243		pagesize = 4096;
2244
2245	if (blksize > (u32)pagesize)
2246		blksize = pagesize;
2247
2248	snprintf(options, sizeof(options), ",blkdev,blksize=%u", blksize);
2249	if (strappend(parsed_options, options))
2250		return -1;
2251	return 0;
2252}
2253
2254static struct fuse *mount_fuse(char *parsed_options)
2255{
2256	struct fuse *fh = NULL;
2257	struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
2258
2259	ctx->fc = try_fuse_mount(parsed_options);
2260	if (!ctx->fc)
2261		return NULL;
2262
2263	if (fuse_opt_add_arg(&args, "") == -1)
2264		goto err;
2265    /* Foxconn modified start pling 12/23/2009 */
2266    /* Use direct_io to improve NTFS write performance */
2267	//if (fuse_opt_add_arg(&args, "-ouse_ino,kernel_cache,attr_timeout=0") == -1)
2268	if (fuse_opt_add_arg(&args, "-ouse_ino,kernel_cache,attr_timeout=0,direct_io") == -1)
2269    /* Foxconn modified end pling 12/23/2009 */
2270		goto err;
2271	if (ctx->debug)
2272		if (fuse_opt_add_arg(&args, "-odebug") == -1)
2273			goto err;
2274
2275	fh = fuse_new(ctx->fc, &args , &ntfs_3g_ops, sizeof(ntfs_3g_ops), NULL);
2276	if (!fh)
2277		goto err;
2278
2279	if (fuse_set_signal_handlers(fuse_get_session(fh)))
2280		goto err_destory;
2281out:
2282	fuse_opt_free_args(&args);
2283	return fh;
2284err_destory:
2285	fuse_destroy(fh);
2286	fh = NULL;
2287err:
2288	fuse_unmount(opts.mnt_point, ctx->fc);
2289	goto out;
2290}
2291
2292static void setup_logging(char *parsed_options)
2293{
2294	if (!ctx->no_detach) {
2295		if (daemon(0, ctx->debug))
2296			ntfs_log_error("Failed to daemonize.\n");
2297		else if (!ctx->debug) {
2298#ifndef DEBUG
2299			ntfs_log_set_handler(ntfs_log_handler_syslog);
2300			/* Override default libntfs identify. */
2301			openlog(EXEC_NAME, LOG_PID, LOG_DAEMON);
2302#endif
2303		}
2304	}
2305
2306	ntfs_log_info("Version %s %s %d\n", VERSION, FUSE_TYPE, fuse_version());
2307	ntfs_log_info("Mounted %s (%s, label \"%s\", NTFS %d.%d)\n",
2308			opts.device, (ctx->ro) ? "Read-Only" : "Read-Write",
2309			ctx->vol->vol_name, ctx->vol->major_ver,
2310			ctx->vol->minor_ver);
2311	ntfs_log_info("Cmdline options: %s\n", opts.options ? opts.options : "");
2312	ntfs_log_info("Mount options: %s\n", parsed_options);
2313
2314    /* Foxconn added start pling 05/05/2009 */
2315    /* Store the volume label under /tmp for later use */
2316    FILE *fp = NULL;
2317    char *devname;
2318    char filename[64];
2319
2320    devname = strstr(opts.device, "sd");
2321    if (devname) {
2322        sprintf(filename, USB_VOL_NAME_FILE, devname);
2323        fp = fopen(filename, "w");
2324        if (fp != NULL) {
2325            fprintf(fp, "%s\n", ctx->vol->vol_name);
2326            fclose(fp);
2327        }
2328    }
2329    /* Foxconn added end pling 05/05/2009 */
2330}
2331
2332int main(int argc, char *argv[])
2333{
2334	char *parsed_options = NULL;
2335	struct fuse *fh;
2336	fuse_fstype fstype = FSTYPE_UNKNOWN;
2337	struct stat sbuf;
2338	int err, fd;
2339
2340	/*
2341	 * Make sure file descriptors 0, 1 and 2 are open,
2342	 * otherwise chaos would ensue.
2343	 */
2344	do {
2345		fd = open("/dev/null", O_RDWR);
2346		if (fd > 2)
2347			close(fd);
2348	} while (fd >= 0 && fd <= 2);
2349
2350#ifndef FUSE_INTERNAL
2351	if ((getuid() != geteuid()) || (getgid() != getegid())) {
2352		fprintf(stderr, "%s", setuid_msg);
2353		return NTFS_VOLUME_INSECURE;
2354	}
2355#endif
2356	if (drop_privs())
2357		return NTFS_VOLUME_NO_PRIVILEGE;
2358
2359	ntfs_set_locale();
2360	ntfs_log_set_handler(ntfs_log_handler_stderr);
2361
2362	if (parse_options(argc, argv)) {
2363		usage();
2364		return NTFS_VOLUME_SYNTAX_ERROR;
2365	}
2366
2367	if (ntfs_fuse_init()) {
2368		err = NTFS_VOLUME_OUT_OF_MEMORY;
2369		goto err2;
2370	}
2371
2372	parsed_options = parse_mount_options(opts.options);
2373	if (!parsed_options) {
2374		err = NTFS_VOLUME_SYNTAX_ERROR;
2375		goto err_out;
2376	}
2377
2378#if defined(linux) || defined(__uClinux__)
2379	fstype = get_fuse_fstype();
2380
2381	err = NTFS_VOLUME_NO_PRIVILEGE;
2382	if (restore_privs())
2383		goto err_out;
2384
2385	if (fstype == FSTYPE_NONE || fstype == FSTYPE_UNKNOWN)
2386		fstype = load_fuse_module();
2387
2388	create_dev_fuse();
2389
2390	if (drop_privs())
2391		goto err_out;
2392#endif
2393	if (stat(opts.device, &sbuf)) {
2394		ntfs_log_perror("Failed to access '%s'", opts.device);
2395		err = NTFS_VOLUME_NO_PRIVILEGE;
2396		goto err_out;
2397	}
2398
2399#if !(defined(__sun) && defined (__SVR4))
2400	/* Always use fuseblk for block devices unless it's surely missing. */
2401	if (S_ISBLK(sbuf.st_mode) && (fstype != FSTYPE_FUSE))
2402		ctx->blkdev = TRUE;
2403#endif
2404
2405#ifndef FUSE_INTERNAL
2406	if (getuid() && ctx->blkdev) {
2407		ntfs_log_error("%s", unpriv_fuseblk_msg);
2408		goto err2;
2409	}
2410#endif
2411	err = ntfs_open(opts.device);
2412	if (err)
2413		goto err_out;
2414
2415	/* We must do this after ntfs_open() to be able to set the blksize */
2416	if (ctx->blkdev && set_fuseblk_options(&parsed_options))
2417		goto err_out;
2418
2419	fh = mount_fuse(parsed_options);
2420	if (!fh) {
2421		err = NTFS_VOLUME_FUSE_ERROR;
2422		goto err_out;
2423	}
2424
2425	ctx->mounted = TRUE;
2426
2427#if defined(linux) || defined(__uClinux__)
2428	if (S_ISBLK(sbuf.st_mode) && (fstype == FSTYPE_FUSE))
2429		ntfs_log_info("%s", fuse26_kmod_msg);
2430#endif
2431	setup_logging(parsed_options);
2432
2433	fuse_loop(fh);
2434
2435	err = 0;
2436
2437	fuse_unmount(opts.mnt_point, ctx->fc);
2438	fuse_destroy(fh);
2439err_out:
2440	ntfs_mount_error(opts.device, opts.mnt_point, err);
2441err2:
2442	ntfs_close();
2443	free(ctx);
2444	free(parsed_options);
2445	free(opts.options);
2446	free(opts.device);
2447	return err;
2448}
2449