📄 readdir.c
字号:
/* * fs/cifs/readdir.c * * Directory search handling * * Copyright (C) International Business Machines Corp., 2004, 2007 * Author(s): Steve French (sfrench@us.ibm.com) * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include <linux/fs.h>#include <linux/pagemap.h>#include <linux/stat.h>#include <linux/smp_lock.h>#include "cifspdu.h"#include "cifsglob.h"#include "cifsproto.h"#include "cifs_unicode.h"#include "cifs_debug.h"#include "cifs_fs_sb.h"#include "cifsfs.h"#ifdef CONFIG_CIFS_DEBUG2static void dump_cifs_file_struct(struct file *file, char *label){ struct cifsFileInfo *cf; if (file) { cf = file->private_data; if (cf == NULL) { cFYI(1, ("empty cifs private file data")); return; } if (cf->invalidHandle) { cFYI(1, ("invalid handle")); } if (cf->srch_inf.endOfSearch) { cFYI(1, ("end of search")); } if (cf->srch_inf.emptyDir) { cFYI(1, ("empty dir")); } }}#endif /* DEBUG2 *//* Returns one if new inode created (which therefore needs to be hashed) *//* Might check in the future if inode number changed so we can rehash inode */static int construct_dentry(struct qstr *qstring, struct file *file, struct inode **ptmp_inode, struct dentry **pnew_dentry){ struct dentry *tmp_dentry; struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; int rc = 0; cFYI(1, ("For %s", qstring->name));#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) cifs_sb = CIFS_SB(file->f_dentry->d_sb); pTcon = cifs_sb->tcon; qstring->hash = full_name_hash(qstring->name, qstring->len); tmp_dentry = d_lookup(file->f_dentry, qstring); if (tmp_dentry) { cFYI(0, ("existing dentry with inode 0x%p", tmp_dentry->d_inode)); *ptmp_inode = tmp_dentry->d_inode;/* BB overwrite old name? i.e. tmp_dentry->d_name and tmp_dentry->d_name.len??*/ if (*ptmp_inode == NULL) { *ptmp_inode = new_inode(file->f_dentry->d_sb);#else cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); pTcon = cifs_sb->tcon; qstring->hash = full_name_hash(qstring->name, qstring->len); tmp_dentry = d_lookup(file->f_path.dentry, qstring); if (tmp_dentry) { cFYI(0, ("existing dentry with inode 0x%p", tmp_dentry->d_inode)); *ptmp_inode = tmp_dentry->d_inode;/* BB overwrite old name? i.e. tmp_dentry->d_name and tmp_dentry->d_name.len??*/ if (*ptmp_inode == NULL) { *ptmp_inode = new_inode(file->f_path.dentry->d_sb);#endif if (*ptmp_inode == NULL) return rc; rc = 1; }#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 19) if (file->f_path.dentry->d_sb->s_flags & MS_NOATIME)#else if (file->f_dentry->d_sb->s_flags & MS_NOATIME)#endif (*ptmp_inode)->i_flags |= S_NOATIME | S_NOCMTIME; } else {#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) tmp_dentry = d_alloc(file->f_dentry, qstring);#else tmp_dentry = d_alloc(file->f_path.dentry, qstring);#endif if (tmp_dentry == NULL) { cERROR(1, ("Failed allocating dentry")); *ptmp_inode = NULL; return rc; }#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) *ptmp_inode = new_inode(file->f_dentry->d_sb);#else *ptmp_inode = new_inode(file->f_path.dentry->d_sb);#endif if (pTcon->nocase) tmp_dentry->d_op = &cifs_ci_dentry_ops; else tmp_dentry->d_op = &cifs_dentry_ops; if (*ptmp_inode == NULL) return rc;#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 19) if (file->f_path.dentry->d_sb->s_flags & MS_NOATIME)#else if (file->f_dentry->d_sb->s_flags & MS_NOATIME)#endif (*ptmp_inode)->i_flags |= S_NOATIME | S_NOCMTIME; rc = 2; } tmp_dentry->d_time = jiffies; *pnew_dentry = tmp_dentry; return rc;}static void AdjustForTZ(struct cifsTconInfo *tcon, struct inode *inode){ if ((tcon) && (tcon->ses) && (tcon->ses->server)) {#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) inode->i_ctime.tv_sec += tcon->ses->server->timeAdj; inode->i_mtime.tv_sec += tcon->ses->server->timeAdj; inode->i_atime.tv_sec += tcon->ses->server->timeAdj;#else inode->i_ctime += tcon->ses->server->timeAdj; inode->i_mtime += tcon->ses->server->timeAdj; inode->i_atime += tcon->ses->server->timeAdj;#endif } return;}static void fill_in_inode(struct inode *tmp_inode, int new_buf_type, char *buf, int *pobject_type, int isNewInode){ loff_t local_size;#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) struct timespec local_mtime;#else time_t local_mtime;#endif struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode); struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb); __u32 attr; __u64 allocation_size; __u64 end_of_file; /* save mtime and size */ local_mtime = tmp_inode->i_mtime; local_size = tmp_inode->i_size; if (new_buf_type) { FILE_DIRECTORY_INFO *pfindData = (FILE_DIRECTORY_INFO *)buf; attr = le32_to_cpu(pfindData->ExtFileAttributes); allocation_size = le64_to_cpu(pfindData->AllocationSize); end_of_file = le64_to_cpu(pfindData->EndOfFile); tmp_inode->i_atime = cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime)); tmp_inode->i_mtime = cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime)); tmp_inode->i_ctime = cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime)); } else { /* legacy, OS2 and DOS style *//* struct timespec ts;*/ FIND_FILE_STANDARD_INFO * pfindData = (FIND_FILE_STANDARD_INFO *)buf; tmp_inode->i_mtime = cnvrtDosUnixTm( le16_to_cpu(pfindData->LastWriteDate), le16_to_cpu(pfindData->LastWriteTime)); tmp_inode->i_atime = cnvrtDosUnixTm( le16_to_cpu(pfindData->LastAccessDate), le16_to_cpu(pfindData->LastAccessTime)); tmp_inode->i_ctime = cnvrtDosUnixTm( le16_to_cpu(pfindData->LastWriteDate), le16_to_cpu(pfindData->LastWriteTime)); AdjustForTZ(cifs_sb->tcon, tmp_inode); attr = le16_to_cpu(pfindData->Attributes); allocation_size = le32_to_cpu(pfindData->AllocationSize); end_of_file = le32_to_cpu(pfindData->DataSize); } /* Linux can not store file creation time unfortunately so ignore it */ cifsInfo->cifsAttrs = attr; cifsInfo->time = jiffies; /* treat dos attribute of read-only as read-only mode bit e.g. 555? */ /* 2767 perms - indicate mandatory locking */ /* BB fill in uid and gid here? with help from winbind? or retrieve from NTFS stream extended attribute */ if (atomic_read(&cifsInfo->inUse) == 0) { tmp_inode->i_uid = cifs_sb->mnt_uid; tmp_inode->i_gid = cifs_sb->mnt_gid; /* set default mode. will override for dirs below */ tmp_inode->i_mode = cifs_sb->mnt_file_mode; } else { /* mask off the type bits since it gets set below and we do not want to get two type bits set */ tmp_inode->i_mode &= ~S_IFMT; } if (attr & ATTR_DIRECTORY) { *pobject_type = DT_DIR; /* override default perms since we do not lock dirs */ if (atomic_read(&cifsInfo->inUse) == 0) { tmp_inode->i_mode = cifs_sb->mnt_dir_mode; } tmp_inode->i_mode |= S_IFDIR; } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && (attr & ATTR_SYSTEM)) { if (end_of_file == 0) { *pobject_type = DT_FIFO; tmp_inode->i_mode |= S_IFIFO; } else { /* rather than get the type here, we mark the inode as needing revalidate and get the real type (blk vs chr vs. symlink) later ie in lookup */ *pobject_type = DT_REG; tmp_inode->i_mode |= S_IFREG; cifsInfo->time = 0; }/* we no longer mark these because we could not follow them *//* } else if (attr & ATTR_REPARSE) { *pobject_type = DT_LNK; tmp_inode->i_mode |= S_IFLNK; */ } else { *pobject_type = DT_REG; tmp_inode->i_mode |= S_IFREG; if (attr & ATTR_READONLY) tmp_inode->i_mode &= ~(S_IWUGO); else if ((tmp_inode->i_mode & S_IWUGO) == 0) /* the ATTR_READONLY flag may have been changed on */ /* server -- set any w bits allowed by mnt_file_mode */ tmp_inode->i_mode |= (S_IWUGO & cifs_sb->mnt_file_mode); } /* could add code here - to validate if device or weird share type? */ /* can not fill in nlink here as in qpathinfo version and Unx search */ if (atomic_read(&cifsInfo->inUse) == 0) { atomic_set(&cifsInfo->inUse, 1); } spin_lock(&tmp_inode->i_lock); if (is_size_safe_to_change(cifsInfo, end_of_file)) { /* can not safely change the file size here if the client is writing to it due to potential races */ i_size_write(tmp_inode, end_of_file); /* 512 bytes (2**9) is the fake blocksize that must be used */ /* for this calculation, even though the reported blocksize is larger */ tmp_inode->i_blocks = (512 - 1 + allocation_size) >> 9; } spin_unlock(&tmp_inode->i_lock); if (allocation_size < end_of_file) cFYI(1, ("May be sparse file, allocation less than file size")); cFYI(1, ("File Size %ld and blocks %llu", (unsigned long)tmp_inode->i_size, (unsigned long long)tmp_inode->i_blocks)); if (S_ISREG(tmp_inode->i_mode)) { cFYI(1, ("File inode")); tmp_inode->i_op = &cifs_file_inode_ops; if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) { if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) tmp_inode->i_fop = &cifs_file_direct_nobrl_ops; else tmp_inode->i_fop = &cifs_file_direct_ops; } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) tmp_inode->i_fop = &cifs_file_nobrl_ops; else tmp_inode->i_fop = &cifs_file_ops; if ((cifs_sb->tcon) && (cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server->maxBuf < PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)) tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf; else tmp_inode->i_data.a_ops = &cifs_addr_ops; if (isNewInode) return; /* No sense invalidating pages for new inode since have not started caching readahead file data yet */ if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) && (local_size == tmp_inode->i_size)) { cFYI(1, ("inode exists but unchanged")); } else { /* file may have changed on server */ cFYI(1, ("invalidate inode, readdir detected change")); invalidate_remote_inode(tmp_inode); } } else if (S_ISDIR(tmp_inode->i_mode)) { cFYI(1, ("Directory inode")); tmp_inode->i_op = &cifs_dir_inode_ops; tmp_inode->i_fop = &cifs_dir_ops; } else if (S_ISLNK(tmp_inode->i_mode)) { cFYI(1, ("Symbolic Link inode")); tmp_inode->i_op = &cifs_symlink_inode_ops; } else { cFYI(1, ("Init special inode")); init_special_inode(tmp_inode, tmp_inode->i_mode, tmp_inode->i_rdev); }}static void unix_fill_in_inode(struct inode *tmp_inode, FILE_UNIX_INFO *pfindData, int *pobject_type, int isNewInode){ loff_t local_size;#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) struct timespec local_mtime;#else time_t local_mtime;#endif struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode); struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb); __u32 type = le32_to_cpu(pfindData->Type); __u64 num_of_bytes = le64_to_cpu(pfindData->NumOfBytes); __u64 end_of_file = le64_to_cpu(pfindData->EndOfFile); cifsInfo->time = jiffies; atomic_inc(&cifsInfo->inUse); /* save mtime and size */ local_mtime = tmp_inode->i_mtime; local_size = tmp_inode->i_size; tmp_inode->i_atime = cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime)); tmp_inode->i_mtime = cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastModificationTime)); tmp_inode->i_ctime = cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastStatusChange)); tmp_inode->i_mode = le64_to_cpu(pfindData->Permissions); /* since we set the inode type below we need to mask off type to avoid strange results if bits above were corrupt */ tmp_inode->i_mode &= ~S_IFMT; if (type == UNIX_FILE) { *pobject_type = DT_REG; tmp_inode->i_mode |= S_IFREG; } else if (type == UNIX_SYMLINK) { *pobject_type = DT_LNK; tmp_inode->i_mode |= S_IFLNK; } else if (type == UNIX_DIR) { *pobject_type = DT_DIR; tmp_inode->i_mode |= S_IFDIR; } else if (type == UNIX_CHARDEV) { *pobject_type = DT_CHR; tmp_inode->i_mode |= S_IFCHR; tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor), le64_to_cpu(pfindData->DevMinor) & MINORMASK); } else if (type == UNIX_BLOCKDEV) { *pobject_type = DT_BLK; tmp_inode->i_mode |= S_IFBLK; tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor), le64_to_cpu(pfindData->DevMinor) & MINORMASK); } else if (type == UNIX_FIFO) { *pobject_type = DT_FIFO; tmp_inode->i_mode |= S_IFIFO; } else if (type == UNIX_SOCKET) { *pobject_type = DT_SOCK; tmp_inode->i_mode |= S_IFSOCK; } else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -