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