📄 inode.c
字号:
static void __exit fat_destroy_inodecache(void){ kmem_cache_destroy(fat_inode_cachep);}static int fat_remount(struct super_block *sb, int *flags, char *data){ struct msdos_sb_info *sbi = MSDOS_SB(sb); *flags |= MS_NODIRATIME | (sbi->options.isvfat ? 0 : MS_NOATIME); return 0;}static int fat_statfs(struct dentry *dentry, struct kstatfs *buf){ struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb); /* If the count of free cluster is still unknown, counts it here. */ if (sbi->free_clusters == -1 || !sbi->free_clus_valid) { int err = fat_count_free_clusters(dentry->d_sb); if (err) return err; } buf->f_type = dentry->d_sb->s_magic; buf->f_bsize = sbi->cluster_size; buf->f_blocks = sbi->max_cluster - FAT_START_ENT; buf->f_bfree = sbi->free_clusters; buf->f_bavail = sbi->free_clusters; buf->f_namelen = sbi->options.isvfat ? 260 : 12; return 0;}static inline loff_t fat_i_pos_read(struct msdos_sb_info *sbi, struct inode *inode){ loff_t i_pos;#if BITS_PER_LONG == 32 spin_lock(&sbi->inode_hash_lock);#endif i_pos = MSDOS_I(inode)->i_pos;#if BITS_PER_LONG == 32 spin_unlock(&sbi->inode_hash_lock);#endif return i_pos;}static int fat_write_inode(struct inode *inode, int wait){ struct super_block *sb = inode->i_sb; struct msdos_sb_info *sbi = MSDOS_SB(sb); struct buffer_head *bh; struct msdos_dir_entry *raw_entry; loff_t i_pos; int err; if (inode->i_ino == MSDOS_ROOT_INO) return 0;retry: i_pos = fat_i_pos_read(sbi, inode); if (!i_pos) return 0; bh = sb_bread(sb, i_pos >> sbi->dir_per_block_bits); if (!bh) { printk(KERN_ERR "FAT: unable to read inode block " "for updating (i_pos %lld)\n", i_pos); return -EIO; } spin_lock(&sbi->inode_hash_lock); if (i_pos != MSDOS_I(inode)->i_pos) { spin_unlock(&sbi->inode_hash_lock); brelse(bh); goto retry; } raw_entry = &((struct msdos_dir_entry *) (bh->b_data)) [i_pos & (sbi->dir_per_block - 1)]; if (S_ISDIR(inode->i_mode)) raw_entry->size = 0; else raw_entry->size = cpu_to_le32(inode->i_size); raw_entry->attr = fat_make_attrs(inode); raw_entry->start = cpu_to_le16(MSDOS_I(inode)->i_logstart); raw_entry->starthi = cpu_to_le16(MSDOS_I(inode)->i_logstart >> 16); fat_time_unix2fat(sbi, &inode->i_mtime, &raw_entry->time, &raw_entry->date, NULL); if (sbi->options.isvfat) { __le16 atime; fat_time_unix2fat(sbi, &inode->i_ctime, &raw_entry->ctime, &raw_entry->cdate, &raw_entry->ctime_cs); fat_time_unix2fat(sbi, &inode->i_atime, &atime, &raw_entry->adate, NULL); } spin_unlock(&sbi->inode_hash_lock); mark_buffer_dirty(bh); err = 0; if (wait) err = sync_dirty_buffer(bh); brelse(bh); return err;}int fat_sync_inode(struct inode *inode){ return fat_write_inode(inode, 1);}EXPORT_SYMBOL_GPL(fat_sync_inode);static int fat_show_options(struct seq_file *m, struct vfsmount *mnt);static const struct super_operations fat_sops = { .alloc_inode = fat_alloc_inode, .destroy_inode = fat_destroy_inode, .write_inode = fat_write_inode, .delete_inode = fat_delete_inode, .put_super = fat_put_super, .write_super = fat_write_super, .statfs = fat_statfs, .clear_inode = fat_clear_inode, .remount_fs = fat_remount, .show_options = fat_show_options,};/* * a FAT file handle with fhtype 3 is * 0/ i_ino - for fast, reliable lookup if still in the cache * 1/ i_generation - to see if i_ino is still valid * bit 0 == 0 iff directory * 2/ i_pos(8-39) - if ino has changed, but still in cache * 3/ i_pos(4-7)|i_logstart - to semi-verify inode found at i_pos * 4/ i_pos(0-3)|parent->i_logstart - maybe used to hunt for the file on disc * * Hack for NFSv2: Maximum FAT entry number is 28bits and maximum * i_pos is 40bits (blocknr(32) + dir offset(8)), so two 4bits * of i_logstart is used to store the directory entry offset. */static struct dentry *fat_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len, int fh_type){ struct inode *inode = NULL; struct dentry *result; u32 *fh = fid->raw; if (fh_len < 5 || fh_type != 3) return NULL; inode = ilookup(sb, fh[0]); if (!inode || inode->i_generation != fh[1]) { if (inode) iput(inode); inode = NULL; } if (!inode) { loff_t i_pos; int i_logstart = fh[3] & 0x0fffffff; i_pos = (loff_t)fh[2] << 8; i_pos |= ((fh[3] >> 24) & 0xf0) | (fh[4] >> 28); /* try 2 - see if i_pos is in F-d-c * require i_logstart to be the same * Will fail if you truncate and then re-write */ inode = fat_iget(sb, i_pos); if (inode && MSDOS_I(inode)->i_logstart != i_logstart) { iput(inode); inode = NULL; } } /* * For now, do nothing if the inode is not found. * * What we could do is: * * - follow the file starting at fh[4], and record the ".." entry, * and the name of the fh[2] entry. * - then follow the ".." file finding the next step up. * * This way we build a path to the root of the tree. If this works, we * lookup the path and so get this inode into the cache. Finally try * the fat_iget lookup again. If that fails, then we are totally out * of luck. But all that is for another day */ result = d_obtain_alias(inode); if (!IS_ERR(result)) result->d_op = sb->s_root->d_op; return result;}static intfat_encode_fh(struct dentry *de, __u32 *fh, int *lenp, int connectable){ int len = *lenp; struct inode *inode = de->d_inode; u32 ipos_h, ipos_m, ipos_l; if (len < 5) return 255; /* no room */ ipos_h = MSDOS_I(inode)->i_pos >> 8; ipos_m = (MSDOS_I(inode)->i_pos & 0xf0) << 24; ipos_l = (MSDOS_I(inode)->i_pos & 0x0f) << 28; *lenp = 5; fh[0] = inode->i_ino; fh[1] = inode->i_generation; fh[2] = ipos_h; fh[3] = ipos_m | MSDOS_I(inode)->i_logstart; spin_lock(&de->d_lock); fh[4] = ipos_l | MSDOS_I(de->d_parent->d_inode)->i_logstart; spin_unlock(&de->d_lock); return 3;}static struct dentry *fat_get_parent(struct dentry *child){ struct super_block *sb = child->d_sb; struct buffer_head *bh; struct msdos_dir_entry *de; loff_t i_pos; struct dentry *parent; struct inode *inode; int err; lock_super(sb); err = fat_get_dotdot_entry(child->d_inode, &bh, &de, &i_pos); if (err) { parent = ERR_PTR(err); goto out; } inode = fat_build_inode(sb, de, i_pos); brelse(bh); parent = d_obtain_alias(inode); if (!IS_ERR(parent)) parent->d_op = sb->s_root->d_op;out: unlock_super(sb); return parent;}static const struct export_operations fat_export_ops = { .encode_fh = fat_encode_fh, .fh_to_dentry = fat_fh_to_dentry, .get_parent = fat_get_parent,};static int fat_show_options(struct seq_file *m, struct vfsmount *mnt){ struct msdos_sb_info *sbi = MSDOS_SB(mnt->mnt_sb); struct fat_mount_options *opts = &sbi->options; int isvfat = opts->isvfat; if (opts->fs_uid != 0) seq_printf(m, ",uid=%u", opts->fs_uid); if (opts->fs_gid != 0) seq_printf(m, ",gid=%u", opts->fs_gid); seq_printf(m, ",fmask=%04o", opts->fs_fmask); seq_printf(m, ",dmask=%04o", opts->fs_dmask); if (opts->allow_utime) seq_printf(m, ",allow_utime=%04o", opts->allow_utime); if (sbi->nls_disk) seq_printf(m, ",codepage=%s", sbi->nls_disk->charset); if (isvfat) { if (sbi->nls_io) seq_printf(m, ",iocharset=%s", sbi->nls_io->charset); switch (opts->shortname) { case VFAT_SFN_DISPLAY_WIN95 | VFAT_SFN_CREATE_WIN95: seq_puts(m, ",shortname=win95"); break; case VFAT_SFN_DISPLAY_WINNT | VFAT_SFN_CREATE_WINNT: seq_puts(m, ",shortname=winnt"); break; case VFAT_SFN_DISPLAY_WINNT | VFAT_SFN_CREATE_WIN95: seq_puts(m, ",shortname=mixed"); break; case VFAT_SFN_DISPLAY_LOWER | VFAT_SFN_CREATE_WIN95: /* seq_puts(m, ",shortname=lower"); */ break; default: seq_puts(m, ",shortname=unknown"); break; } } if (opts->name_check != 'n') seq_printf(m, ",check=%c", opts->name_check); if (opts->usefree) seq_puts(m, ",usefree"); if (opts->quiet) seq_puts(m, ",quiet"); if (opts->showexec) seq_puts(m, ",showexec"); if (opts->sys_immutable) seq_puts(m, ",sys_immutable"); if (!isvfat) { if (opts->dotsOK) seq_puts(m, ",dotsOK=yes"); if (opts->nocase) seq_puts(m, ",nocase"); } else { if (opts->utf8) seq_puts(m, ",utf8"); if (opts->unicode_xlate) seq_puts(m, ",uni_xlate"); if (!opts->numtail) seq_puts(m, ",nonumtail"); if (opts->rodir) seq_puts(m, ",rodir"); } if (opts->flush) seq_puts(m, ",flush"); if (opts->tz_utc) seq_puts(m, ",tz=UTC"); return 0;}enum { Opt_check_n, Opt_check_r, Opt_check_s, Opt_uid, Opt_gid, Opt_umask, Opt_dmask, Opt_fmask, Opt_allow_utime, Opt_codepage, Opt_usefree, Opt_nocase, Opt_quiet, Opt_showexec, Opt_debug, Opt_immutable, Opt_dots, Opt_nodots, Opt_charset, Opt_shortname_lower, Opt_shortname_win95, Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes, Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes, Opt_obsolate, Opt_flush, Opt_tz_utc, Opt_rodir, Opt_err,};static const match_table_t fat_tokens = { {Opt_check_r, "check=relaxed"}, {Opt_check_s, "check=strict"}, {Opt_check_n, "check=normal"}, {Opt_check_r, "check=r"}, {Opt_check_s, "check=s"}, {Opt_check_n, "check=n"}, {Opt_uid, "uid=%u"}, {Opt_gid, "gid=%u"}, {Opt_umask, "umask=%o"}, {Opt_dmask, "dmask=%o"}, {Opt_fmask, "fmask=%o"}, {Opt_allow_utime, "allow_utime=%o"}, {Opt_codepage, "codepage=%u"}, {Opt_usefree, "usefree"}, {Opt_nocase, "nocase"}, {Opt_quiet, "quiet"}, {Opt_showexec, "showexec"}, {Opt_debug, "debug"}, {Opt_immutable, "sys_immutable"}, {Opt_obsolate, "conv=binary"}, {Opt_obsolate, "conv=text"}, {Opt_obsolate, "conv=auto"}, {Opt_obsolate, "conv=b"}, {Opt_obsolate, "conv=t"}, {Opt_obsolate, "conv=a"}, {Opt_obsolate, "fat=%u"}, {Opt_obsolate, "blocksize=%u"}, {Opt_obsolate, "cvf_format=%20s"}, {Opt_obsolate, "cvf_options=%100s"}, {Opt_obsolate, "posix"}, {Opt_flush, "flush"}, {Opt_tz_utc, "tz=UTC"}, {Opt_err, NULL},};static const match_table_t msdos_tokens = { {Opt_nodots, "nodots"}, {Opt_nodots, "dotsOK=no"}, {Opt_dots, "dots"}, {Opt_dots, "dotsOK=yes"}, {Opt_err, NULL}};static const match_table_t vfat_tokens = { {Opt_charset, "iocharset=%s"}, {Opt_shortname_lower, "shortname=lower"}, {Opt_shortname_win95, "shortname=win95"}, {Opt_shortname_winnt, "shortname=winnt"}, {Opt_shortname_mixed, "shortname=mixed"}, {Opt_utf8_no, "utf8=0"}, /* 0 or no or false */ {Opt_utf8_no, "utf8=no"}, {Opt_utf8_no, "utf8=false"}, {Opt_utf8_yes, "utf8=1"}, /* empty or 1 or yes or true */ {Opt_utf8_yes, "utf8=yes"}, {Opt_utf8_yes, "utf8=true"}, {Opt_utf8_yes, "utf8"}, {Opt_uni_xl_no, "uni_xlate=0"}, /* 0 or no or false */ {Opt_uni_xl_no, "uni_xlate=no"}, {Opt_uni_xl_no, "uni_xlate=false"}, {Opt_uni_xl_yes, "uni_xlate=1"}, /* empty or 1 or yes or true */ {Opt_uni_xl_yes, "uni_xlate=yes"}, {Opt_uni_xl_yes, "uni_xlate=true"}, {Opt_uni_xl_yes, "uni_xlate"}, {Opt_nonumtail_no, "nonumtail=0"}, /* 0 or no or false */ {Opt_nonumtail_no, "nonumtail=no"}, {Opt_nonumtail_no, "nonumtail=false"}, {Opt_nonumtail_yes, "nonumtail=1"}, /* empty or 1 or yes or true */ {Opt_nonumtail_yes, "nonumtail=yes"}, {Opt_nonumtail_yes, "nonumtail=true"}, {Opt_nonumtail_yes, "nonumtail"}, {Opt_rodir, "rodir"}, {Opt_err, NULL}};static int parse_options(char *options, int is_vfat, int silent, int *debug, struct fat_mount_options *opts){ char *p; substring_t args[MAX_OPT_ARGS]; int option; char *iocharset; opts->isvfat = is_vfat; opts->fs_uid = current_uid(); opts->fs_gid = current_gid(); opts->fs_fmask = opts->fs_dmask = current->fs->umask; opts->allow_utime = -1; opts->codepage = fat_default_codepage; opts->iocharset = fat_default_iocharset; if (is_vfat) { opts->shortname = VFAT_SFN_DISPLAY_LOWER|VFAT_SFN_CREATE_WIN95; opts->rodir = 0; } else { opts->shortname = 0; opts->rodir = 1; } opts->name_check = 'n'; opts->quiet = opts->showexec = opts->sys_immutable = opts->dotsOK = 0; opts->utf8 = opts->unicode_xlate = 0; opts->numtail = 1; opts->usefree = opts->nocase = 0; opts->tz_utc = 0; *debug = 0; if (!options) goto out; while ((p = strsep(&options, ",")) != NULL) { int token; if (!*p) continue; token = match_token(p, fat_tokens, args); if (token == Opt_err) { if (is_vfat) token = match_token(p, vfat_tokens, args); else token = match_token(p, msdos_tokens, args); } switch (token) { case Opt_check_s: opts->name_check = 's'; break; case Opt_check_r: opts->name_check = 'r'; break; case Opt_check_n: opts->name_check = 'n'; break; case Opt_usefree: opts->usefree = 1; break; case Opt_nocase: if (!is_vfat) opts->nocase = 1; else { /* for backward compatibility */ opts->shortname = VFAT_SFN_DISPLAY_WIN95 | VFAT_SFN_CREATE_WIN95; } break; case Opt_quiet: opts->quiet = 1; break; case Opt_showexec: opts->showexec = 1; break; case Opt_debug: *debug = 1; break; case Opt_immutable: opts->sys_immutable = 1; break; case Opt_uid: if (match_int(&args[0], &option)) return 0; opts->fs_uid = option; break; case Opt_gid: if (match_int(&args[0], &option)) return 0; opts->fs_gid = option; break; case Opt_umask: if (match_octal(&args[0], &option)) return 0; opts->fs_fmask = opts->fs_dmask = option; break; case Opt_dmask: if (match_octal(&args[0], &option)) return 0; opts->fs_dmask = option; break; case Opt_fmask: if (match_octal(&args[0], &option))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -