diff --git a/configure.ac b/configure.ac index c6d1a119..7e85411b 100644 --- a/configure.ac +++ b/configure.ac @@ -23,8 +23,8 @@ # Autoconf AC_PREREQ(2.59) -AC_INIT([ntfs-3g],[2009.1.1],[ntfs-3g-devel@lists.sf.net]) -LIBNTFS_3G_VERSION="48" +AC_INIT([ntfs-3g],[2009.2.1],[ntfs-3g-devel@lists.sf.net]) +LIBNTFS_3G_VERSION="49" AC_CONFIG_SRCDIR([src/ntfs-3g.c]) # Environment diff --git a/include/ntfs-3g/volume.h b/include/ntfs-3g/volume.h index 845457d7..5b726fbf 100644 --- a/include/ntfs-3g/volume.h +++ b/include/ntfs-3g/volume.h @@ -4,7 +4,7 @@ * Copyright (c) 2000-2004 Anton Altaparmakov * Copyright (c) 2004-2005 Richard Russon * Copyright (c) 2005-2006 Yura Pakhuchiy - * Copyright (c) 2005-2008 Szabolcs Szakacsits + * Copyright (c) 2005-2009 Szabolcs Szakacsits * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -56,8 +56,8 @@ #define MS_EXCLUSIVE 0x08000000 -#ifndef MS_FORCE -#define MS_FORCE 0x10000000 +#ifndef MS_RECOVER +#define MS_RECOVER 0x10000000 #endif #define MS_IGNORE_HIBERFILE 0x20000000 diff --git a/libntfs-3g/attrib.c b/libntfs-3g/attrib.c index ce664fd0..6d132a5d 100644 --- a/libntfs-3g/attrib.c +++ b/libntfs-3g/attrib.c @@ -392,7 +392,7 @@ ntfs_attr *ntfs_attr_open(ntfs_inode *ni, const ATTR_TYPES type, errno = EINVAL; goto out; } - na = calloc(sizeof(ntfs_attr), 1); + na = ntfs_calloc(sizeof(ntfs_attr)); if (!na) goto out; if (name && name != AT_UNNAMED && name != NTFS_INDEX_I30) { @@ -1704,6 +1704,7 @@ static int ntfs_attr_find(const ATTR_TYPES type, const ntfschar *name, } else { if (name && name != AT_UNNAMED) { errno = EINVAL; + ntfs_log_perror("%s", __FUNCTION__); return -1; } vol = NULL; @@ -1815,8 +1816,9 @@ static int ntfs_attr_find(const ATTR_TYPES type, const ntfschar *name, } } } - ntfs_log_debug("ntfs_attr_find(): File is corrupt. Run chkdsk.\n"); errno = EIO; + ntfs_log_perror("%s: Corrupt inode (%lld)", __FUNCTION__, + ctx->ntfs_ino ? (long long)ctx->ntfs_ino->mft_no : -1); return -1; } @@ -1984,6 +1986,7 @@ find_attr_list_attr: /* Check for bogus calls. */ if (name || name_len || val || val_len || lowest_vcn) { errno = EINVAL; + ntfs_log_perror("%s", __FUNCTION__); return -1; } @@ -2014,9 +2017,9 @@ find_attr_list_attr: if (errno != ENOENT) return rc; - /* Not found?!? Absurd! Must be a bug... )-: */ - ntfs_log_error("Extant attribute list wasn't found\n"); - errno = EINVAL; + /* Not found?!? Absurd! */ + errno = EIO; + ntfs_log_error("Attribute list wasn't found"); return -1; } } @@ -2131,10 +2134,8 @@ is_enumeration: /* We want an extent record. */ ni = ntfs_extent_inode_open(base_ni, al_entry->mft_reference); - if (!ni) { - ntfs_log_perror("Failed to map extent inode"); + if (!ni) break; - } ctx->ntfs_ino = ni; ctx->mrec = ni->mrec; } @@ -2204,7 +2205,7 @@ do_next_attr: ctx->attr = ctx->base_attr; } errno = EIO; - ntfs_log_perror("Inode is corrupt (%lld)", (unsigned long long)ni->mft_no); + ntfs_log_perror("Inode is corrupt (%lld)", (long long)base_ni->mft_no); return -1; not_found: /* @@ -2338,6 +2339,7 @@ int ntfs_attr_lookup(const ATTR_TYPES type, const ntfschar *name, (!ctx->ntfs_ino || !(vol = ctx->ntfs_ino->vol) || !vol->upcase || !vol->upcase_len))) { errno = EINVAL; + ntfs_log_perror("%s", __FUNCTION__); goto out; } @@ -4281,6 +4283,7 @@ static int ntfs_attr_update_mapping_pairs_i(ntfs_attr *na, VCN from_vcn) const runlist_element *stop_rl; int err, mp_size, cur_max_mp_size, exp_max_mp_size, ret = -1; BOOL finished_build; + retry: if (!na || !na->rl || from_vcn) { errno = EINVAL; @@ -4376,12 +4379,19 @@ retry: exp_max_mp_size = le32_to_cpu(m->bytes_allocated) - le32_to_cpu(m->bytes_in_use) + cur_max_mp_size; /* Get the size for the rest of mapping pairs array. */ -/* old code equivalent - mp_size = ntfs_get_size_for_mapping_pairs(na->ni->vol, na->rl, - stop_vcn, INT_MAX); -*/ mp_size = ntfs_get_size_for_mapping_pairs(na->ni->vol, stop_rl, stop_vcn, exp_max_mp_size); +{ /* temporary compare against old computation */ +int old; + + old = ntfs_get_size_for_mapping_pairs(na->ni->vol, na->rl, + stop_vcn, INT_MAX); + if (((mp_size <= exp_max_mp_size) || (old <= exp_max_mp_size)) + && (mp_size != old)) { + ntfs_log_error("Bad runlist size, old %d new %d\n",old,mp_size); + goto put_err_out; + } +} if (mp_size <= 0) { ntfs_log_perror("%s: get MP size failed", __FUNCTION__); goto put_err_out; diff --git a/libntfs-3g/inode.c b/libntfs-3g/inode.c index 7dd6584d..7fd386d4 100644 --- a/libntfs-3g/inode.c +++ b/libntfs-3g/inode.c @@ -87,7 +87,7 @@ static ntfs_inode *__ntfs_inode_allocate(ntfs_volume *vol) { ntfs_inode *ni; - ni = (ntfs_inode*)calloc(1, sizeof(ntfs_inode)); + ni = (ntfs_inode*)ntfs_calloc(sizeof(ntfs_inode)); if (ni) ni->vol = vol; return ni; @@ -444,11 +444,8 @@ ntfs_inode *ntfs_extent_inode_open(ntfs_inode *base_ni, const MFT_REF mref) ni = __ntfs_inode_allocate(base_ni->vol); if (!ni) goto out; - if (ntfs_file_record_read(base_ni->vol, le64_to_cpu(mref), &ni->mrec, - NULL)) { - ntfs_log_perror("ntfs_file_record_read failed #2"); + if (ntfs_file_record_read(base_ni->vol, le64_to_cpu(mref), &ni->mrec, NULL)) goto err_out; - } ni->mft_no = mft_no; ni->nr_extents = -1; ni->base_ni = base_ni; diff --git a/libntfs-3g/logfile.c b/libntfs-3g/logfile.c index 3fb04f3d..277ad142 100644 --- a/libntfs-3g/logfile.c +++ b/libntfs-3g/logfile.c @@ -3,7 +3,7 @@ * * Copyright (c) 2002-2005 Anton Altaparmakov * Copyright (c) 2005 Yura Pakhuchiy - * Copyright (c) 2005-2006 Szabolcs Szakacsits + * Copyright (c) 2005-2009 Szabolcs Szakacsits * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -676,8 +676,8 @@ BOOL ntfs_is_logfile_clean(ntfs_attr *log_na, RESTART_PAGE_HEADER *rp) */ if (ra->client_in_use_list != LOGFILE_NO_CLIENT && !(ra->flags & RESTART_VOLUME_IS_CLEAN)) { - ntfs_log_error("$LogFile indicates unclean shutdown (%d, %d)\n", - le16_to_cpu(ra->client_in_use_list), + ntfs_log_error("The disk contains an unclean file system (%d, " + "%d).\n", le16_to_cpu(ra->client_in_use_list), le16_to_cpu(ra->flags)); return FALSE; } diff --git a/libntfs-3g/mft.c b/libntfs-3g/mft.c index bd3a15c2..ce267a37 100644 --- a/libntfs-3g/mft.c +++ b/libntfs-3g/mft.c @@ -105,11 +105,9 @@ int ntfs_mft_records_read(const ntfs_volume *vol, const MFT_REF mref, if (br != count) { if (br != -1) errno = EIO; - if (br >= 0) - ntfs_log_debug("Error: partition is smaller than it should " - "be!\n"); - else - ntfs_log_perror("Error reading $Mft record(s)"); + ntfs_log_perror("Failed to read of MFT, mft=%llu count=%lld " + "br=%lld", (long long)m, (long long)count, + (long long)br); return -1; } return 0; @@ -290,10 +288,9 @@ int ntfs_file_record_read(const ntfs_volume *vol, const MFT_REF mref, if (!m) return -1; } - if (ntfs_mft_record_read(vol, mref, m)) { - ntfs_log_perror("ntfs_mft_record_read failed"); + if (ntfs_mft_record_read(vol, mref, m)) goto err_out; - } + if (ntfs_mft_record_check(vol, mref, m)) goto err_out; @@ -1404,7 +1401,6 @@ found_free_rec: goto undo_mftbmp_alloc; if (ntfs_mft_record_read(vol, bit, m)) { - ntfs_log_perror("Error reading mft %lld #2", (long long)bit); free(m); goto undo_mftbmp_alloc; } @@ -1707,7 +1703,6 @@ found_free_rec: goto undo_mftbmp_alloc; if (ntfs_mft_record_read(vol, bit, m)) { - ntfs_log_perror("Error reading mft %lld", (long long)bit); free(m); goto undo_mftbmp_alloc; } diff --git a/libntfs-3g/mst.c b/libntfs-3g/mst.c index 4cd1f154..b6beb39d 100644 --- a/libntfs-3g/mst.c +++ b/libntfs-3g/mst.c @@ -2,7 +2,7 @@ * mst.c - Multi sector fixup handling code. Originated from the Linux-NTFS project. * * Copyright (c) 2000-2004 Anton Altaparmakov - * Copyright (c) 2006 Szabolcs Szakacsits + * Copyright (c) 2006-2009 Szabolcs Szakacsits * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -63,6 +63,7 @@ int ntfs_mst_post_read_fixup(NTFS_RECORD *b, const u32 size) (u32)(usa_ofs + (usa_count * 2)) > size || (size >> NTFS_BLOCK_SIZE_BITS) != usa_count) { errno = EINVAL; + ntfs_log_perror("%s", __FUNCTION__); return -1; } /* Position of usn in update sequence array. */ @@ -91,6 +92,7 @@ int ntfs_mst_post_read_fixup(NTFS_RECORD *b, const u32 size) */ b->magic = magic_BAAD; errno = EIO; + ntfs_log_perror("Incomplete multi-sector transfer"); return -1; } data_pos += NTFS_BLOCK_SIZE/sizeof(u16); @@ -142,6 +144,7 @@ int ntfs_mst_pre_write_fixup(NTFS_RECORD *b, const u32 size) if (!b || ntfs_is_baad_record(b->magic) || ntfs_is_hole_record(b->magic)) { errno = EINVAL; + ntfs_log_perror("%s: bad argument", __FUNCTION__); return -1; } /* Setup the variables. */ @@ -153,6 +156,7 @@ int ntfs_mst_pre_write_fixup(NTFS_RECORD *b, const u32 size) (u32)(usa_ofs + (usa_count * 2)) > size || (size >> NTFS_BLOCK_SIZE_BITS) != usa_count) { errno = EINVAL; + ntfs_log_perror("%s", __FUNCTION__); return -1; } /* Position of usn in update sequence array. */ diff --git a/libntfs-3g/volume.c b/libntfs-3g/volume.c index 22ff18af..d2fa4a27 100644 --- a/libntfs-3g/volume.c +++ b/libntfs-3g/volume.c @@ -94,14 +94,8 @@ static const char *hibernated_volume_msg = "\n"; static const char *unclean_journal_msg = -"Mount is denied because NTFS is marked to be in use. Choose one action:\n" -"\n" -"Choice 1: If you have Windows then disconnect the external devices by\n" -" clicking on the 'Safely Remove Hardware' icon in the Windows\n" -" taskbar then shutdown Windows cleanly.\n" -"\n" -"Choice 2: If you don't have Windows then you can use the 'force' option for\n" -" your own responsibility. For example type on the command line:\n"; +"Write access is denied because the disk wasn't safely powered\n" +"off and the 'norecover' mount option was specified.\n"; static const char *opened_volume_msg = "Mount is denied because the NTFS volume is already exclusively opened.\n" @@ -119,14 +113,6 @@ static const char *access_denied_msg = "and the mounting user ID. More explanation is provided at\n" "http://ntfs-3g.org/support.html#unprivileged\n"; -static const char *forced_mount_msg = -"\n" -" mount -t ntfs-3g -o force %s %s\n" -"\n" -" Or add the option to the relevant row in the /etc/fstab file:\n" -"\n" -" %s %s ntfs-3g force 0 0\n"; - /** * ntfs_volume_alloc - Create an NTFS volume object and initialise it * @@ -1116,9 +1102,10 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags) ntfs_volume_check_hiberfile(vol, 1) < 0) goto error_exit; if (ntfs_volume_check_logfile(vol) < 0) { - if (!(flags & MS_FORCE)) + if (!(flags & MS_RECOVER)) goto error_exit; - ntfs_log_info("WARNING: Forced mount, reset $LogFile.\n"); + ntfs_log_info("The file system wasn't safely " + "closed on Windows. Fixing.\n"); if (ntfs_logfile_reset(vol)) goto error_exit; } @@ -1550,8 +1537,6 @@ void ntfs_mount_error(const char *volume, const char *mntpoint, int err) break; case NTFS_VOLUME_UNCLEAN_UNMOUNT: ntfs_log_error("%s", unclean_journal_msg); - ntfs_log_error(forced_mount_msg, volume, mntpoint, - volume, mntpoint); break; case NTFS_VOLUME_LOCKED: ntfs_log_error("%s", opened_volume_msg); diff --git a/src/ntfs-3g.c b/src/ntfs-3g.c index 96e9d6b5..56321b7b 100644 --- a/src/ntfs-3g.c +++ b/src/ntfs-3g.c @@ -133,7 +133,7 @@ typedef struct { BOOL ro; BOOL show_sys_files; BOOL silent; - BOOL force; + BOOL recover; BOOL hiberfile; BOOL debug; BOOL no_detach; @@ -162,18 +162,18 @@ static const char *usage_msg = "\n" "%s %s %s %d - Third Generation NTFS Driver\n" "\n" -"Copyright (C) 2006-2009 Szabolcs Szakacsits\n" "Copyright (C) 2005-2007 Yura Pakhuchiy\n" +"Copyright (C) 2006-2009 Szabolcs Szakacsits\n" "Copyright (C) 2007-2009 Jean-Pierre Andre\n" "Copyright (C) 2009 Erik Larsson\n" "\n" "Usage: %s [-o option[,...]] \n" "\n" -"Options: ro (read-only mount), force, remove_hiberfile, uid=,\n" -" gid=, umask=, fmask=, dmask=, streams_interface=.\n" -" Please see the details in the manual.\n" +"Options: ro (read-only mount), remove_hiberfile, uid=, gid=,\n" +" umask=, fmask=, dmask=, streams_interface=.\n" +" Please see the details in the manual (type: man ntfs-3g).\n" "\n" -"Examples: ntfs-3g -o force /dev/sda1 /mnt/windows\n" +"Example: ntfs-3g /dev/sda1 /mnt/windows\n" "\n" "%s"; @@ -380,11 +380,11 @@ static void set_fuse_error(int *err) #if defined(__APPLE__) || defined(__DARWIN__) static void *ntfs_macfuse_init(struct fuse_conn_info *conn) { - FUSE_ENABLE_XTIMES(conn); - return NULL; + FUSE_ENABLE_XTIMES(conn); + return NULL; } -static int ntfs_macfuse_getxtimes(const char *org_path, +static int ntfs_macfuse_getxtimes(const char *org_path, struct timespec *bkuptime, struct timespec *crtime) { int res = 0; @@ -429,12 +429,33 @@ int ntfs_macfuse_setcrtime(const char *path, const struct timespec *tv) if (tv) { ni->creation_time = tv->tv_sec; ntfs_fuse_update_times(ni, NTFS_UPDATE_CTIME); - } + } if (ntfs_inode_close(ni)) set_fuse_error(&res); return res; } + +int ntfs_macfuse_setbkuptime(const char *path, const struct timespec *tv) +{ + ntfs_inode *ni; + int res = 0; + + if (ntfs_fuse_is_named_data_stream(path)) + return -EINVAL; /* n/a for named data streams. */ + ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); + if (!ni) + return -errno; + + /* + * Doing nothing while pretending to do something. NTFS has no backup + * time. If this function is not implemented then some apps break. + */ + + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + return res; +} #endif /* defined(__APPLE__) || defined(__DARWIN__) */ static int ntfs_fuse_getattr(const char *org_path, struct stat *stbuf) @@ -2279,7 +2300,7 @@ static int ntfs_fuse_getxattr(const char *path, const char *name, return -EOPNOTSUPP; namespace = xattr_namespace(name); if (namespace == XATTRNS_NONE) - return -ENODATA; + return -EOPNOTSUPP; #if POSIXACLS /* parent directory must be executable */ if (ntfs_fuse_fill_security_context(&security) @@ -2437,7 +2458,7 @@ static int ntfs_fuse_setxattr(const char *path, const char *name, return -EOPNOTSUPP; namespace = xattr_namespace(name); if (namespace == XATTRNS_NONE) - return -ENODATA; + return -EOPNOTSUPP; #if POSIXACLS /* parent directory must be executable */ if (ntfs_fuse_fill_security_context(&security) @@ -2626,7 +2647,7 @@ static int ntfs_fuse_removexattr(const char *path, const char *name) return -EOPNOTSUPP; namespace = xattr_namespace(name); if (namespace == XATTRNS_NONE) - return -ENODATA; + return -EOPNOTSUPP; #if POSIXACLS /* parent directory must be executable */ if (ntfs_fuse_fill_security_context(&security) @@ -2762,10 +2783,11 @@ static struct fuse_operations ntfs_3g_ops = { .listxattr = ntfs_fuse_listxattr, #endif /* HAVE_SETXATTR */ #if defined(__APPLE__) || defined(__DARWIN__) - .init = ntfs_macfuse_init, + .init = ntfs_macfuse_init, /* MacFUSE extensions. */ - .getxtimes = ntfs_macfuse_getxtimes, - .setcrtime = ntfs_macfuse_setcrtime, + .getxtimes = ntfs_macfuse_getxtimes, + .setcrtime = ntfs_macfuse_setcrtime, + .setbkuptime = ntfs_macfuse_setbkuptime #endif /* defined(__APPLE__) || defined(__DARWIN__) */ }; @@ -2776,9 +2798,16 @@ static int ntfs_fuse_init(void) return -1; *ctx = (ntfs_fuse_context_t) { - .uid = getuid(), - .gid = getgid(), + .uid = getuid(), + .gid = getgid(), +#if defined(linux) + .streams = NF_STREAMS_INTERFACE_XATTR, +#else .streams = NF_STREAMS_INTERFACE_NONE, +#endif + .atime = ATIME_RELATIVE, + .silent = TRUE, + .recover = TRUE }; return 0; } @@ -2791,8 +2820,8 @@ static int ntfs_open(const char *device) flags |= MS_EXCLUSIVE; if (ctx->ro) flags |= MS_RDONLY; - if (ctx->force) - flags |= MS_FORCE; + if (ctx->recover) + flags |= MS_RECOVER; if (ctx->hiberfile) flags |= MS_IGNORE_HIBERFILE; @@ -2893,9 +2922,6 @@ static char *parse_mount_options(const char *orig_opts) return NULL; } - ctx->silent = TRUE; - ctx->atime = ATIME_RELATIVE; - s = options; while (s && *s && (val = strsep(&s, ","))) { opt = strsep(&val, "="); @@ -2976,10 +3002,14 @@ static char *parse_mount_options(const char *orig_opts) if (bogus_option_value(val, "silent")) goto err_exit; ctx->silent = TRUE; - } else if (!strcmp(opt, "force")) { - if (bogus_option_value(val, "force")) + } else if (!strcmp(opt, "recover")) { + if (bogus_option_value(val, "recover")) goto err_exit; - ctx->force = TRUE; + ctx->recover = TRUE; + } else if (!strcmp(opt, "norecover")) { + if (bogus_option_value(val, "norecover")) + goto err_exit; + ctx->recover = FALSE; } else if (!strcmp(opt, "remove_hiberfile")) { if (bogus_option_value(val, "remove_hiberfile")) goto err_exit;