📄 super.c
字号:
ntfs_error(sb, "Failed to initialize attribute definition table."); return false;}#endif /* NTFS_RW *//** * load_and_init_upcase - load the upcase table for an ntfs volume * @vol: ntfs super block describing device whose upcase to load * * Return 'true' on success or 'false' on error. */static bool load_and_init_upcase(ntfs_volume *vol){ loff_t i_size; struct super_block *sb = vol->sb; struct inode *ino; struct page *page; pgoff_t index, max_index; unsigned int size; int i, max; ntfs_debug("Entering."); /* Read upcase table and setup vol->upcase and vol->upcase_len. */ ino = ntfs_iget(sb, FILE_UpCase); if (IS_ERR(ino) || is_bad_inode(ino)) { if (!IS_ERR(ino)) iput(ino); goto upcase_failed; } /* * The upcase size must not be above 64k Unicode characters, must not * be zero and must be a multiple of sizeof(ntfschar). */ i_size = i_size_read(ino); if (!i_size || i_size & (sizeof(ntfschar) - 1) || i_size > 64ULL * 1024 * sizeof(ntfschar)) goto iput_upcase_failed; vol->upcase = (ntfschar*)ntfs_malloc_nofs(i_size); if (!vol->upcase) goto iput_upcase_failed; index = 0; max_index = i_size >> PAGE_CACHE_SHIFT; size = PAGE_CACHE_SIZE; while (index < max_index) { /* Read the upcase table and copy it into the linear buffer. */read_partial_upcase_page: page = ntfs_map_page(ino->i_mapping, index); if (IS_ERR(page)) goto iput_upcase_failed; memcpy((char*)vol->upcase + (index++ << PAGE_CACHE_SHIFT), page_address(page), size); ntfs_unmap_page(page); }; if (size == PAGE_CACHE_SIZE) { size = i_size & ~PAGE_CACHE_MASK; if (size) goto read_partial_upcase_page; } vol->upcase_len = i_size >> UCHAR_T_SIZE_BITS; ntfs_debug("Read %llu bytes from $UpCase (expected %zu bytes).", i_size, 64 * 1024 * sizeof(ntfschar)); iput(ino); mutex_lock(&ntfs_lock); if (!default_upcase) { ntfs_debug("Using volume specified $UpCase since default is " "not present."); mutex_unlock(&ntfs_lock); return true; } max = default_upcase_len; if (max > vol->upcase_len) max = vol->upcase_len; for (i = 0; i < max; i++) if (vol->upcase[i] != default_upcase[i]) break; if (i == max) { ntfs_free(vol->upcase); vol->upcase = default_upcase; vol->upcase_len = max; ntfs_nr_upcase_users++; mutex_unlock(&ntfs_lock); ntfs_debug("Volume specified $UpCase matches default. Using " "default."); return true; } mutex_unlock(&ntfs_lock); ntfs_debug("Using volume specified $UpCase since it does not match " "the default."); return true;iput_upcase_failed: iput(ino); ntfs_free(vol->upcase); vol->upcase = NULL;upcase_failed: mutex_lock(&ntfs_lock); if (default_upcase) { vol->upcase = default_upcase; vol->upcase_len = default_upcase_len; ntfs_nr_upcase_users++; mutex_unlock(&ntfs_lock); ntfs_error(sb, "Failed to load $UpCase from the volume. Using " "default."); return true; } mutex_unlock(&ntfs_lock); ntfs_error(sb, "Failed to initialize upcase table."); return false;}/* * The lcn and mft bitmap inodes are NTFS-internal inodes with * their own special locking rules: */static struct lock_class_key lcnbmp_runlist_lock_key, lcnbmp_mrec_lock_key, mftbmp_runlist_lock_key, mftbmp_mrec_lock_key;/** * load_system_files - open the system files using normal functions * @vol: ntfs super block describing device whose system files to load * * Open the system files with normal access functions and complete setting up * the ntfs super block @vol. * * Return 'true' on success or 'false' on error. */static bool load_system_files(ntfs_volume *vol){ struct super_block *sb = vol->sb; MFT_RECORD *m; VOLUME_INFORMATION *vi; ntfs_attr_search_ctx *ctx;#ifdef NTFS_RW RESTART_PAGE_HEADER *rp; int err;#endif /* NTFS_RW */ ntfs_debug("Entering.");#ifdef NTFS_RW /* Get mft mirror inode compare the contents of $MFT and $MFTMirr. */ if (!load_and_init_mft_mirror(vol) || !check_mft_mirror(vol)) { static const char *es1 = "Failed to load $MFTMirr"; static const char *es2 = "$MFTMirr does not match $MFT"; static const char *es3 = ". Run ntfsfix and/or chkdsk."; /* If a read-write mount, convert it to a read-only mount. */ if (!(sb->s_flags & MS_RDONLY)) { if (!(vol->on_errors & (ON_ERRORS_REMOUNT_RO | ON_ERRORS_CONTINUE))) { ntfs_error(sb, "%s and neither on_errors=" "continue nor on_errors=" "remount-ro was specified%s", !vol->mftmirr_ino ? es1 : es2, es3); goto iput_mirr_err_out; } sb->s_flags |= MS_RDONLY; ntfs_error(sb, "%s. Mounting read-only%s", !vol->mftmirr_ino ? es1 : es2, es3); } else ntfs_warning(sb, "%s. Will not be able to remount " "read-write%s", !vol->mftmirr_ino ? es1 : es2, es3); /* This will prevent a read-write remount. */ NVolSetErrors(vol); }#endif /* NTFS_RW */ /* Get mft bitmap attribute inode. */ vol->mftbmp_ino = ntfs_attr_iget(vol->mft_ino, AT_BITMAP, NULL, 0); if (IS_ERR(vol->mftbmp_ino)) { ntfs_error(sb, "Failed to load $MFT/$BITMAP attribute."); goto iput_mirr_err_out; } lockdep_set_class(&NTFS_I(vol->mftbmp_ino)->runlist.lock, &mftbmp_runlist_lock_key); lockdep_set_class(&NTFS_I(vol->mftbmp_ino)->mrec_lock, &mftbmp_mrec_lock_key); /* Read upcase table and setup @vol->upcase and @vol->upcase_len. */ if (!load_and_init_upcase(vol)) goto iput_mftbmp_err_out;#ifdef NTFS_RW /* * Read attribute definitions table and setup @vol->attrdef and * @vol->attrdef_size. */ if (!load_and_init_attrdef(vol)) goto iput_upcase_err_out;#endif /* NTFS_RW */ /* * Get the cluster allocation bitmap inode and verify the size, no * need for any locking at this stage as we are already running * exclusively as we are mount in progress task. */ vol->lcnbmp_ino = ntfs_iget(sb, FILE_Bitmap); if (IS_ERR(vol->lcnbmp_ino) || is_bad_inode(vol->lcnbmp_ino)) { if (!IS_ERR(vol->lcnbmp_ino)) iput(vol->lcnbmp_ino); goto bitmap_failed; } lockdep_set_class(&NTFS_I(vol->lcnbmp_ino)->runlist.lock, &lcnbmp_runlist_lock_key); lockdep_set_class(&NTFS_I(vol->lcnbmp_ino)->mrec_lock, &lcnbmp_mrec_lock_key); NInoSetSparseDisabled(NTFS_I(vol->lcnbmp_ino)); if ((vol->nr_clusters + 7) >> 3 > i_size_read(vol->lcnbmp_ino)) { iput(vol->lcnbmp_ino);bitmap_failed: ntfs_error(sb, "Failed to load $Bitmap."); goto iput_attrdef_err_out; } /* * Get the volume inode and setup our cache of the volume flags and * version. */ vol->vol_ino = ntfs_iget(sb, FILE_Volume); if (IS_ERR(vol->vol_ino) || is_bad_inode(vol->vol_ino)) { if (!IS_ERR(vol->vol_ino)) iput(vol->vol_ino);volume_failed: ntfs_error(sb, "Failed to load $Volume."); goto iput_lcnbmp_err_out; } m = map_mft_record(NTFS_I(vol->vol_ino)); if (IS_ERR(m)) {iput_volume_failed: iput(vol->vol_ino); goto volume_failed; } if (!(ctx = ntfs_attr_get_search_ctx(NTFS_I(vol->vol_ino), m))) { ntfs_error(sb, "Failed to get attribute search context."); goto get_ctx_vol_failed; } if (ntfs_attr_lookup(AT_VOLUME_INFORMATION, NULL, 0, 0, 0, NULL, 0, ctx) || ctx->attr->non_resident || ctx->attr->flags) {err_put_vol: ntfs_attr_put_search_ctx(ctx);get_ctx_vol_failed: unmap_mft_record(NTFS_I(vol->vol_ino)); goto iput_volume_failed; } vi = (VOLUME_INFORMATION*)((char*)ctx->attr + le16_to_cpu(ctx->attr->data.resident.value_offset)); /* Some bounds checks. */ if ((u8*)vi < (u8*)ctx->attr || (u8*)vi + le32_to_cpu(ctx->attr->data.resident.value_length) > (u8*)ctx->attr + le32_to_cpu(ctx->attr->length)) goto err_put_vol; /* Copy the volume flags and version to the ntfs_volume structure. */ vol->vol_flags = vi->flags; vol->major_ver = vi->major_ver; vol->minor_ver = vi->minor_ver; ntfs_attr_put_search_ctx(ctx); unmap_mft_record(NTFS_I(vol->vol_ino)); printk(KERN_INFO "NTFS volume version %i.%i.\n", vol->major_ver, vol->minor_ver); if (vol->major_ver < 3 && NVolSparseEnabled(vol)) { ntfs_warning(vol->sb, "Disabling sparse support due to NTFS " "volume version %i.%i (need at least version " "3.0).", vol->major_ver, vol->minor_ver); NVolClearSparseEnabled(vol); }#ifdef NTFS_RW /* Make sure that no unsupported volume flags are set. */ if (vol->vol_flags & VOLUME_MUST_MOUNT_RO_MASK) { static const char *es1a = "Volume is dirty"; static const char *es1b = "Volume has been modified by chkdsk"; static const char *es1c = "Volume has unsupported flags set"; static const char *es2a = ". Run chkdsk and mount in Windows."; static const char *es2b = ". Mount in Windows."; const char *es1, *es2; es2 = es2a; if (vol->vol_flags & VOLUME_IS_DIRTY) es1 = es1a; else if (vol->vol_flags & VOLUME_MODIFIED_BY_CHKDSK) { es1 = es1b; es2 = es2b; } else { es1 = es1c; ntfs_warning(sb, "Unsupported volume flags 0x%x " "encountered.", (unsigned)le16_to_cpu(vol->vol_flags)); } /* If a read-write mount, convert it to a read-only mount. */ if (!(sb->s_flags & MS_RDONLY)) { if (!(vol->on_errors & (ON_ERRORS_REMOUNT_RO | ON_ERRORS_CONTINUE))) { ntfs_error(sb, "%s and neither on_errors=" "continue nor on_errors=" "remount-ro was specified%s", es1, es2); goto iput_vol_err_out; } sb->s_flags |= MS_RDONLY; ntfs_error(sb, "%s. Mounting read-only%s", es1, es2); } else ntfs_warning(sb, "%s. Will not be able to remount " "read-write%s", es1, es2); /* * Do not set NVolErrors() because ntfs_remount() re-checks the * flags which we need to do in case any flags have changed. */ } /* * Get the inode for the logfile, check it and determine if the volume * was shutdown cleanly. */ rp = NULL; if (!load_and_check_logfile(vol, &rp) || !ntfs_is_logfile_clean(vol->logfile_ino, rp)) { static const char *es1a = "Failed to load $LogFile"; static const char *es1b = "$LogFile is not clean"; static const char *es2 = ". Mount in Windows."; const char *es1; es1 = !vol->logfile_ino ? es1a : es1b; /* If a read-write mount, convert it to a read-only mount. */ if (!(sb->s_flags & MS_RDONLY)) { if (!(vol->on_errors & (ON_ERRORS_REMOUNT_RO | ON_ERRORS_CONTINUE))) { ntfs_error(sb, "%s and neither on_errors=" "continue nor on_errors=" "remount-ro was specified%s", es1, es2); if (vol->logfile_ino) { BUG_ON(!rp); ntfs_free(rp); } goto iput_logfile_err_out; } sb->s_flags |= MS_RDONLY; ntfs_error(sb, "%s. Mounting read-only%s", es1, es2); } else ntfs_warning(sb, "%s. Will not be able to remount " "read-write%s", es1, es2); /* This will prevent a read-write remount. */ NVolSetErrors(vol); } ntfs_free(rp);#endif /* NTFS_RW */ /* Get the root directory inode so we can do path lookups. */ vol->root_ino = ntfs_iget(sb, FILE_root); if (IS_ERR(vol->root_ino) || is_bad_inode(vol->root_ino)) { if (!IS_ERR(vol->root_ino)) iput(vol->root_ino); ntfs_error(sb, "Failed to load root directory."); goto iput_logfile_err_out; }#ifdef NTFS_RW /* * Check if Windows is suspended to disk on the target volume. If it * is hibernated, we must not write *anything* to the disk so set * NVolErrors() without setting the dirty volume flag and mount * read-only. This will prevent read-write remounting and it will also * prevent all writes. */ err = check_windows_hibernation_status(vol); if (unlikely(err)) { static const char *es1a = "Failed to determine if Windows is " "hibernated"; static const char *es1b = "Windows is hibernated"; static const char *es2 = ". Run chkdsk."; const char *es1; es1 = err < 0 ? es1a : es1b; /* If a read-write mount, convert it to a read-only mount. */ if (!(sb->s_flags & MS_RDONLY)) { if (!(vol->on_errors & (ON_ERRORS_REMOUNT_RO | ON_ERRORS_CONTINUE))) { ntfs_error(sb, "%s and neither on_errors=" "continue nor on_errors=" "remount-ro was specified%s", es1, es2); goto iput_root_err_out; } sb->s_flags |= MS_RDONLY; ntfs_error(sb, "%s. Mounting read-only%s", es1, es2); } else ntfs_warning(sb, "%s. Will not be able to remount " "read-write%s", es1, es2); /* This will prevent a read-write remount. */ NVolSetErrors(vol); } /* If (still) a read-write mount, mark the volume dirty. */ if (!(sb->s_flags & MS_RDONLY) && ntfs_set_volume_flags(vol, VOLUME_IS_DIRTY)) { static const char *es1 = "Failed to set dirty bit in volume " "information flags"; static const char *es2 = ". Run chkdsk."; /* Convert to a read-only mount. */ if (!(vol->on_errors & (ON_ERRORS_REMOUNT_RO | ON_ERRORS_CONTINUE))) { ntfs_error(sb, "%s and neither on_errors=continue nor " "on_errors=remount-ro was specified%s", es1, es2); goto iput_root_err_out; } ntfs_error(sb, "%s. Mounting read-only%s", es1, es2); sb->s_flags |= MS_RDONLY; /* * Do not
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -