📄 fs.c
字号:
/* * fs.c - NTFS driver for Linux 2.4.x * * Legato Systems, Inc. (http://www.legato.com) have sponsored Anton * Altaparmakov to develop NTFS on Linux since June 2001. * * Copyright (C) 1995-1997, 1999 Martin von L鰓is * Copyright (C) 1996 Richard Russon * Copyright (C) 1996-1997 R間is Duchesne * Copyright (C) 2000-2001, Anton Altaparmakov (AIA) */#include <linux/config.h>#include <linux/errno.h>#include "ntfstypes.h"#include "struct.h"#include "util.h"#include "inode.h"#include "super.h"#include "dir.h"#include "support.h"#include "macros.h"#include "sysctl.h"#include "attr.h"#include <linux/module.h>#include <asm/uaccess.h>#include <linux/locks.h>#include <linux/init.h>#include <linux/smp_lock.h>#include <linux/blkdev.h>#include <asm/page.h>#include <linux/nls.h>#include <linux/ntfs_fs.h>/* Forward declarations. */static struct inode_operations ntfs_dir_inode_operations;static struct file_operations ntfs_dir_operations;#define ITEM_SIZE 2040/* Io functions to user space. */static void ntfs_putuser(ntfs_io* dest, void *src, ntfs_size_t len){ copy_to_user(dest->param, src, len); dest->param += len;}#ifdef CONFIG_NTFS_RWstruct ntfs_getuser_update_vm_s { const char *user; struct inode *ino; loff_t off;};static void ntfs_getuser_update_vm(void *dest, ntfs_io *src, ntfs_size_t len){ struct ntfs_getuser_update_vm_s *p = src->param; copy_from_user(dest, p->user, len); p->user += len; p->off += len;}#endif/* loff_t is 64 bit signed, so is cool. */static ssize_t ntfs_read(struct file *filp, char *buf, size_t count,loff_t *off){ int error; ntfs_io io; ntfs_attribute *attr; ntfs_inode *ino = NTFS_LINO2NINO(filp->f_dentry->d_inode); /* Inode is not properly initialized. */ if (!ino) return -EINVAL; ntfs_debug(DEBUG_OTHER, "ntfs_read %x, %Lx, %x ->", (unsigned)ino->i_number, (unsigned long long)*off, (unsigned)count); attr = ntfs_find_attr(ino, ino->vol->at_data, NULL); /* Inode has no unnamed data attribute. */ if (!attr) { ntfs_debug(DEBUG_OTHER, "ntfs_read: $DATA not found!\n"); return -EINVAL; } if (attr->flags & ATTR_IS_ENCRYPTED) return -EACCES; /* Read the data. */ io.fn_put = ntfs_putuser; io.fn_get = 0; io.param = buf; io.size = count; error = ntfs_read_attr(ino, ino->vol->at_data, NULL, *off, &io); if (error && !io.size) { ntfs_debug(DEBUG_OTHER, "ntfs_read: read_attr failed with " "error %i, io size %u.\n", error, io.size); return error; } *off += io.size; ntfs_debug(DEBUG_OTHER, "ntfs_read: finished. read %u bytes.\n", io.size); return io.size;}#ifdef CONFIG_NTFS_RWstatic ssize_t ntfs_write(struct file *filp, const char *buf, size_t count, loff_t *pos){ int err; struct inode *vfs_ino = filp->f_dentry->d_inode; ntfs_inode *ntfs_ino = NTFS_LINO2NINO(vfs_ino); ntfs_attribute *data; ntfs_io io; struct ntfs_getuser_update_vm_s param; if (!ntfs_ino) return -EINVAL; ntfs_debug(DEBUG_LINUX, "%s(): Entering for inode 0x%lx, *pos 0x%Lx, " "count 0x%x.\n", __FUNCTION__, ntfs_ino->i_number, *pos, count); /* Allows to lock fs ro at any time. */ if (vfs_ino->i_sb->s_flags & MS_RDONLY) return -EROFS; data = ntfs_find_attr(ntfs_ino, ntfs_ino->vol->at_data, NULL); if (!data) return -EINVAL; /* Evaluating O_APPEND is the file system's job... */ if (filp->f_flags & O_APPEND) *pos = vfs_ino->i_size; if (!data->resident && *pos + count > data->allocated) { err = ntfs_extend_attr(ntfs_ino, data, *pos + count); if (err < 0) return err; } param.user = buf; param.ino = vfs_ino; param.off = *pos; io.fn_put = 0; io.fn_get = ntfs_getuser_update_vm; io.param = ¶m; io.size = count; io.do_read = 0; err = ntfs_readwrite_attr(ntfs_ino, data, *pos, &io); ntfs_debug(DEBUG_LINUX, "%s(): Returning %i\n", __FUNCTION__, -err); if (!err) { *pos += io.size; if (*pos > vfs_ino->i_size) vfs_ino->i_size = *pos; mark_inode_dirty(vfs_ino); return io.size; } return err;}#endifstruct ntfs_filldir { struct inode *dir; filldir_t filldir; unsigned int type; u32 ph, pl; void *dirent; char *name; int namelen; int ret_code;};static int ntfs_printcb(ntfs_u8 *entry, void *param){ unsigned long inum = NTFS_GETU64(entry) & 0xffffffffffff; struct ntfs_filldir *nf = param; u32 flags = NTFS_GETU32(entry + 0x48); char show_sys_files = 0; u8 name_len = NTFS_GETU8(entry + 0x50); u8 name_type = NTFS_GETU8(entry + 0x51); int err; unsigned file_type; switch (nf->type) { case ngt_dos: /* Don't display long names. */ if (!(name_type & 2)) return 0; break; case ngt_nt: /* Don't display short-only names. */ if ((name_type & 3) == 2) return 0; break; case ngt_posix: break; case ngt_full: show_sys_files = 1; break; default: BUG(); } err = ntfs_encodeuni(NTFS_INO2VOL(nf->dir), (ntfs_u16*)(entry + 0x52), name_len, &nf->name, &nf->namelen); if (err) { ntfs_debug(DEBUG_OTHER, "%s(): Skipping unrepresentable " "file.\n", __FUNCTION__); err = 0; goto err_noname; } if (!show_sys_files && inum < 0x10UL) { ntfs_debug(DEBUG_OTHER, "%s(): Skipping system file (%s).\n", __FUNCTION__, nf->name); err = 0; goto err_ret; } /* Do not return ".", as this is faked. */ if (nf->namelen == 1 && nf->name[0] == '.') { ntfs_debug(DEBUG_OTHER, "%s(): Skipping \".\"\n", __FUNCTION__); err = 0; goto err_ret; } nf->name[nf->namelen] = 0; if (flags & 0x10000000) /* FILE_ATTR_DUP_FILE_NAME_INDEX_PRESENT */ file_type = DT_DIR; else file_type = DT_REG; ntfs_debug(DEBUG_OTHER, "%s(): Calling filldir for %s with " "len %i, f_pos 0x%Lx, inode %lu, %s.\n", __FUNCTION__, nf->name, nf->namelen, (loff_t)(nf->ph << 16) | nf->pl, inum, file_type == DT_DIR ? "DT_DIR" : "DT_REG"); /* * Userspace side of filldir expects an off_t rather than an loff_t. * And it also doesn't like the most significant bit being set as it * then considers the value to be negative. Thus this implementation * limits the number of index records to 32766, which should be plenty. */ err = nf->filldir(nf->dirent, nf->name, nf->namelen, (loff_t)(nf->ph << 16) | nf->pl, inum, file_type); if (err) nf->ret_code = err;err_ret: ntfs_free(nf->name);err_noname: nf->namelen = 0; nf->name = NULL; return err;}/* * readdir returns '.', then '..', then the directory entries in sequence. * As the root directory contains an entry for itself, '.' is not emulated for * the root directory. */static int ntfs_readdir(struct file* filp, void *dirent, filldir_t filldir){ struct inode *dir = filp->f_dentry->d_inode; int err; struct ntfs_filldir cb; cb.ret_code = 0; cb.pl = filp->f_pos & 0xffff; cb.ph = (filp->f_pos >> 16) & 0x7fff; filp->f_pos = (loff_t)(cb.ph << 16) | cb.pl; ntfs_debug(DEBUG_OTHER, "%s(): Entering for inode %lu, f_pos 0x%Lx, " "i_mode 0x%x, i_count %lu.\n", __FUNCTION__, dir->i_ino, filp->f_pos, (unsigned int)dir->i_mode, atomic_read(&dir->i_count)); if (!cb.ph) { /* Start of directory. Emulate "." and "..". */ if (!cb.pl) { ntfs_debug(DEBUG_OTHER, "%s(): Calling filldir for . " "with len 1, f_pos 0x%Lx, inode %lu, " "DT_DIR.\n", __FUNCTION__, filp->f_pos, dir->i_ino); cb.ret_code = filldir(dirent, ".", 1, filp->f_pos, dir->i_ino, DT_DIR); if (cb.ret_code) goto done; cb.pl++; filp->f_pos = (loff_t)(cb.ph << 16) | cb.pl; } if (cb.pl == (u32)1) { ntfs_debug(DEBUG_OTHER, "%s(): Calling filldir for .. " "with len 2, f_pos 0x%Lx, inode %lu, " "DT_DIR.\n", __FUNCTION__, filp->f_pos, filp->f_dentry->d_parent->d_inode->i_ino); cb.ret_code = filldir(dirent, "..", 2, filp->f_pos, filp->f_dentry->d_parent->d_inode->i_ino, DT_DIR); if (cb.ret_code) goto done; cb.pl++; filp->f_pos = (loff_t)(cb.ph << 16) | cb.pl; } } else if (cb.ph >= 0x7fff) /* End of directory. */ goto done; cb.dir = dir; cb.filldir = filldir; cb.dirent = dirent; cb.type = NTFS_INO2VOL(dir)->ngt; do { ntfs_debug(DEBUG_OTHER, "%s(): Looking for next file using " "ntfs_getdir_unsorted(), f_pos 0x%Lx.\n", __FUNCTION__, (loff_t)(cb.ph << 16) | cb.pl); err = ntfs_getdir_unsorted(NTFS_LINO2NINO(dir), &cb.ph, &cb.pl, ntfs_printcb, &cb); } while (!err && !cb.ret_code && cb.ph < 0x7fff); filp->f_pos = (loff_t)(cb.ph << 16) | cb.pl; ntfs_debug(DEBUG_OTHER, "%s(): After ntfs_getdir_unsorted()" " calls, f_pos 0x%Lx.\n", __FUNCTION__, filp->f_pos); if (!err) {done:#ifdef DEBUG if (!cb.ret_code) ntfs_debug(DEBUG_OTHER, "%s(): EOD, f_pos 0x%Lx, " "returning 0.\n", __FUNCTION__, filp->f_pos); else ntfs_debug(DEBUG_OTHER, "%s(): filldir returned %i, " "returning 0, f_pos 0x%Lx.\n", __FUNCTION__, cb.ret_code, filp->f_pos);#endif return 0; } ntfs_debug(DEBUG_OTHER, "%s(): Returning %i, f_pos 0x%Lx.\n", __FUNCTION__, err, filp->f_pos); return err;}/* Copied from vfat driver. */static int simple_getbool(char *s, int *setval){ if (s) { if (!strcmp(s, "1") || !strcmp(s, "yes") || !strcmp(s, "true")) *setval = 1; else if (!strcmp(s, "0") || !strcmp(s, "no") || !strcmp(s, "false")) *setval = 0; else return 0; } else *setval = 1; return 1;}/* * This needs to be outside parse_options() otherwise a remount will reset * these unintentionally. */static void init_ntfs_super_block(ntfs_volume* vol){ vol->uid = vol->gid = 0; vol->umask = 0077; vol->ngt = ngt_nt; vol->nls_map = (void*)-1; vol->mft_zone_multiplier = -1;}/* Parse the (re)mount options. */static int parse_options(ntfs_volume *vol, char *opt){ char *value; /* Defaults if not specified and !remount. */ ntfs_uid_t uid = -1; /* 0, root user only */ ntfs_gid_t gid = -1; /* 0, root user only */ int umask = -1; /* 0077, owner access only */ unsigned int ngt = -1; /* ngt_nt */ void *nls_map = NULL; /* Try to load the default NLS. */ int use_utf8 = -1; /* If no NLS specified and loading the default NLS failed use utf8. */ int mft_zone_mul = -1; /* 1 */ if (!opt) goto done; for (opt = strtok(opt, ","); opt; opt = strtok(NULL, ",")) { if ((value = strchr(opt, '=')) != NULL) *value ++= '\0'; if (strcmp(opt, "uid") == 0) { if (!value || !*value) goto needs_arg; uid = simple_strtoul(value, &value, 0); if (*value) { printk(KERN_ERR "NTFS: uid invalid argument\n"); return 0; } } else if (strcmp(opt, "gid") == 0) { if (!value || !*value) goto needs_arg; gid = simple_strtoul(value, &value, 0); if (*value) { printk(KERN_ERR "NTFS: gid invalid argument\n"); return 0; } } else if (strcmp(opt, "umask") == 0) { if (!value || !*value) goto needs_arg;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -