📄 super.c
字号:
/* * super.c - NTFS kernel super block handling. Part of the Linux-NTFS project. * * Copyright (c) 2001-2007 Anton Altaparmakov * Copyright (c) 2001,2002 Richard Russon * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program/include file is distributed in the hope that it will be * useful, but WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program (in the main directory of the Linux-NTFS * distribution in the file COPYING); if not, write to the Free Software * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include <linux/stddef.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/string.h>#include <linux/spinlock.h>#include <linux/blkdev.h> /* For bdev_hardsect_size(). */#include <linux/backing-dev.h>#include <linux/buffer_head.h>#include <linux/vfs.h>#include <linux/moduleparam.h>#include <linux/smp_lock.h>#include "sysctl.h"#include "logfile.h"#include "quota.h"#include "usnjrnl.h"#include "dir.h"#include "debug.h"#include "index.h"#include "aops.h"#include "layout.h"#include "malloc.h"#include "ntfs.h"/* Number of mounted filesystems which have compression enabled. */static unsigned long ntfs_nr_compression_users;/* A global default upcase table and a corresponding reference count. */static ntfschar *default_upcase = NULL;static unsigned long ntfs_nr_upcase_users = 0;/* Error constants/strings used in inode.c::ntfs_show_options(). */typedef enum { /* One of these must be present, default is ON_ERRORS_CONTINUE. */ ON_ERRORS_PANIC = 0x01, ON_ERRORS_REMOUNT_RO = 0x02, ON_ERRORS_CONTINUE = 0x04, /* Optional, can be combined with any of the above. */ ON_ERRORS_RECOVER = 0x10,} ON_ERRORS_ACTIONS;const option_t on_errors_arr[] = { { ON_ERRORS_PANIC, "panic" }, { ON_ERRORS_REMOUNT_RO, "remount-ro", }, { ON_ERRORS_CONTINUE, "continue", }, { ON_ERRORS_RECOVER, "recover" }, { 0, NULL }};/** * simple_getbool - * * Copied from old ntfs driver (which copied from vfat driver). */static int simple_getbool(char *s, bool *setval){ if (s) { if (!strcmp(s, "1") || !strcmp(s, "yes") || !strcmp(s, "true")) *setval = true; else if (!strcmp(s, "0") || !strcmp(s, "no") || !strcmp(s, "false")) *setval = false; else return 0; } else *setval = true; return 1;}/** * parse_options - parse the (re)mount options * @vol: ntfs volume * @opt: string containing the (re)mount options * * Parse the recognized options in @opt for the ntfs volume described by @vol. */static bool parse_options(ntfs_volume *vol, char *opt){ char *p, *v, *ov; static char *utf8 = "utf8"; int errors = 0, sloppy = 0; uid_t uid = (uid_t)-1; gid_t gid = (gid_t)-1; mode_t fmask = (mode_t)-1, dmask = (mode_t)-1; int mft_zone_multiplier = -1, on_errors = -1; int show_sys_files = -1, case_sensitive = -1, disable_sparse = -1; struct nls_table *nls_map = NULL, *old_nls; /* I am lazy... (-8 */#define NTFS_GETOPT_WITH_DEFAULT(option, variable, default_value) \ if (!strcmp(p, option)) { \ if (!v || !*v) \ variable = default_value; \ else { \ variable = simple_strtoul(ov = v, &v, 0); \ if (*v) \ goto needs_val; \ } \ }#define NTFS_GETOPT(option, variable) \ if (!strcmp(p, option)) { \ if (!v || !*v) \ goto needs_arg; \ variable = simple_strtoul(ov = v, &v, 0); \ if (*v) \ goto needs_val; \ }#define NTFS_GETOPT_OCTAL(option, variable) \ if (!strcmp(p, option)) { \ if (!v || !*v) \ goto needs_arg; \ variable = simple_strtoul(ov = v, &v, 8); \ if (*v) \ goto needs_val; \ }#define NTFS_GETOPT_BOOL(option, variable) \ if (!strcmp(p, option)) { \ bool val; \ if (!simple_getbool(v, &val)) \ goto needs_bool; \ variable = val; \ }#define NTFS_GETOPT_OPTIONS_ARRAY(option, variable, opt_array) \ if (!strcmp(p, option)) { \ int _i; \ if (!v || !*v) \ goto needs_arg; \ ov = v; \ if (variable == -1) \ variable = 0; \ for (_i = 0; opt_array[_i].str && *opt_array[_i].str; _i++) \ if (!strcmp(opt_array[_i].str, v)) { \ variable |= opt_array[_i].val; \ break; \ } \ if (!opt_array[_i].str || !*opt_array[_i].str) \ goto needs_val; \ } if (!opt || !*opt) goto no_mount_options; ntfs_debug("Entering with mount options string: %s", opt); while ((p = strsep(&opt, ","))) { if ((v = strchr(p, '='))) *v++ = 0; NTFS_GETOPT("uid", uid) else NTFS_GETOPT("gid", gid) else NTFS_GETOPT_OCTAL("umask", fmask = dmask) else NTFS_GETOPT_OCTAL("fmask", fmask) else NTFS_GETOPT_OCTAL("dmask", dmask) else NTFS_GETOPT("mft_zone_multiplier", mft_zone_multiplier) else NTFS_GETOPT_WITH_DEFAULT("sloppy", sloppy, true) else NTFS_GETOPT_BOOL("show_sys_files", show_sys_files) else NTFS_GETOPT_BOOL("case_sensitive", case_sensitive) else NTFS_GETOPT_BOOL("disable_sparse", disable_sparse) else NTFS_GETOPT_OPTIONS_ARRAY("errors", on_errors, on_errors_arr) else if (!strcmp(p, "posix") || !strcmp(p, "show_inodes")) ntfs_warning(vol->sb, "Ignoring obsolete option %s.", p); else if (!strcmp(p, "nls") || !strcmp(p, "iocharset")) { if (!strcmp(p, "iocharset")) ntfs_warning(vol->sb, "Option iocharset is " "deprecated. Please use " "option nls=<charsetname> in " "the future."); if (!v || !*v) goto needs_arg;use_utf8: old_nls = nls_map; nls_map = load_nls(v); if (!nls_map) { if (!old_nls) { ntfs_error(vol->sb, "NLS character set " "%s not found.", v); return false; } ntfs_error(vol->sb, "NLS character set %s not " "found. Using previous one %s.", v, old_nls->charset); nls_map = old_nls; } else /* nls_map */ { if (old_nls) unload_nls(old_nls); } } else if (!strcmp(p, "utf8")) { bool val = false; ntfs_warning(vol->sb, "Option utf8 is no longer " "supported, using option nls=utf8. Please " "use option nls=utf8 in the future and " "make sure utf8 is compiled either as a " "module or into the kernel."); if (!v || !*v) val = true; else if (!simple_getbool(v, &val)) goto needs_bool; if (val) { v = utf8; goto use_utf8; } } else { ntfs_error(vol->sb, "Unrecognized mount option %s.", p); if (errors < INT_MAX) errors++; }#undef NTFS_GETOPT_OPTIONS_ARRAY#undef NTFS_GETOPT_BOOL#undef NTFS_GETOPT#undef NTFS_GETOPT_WITH_DEFAULT }no_mount_options: if (errors && !sloppy) return false; if (sloppy) ntfs_warning(vol->sb, "Sloppy option given. Ignoring " "unrecognized mount option(s) and continuing."); /* Keep this first! */ if (on_errors != -1) { if (!on_errors) { ntfs_error(vol->sb, "Invalid errors option argument " "or bug in options parser."); return false; } } if (nls_map) { if (vol->nls_map && vol->nls_map != nls_map) { ntfs_error(vol->sb, "Cannot change NLS character set " "on remount."); return false; } /* else (!vol->nls_map) */ ntfs_debug("Using NLS character set %s.", nls_map->charset); vol->nls_map = nls_map; } else /* (!nls_map) */ { if (!vol->nls_map) { vol->nls_map = load_nls_default(); if (!vol->nls_map) { ntfs_error(vol->sb, "Failed to load default " "NLS character set."); return false; } ntfs_debug("Using default NLS character set (%s).", vol->nls_map->charset); } } if (mft_zone_multiplier != -1) { if (vol->mft_zone_multiplier && vol->mft_zone_multiplier != mft_zone_multiplier) { ntfs_error(vol->sb, "Cannot change mft_zone_multiplier " "on remount."); return false; } if (mft_zone_multiplier < 1 || mft_zone_multiplier > 4) { ntfs_error(vol->sb, "Invalid mft_zone_multiplier. " "Using default value, i.e. 1."); mft_zone_multiplier = 1; } vol->mft_zone_multiplier = mft_zone_multiplier; } if (!vol->mft_zone_multiplier) vol->mft_zone_multiplier = 1; if (on_errors != -1) vol->on_errors = on_errors; if (!vol->on_errors || vol->on_errors == ON_ERRORS_RECOVER) vol->on_errors |= ON_ERRORS_CONTINUE; if (uid != (uid_t)-1) vol->uid = uid; if (gid != (gid_t)-1) vol->gid = gid; if (fmask != (mode_t)-1) vol->fmask = fmask; if (dmask != (mode_t)-1) vol->dmask = dmask; if (show_sys_files != -1) { if (show_sys_files) NVolSetShowSystemFiles(vol); else NVolClearShowSystemFiles(vol); } if (case_sensitive != -1) { if (case_sensitive) NVolSetCaseSensitive(vol); else NVolClearCaseSensitive(vol); } if (disable_sparse != -1) { if (disable_sparse) NVolClearSparseEnabled(vol); else { if (!NVolSparseEnabled(vol) && vol->major_ver && vol->major_ver < 3) ntfs_warning(vol->sb, "Not enabling sparse " "support due to NTFS volume " "version %i.%i (need at least " "version 3.0).", vol->major_ver, vol->minor_ver); else NVolSetSparseEnabled(vol); } } return true;needs_arg: ntfs_error(vol->sb, "The %s option requires an argument.", p); return false;needs_bool: ntfs_error(vol->sb, "The %s option requires a boolean argument.", p); return false;needs_val: ntfs_error(vol->sb, "Invalid %s option argument: %s", p, ov); return false;}#ifdef NTFS_RW/** * ntfs_write_volume_flags - write new flags to the volume information flags * @vol: ntfs volume on which to modify the flags * @flags: new flags value for the volume information flags * * Internal function. You probably want to use ntfs_{set,clear}_volume_flags() * instead (see below). * * Replace the volume information flags on the volume @vol with the value * supplied in @flags. Note, this overwrites the volume information flags, so * make sure to combine the flags you want to modify with the old flags and use * the result when calling ntfs_write_volume_flags(). * * Return 0 on success and -errno on error. */static int ntfs_write_volume_flags(ntfs_volume *vol, const VOLUME_FLAGS flags){ ntfs_inode *ni = NTFS_I(vol->vol_ino); MFT_RECORD *m; VOLUME_INFORMATION *vi; ntfs_attr_search_ctx *ctx; int err; ntfs_debug("Entering, old flags = 0x%x, new flags = 0x%x.", le16_to_cpu(vol->vol_flags), le16_to_cpu(flags)); if (vol->vol_flags == flags) goto done; BUG_ON(!ni); m = map_mft_record(ni); if (IS_ERR(m)) { err = PTR_ERR(m); goto err_out; } ctx = ntfs_attr_get_search_ctx(ni, m); if (!ctx) { err = -ENOMEM; goto put_unm_err_out; } err = ntfs_attr_lookup(AT_VOLUME_INFORMATION, NULL, 0, 0, 0, NULL, 0, ctx); if (err) goto put_unm_err_out; vi = (VOLUME_INFORMATION*)((u8*)ctx->attr + le16_to_cpu(ctx->attr->data.resident.value_offset)); vol->vol_flags = vi->flags = flags; flush_dcache_mft_record_page(ctx->ntfs_ino); mark_mft_record_dirty(ctx->ntfs_ino); ntfs_attr_put_search_ctx(ctx); unmap_mft_record(ni);done: ntfs_debug("Done."); return 0;put_unm_err_out: if (ctx) ntfs_attr_put_search_ctx(ctx); unmap_mft_record(ni);err_out: ntfs_error(vol->sb, "Failed with error code %i.", -err); return err;}/** * ntfs_set_volume_flags - set bits in the volume information flags * @vol: ntfs volume on which to modify the flags * @flags: flags to set on the volume * * Set the bits in @flags in the volume information flags on the volume @vol. * * Return 0 on success and -errno on error. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -