📄 file.c
字号:
int is_size_safe_to_change(struct cifsInodeInfo * cifsInode){ struct list_head *tmp; struct list_head *tmp1; struct cifsFileInfo *open_file = NULL; int rc = TRUE; if(cifsInode == NULL) return rc; read_lock(&GlobalSMBSeslock); list_for_each_safe(tmp, tmp1, &cifsInode->openFileList) { open_file = list_entry(tmp,struct cifsFileInfo, flist); if(open_file == NULL) break; if(open_file->closePend) continue; /* We check if file is open for writing, BB we could supplement this with a check to see if file size changes have been flushed to server - ie inode metadata dirty */ if((open_file->pfile) && ((open_file->pfile->f_flags & O_RDWR) || (open_file->pfile->f_flags & O_WRONLY))) { rc = FALSE; break; } if(tmp->next == NULL) { cFYI(1,("File instance %p removed",tmp)); break; } } read_unlock(&GlobalSMBSeslock); return rc;}voidfill_in_inode(struct inode *tmp_inode, FILE_DIRECTORY_INFO * pfindData, int *pobject_type){ struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode); struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb); __u32 attr = le32_to_cpu(pfindData->ExtFileAttributes); __u64 allocation_size = le64_to_cpu(pfindData->AllocationSize); __u64 end_of_file = le64_to_cpu(pfindData->EndOfFile); cifsInfo->cifsAttrs = attr; cifsInfo->time = jiffies; /* Linux can not store file creation time unfortunately so ignore it */ 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)); /* 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; } cFYI(0, ("CIFS FFIRST: Attributes came in as 0x%x", attr)); if (attr & ATTR_REPARSE) { *pobject_type = DT_LNK; /* BB can this and S_IFREG or S_IFDIR be set as in Windows? */ tmp_inode->i_mode |= S_IFLNK; } else 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 { *pobject_type = DT_REG; tmp_inode->i_mode |= S_IFREG; if(attr & ATTR_READONLY) tmp_inode->i_mode &= ~(S_IWUGO); }/* 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); } if(is_size_safe_to_change(cifsInfo)) { /* 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; } if (allocation_size < end_of_file) cFYI(1, ("Possible sparse file: allocation size less than end of file ")); cFYI(1, ("File Size %ld and blocks %ld and blocksize %ld", (unsigned long) tmp_inode->i_size, tmp_inode->i_blocks, tmp_inode->i_blksize)); if (S_ISREG(tmp_inode->i_mode)) { cFYI(1, (" File inode ")); tmp_inode->i_op = &cifs_file_inode_ops; tmp_inode->i_fop = &cifs_file_ops; tmp_inode->i_data.a_ops = &cifs_addr_ops; } 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); }}voidunix_fill_in_inode(struct inode *tmp_inode, FILE_UNIX_INFO * pfindData, int *pobject_type){ struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode); __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); 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); 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; } tmp_inode->i_uid = le64_to_cpu(pfindData->Uid); tmp_inode->i_gid = le64_to_cpu(pfindData->Gid); tmp_inode->i_nlink = le64_to_cpu(pfindData->Nlinks); if(is_size_safe_to_change(cifsInfo)) { /* 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, not the real blocksize */ tmp_inode->i_blocks = (512 - 1 + num_of_bytes) >> 9; } if (S_ISREG(tmp_inode->i_mode)) { cFYI(1, ("File inode")); tmp_inode->i_op = &cifs_file_inode_ops; tmp_inode->i_fop = &cifs_file_ops; tmp_inode->i_data.a_ops = &cifs_addr_ops; } 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;/* tmp_inode->i_fop = *//* do not need to set to anything */ } else { cFYI(1, ("Special inode")); init_special_inode(tmp_inode, tmp_inode->i_mode, tmp_inode->i_rdev); }}static voidconstruct_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; cFYI(1, ("For %s ", qstring->name)); 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 the 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); if(*ptmp_inode == NULL) return; d_instantiate(tmp_dentry, *ptmp_inode); insert_inode_hash(*ptmp_inode); } } else { tmp_dentry = d_alloc(file->f_dentry, qstring); if(tmp_dentry == NULL) { cERROR(1,("Failed allocating dentry")); *ptmp_inode = NULL; return; } *ptmp_inode = new_inode(file->f_dentry->d_sb); tmp_dentry->d_op = &cifs_dentry_ops; if(*ptmp_inode == NULL) return; d_instantiate(tmp_dentry, *ptmp_inode); d_rehash(tmp_dentry); insert_inode_hash(*ptmp_inode); } tmp_dentry->d_time = jiffies; *pnew_dentry = tmp_dentry;}static void reset_resume_key(struct file * dir_file, unsigned char * filename, unsigned int len,int Unicode,struct nls_table * nls_tab) { struct cifsFileInfo *cifsFile; cifsFile = (struct cifsFileInfo *)dir_file->private_data; if(cifsFile == NULL) return; if(cifsFile->search_resume_name) { kfree(cifsFile->search_resume_name); } if(Unicode) len *= 2; cifsFile->resume_name_length = len; cifsFile->search_resume_name = kmalloc(cifsFile->resume_name_length, GFP_KERNEL); if(cifsFile->search_resume_name == NULL) { cERROR(1,("failed new resume key allocate, length %d", cifsFile->resume_name_length)); return; } if(Unicode) cifs_strtoUCS((wchar_t *) cifsFile->search_resume_name, filename, len, nls_tab); else memcpy(cifsFile->search_resume_name, filename, cifsFile->resume_name_length); cFYI(1,("Reset resume key to: %s with len %d",filename,len)); return;}static intcifs_filldir(struct qstr *pqstring, FILE_DIRECTORY_INFO * pfindData, struct file *file, filldir_t filldir, void *direntry){ struct inode *tmp_inode; struct dentry *tmp_dentry; int object_type,rc; pqstring->name = pfindData->FileName; /* pqstring->len is already set by caller */ construct_dentry(pqstring, file, &tmp_inode, &tmp_dentry); if((tmp_inode == NULL) || (tmp_dentry == NULL)) { return -ENOMEM; } fill_in_inode(tmp_inode, pfindData, &object_type); rc = filldir(direntry, pfindData->FileName, pqstring->len, file->f_pos, tmp_inode->i_ino, object_type); if(rc) { /* due to readdir error we need to recalculate resume key so next readdir will restart on right entry */ cFYI(1,("Error %d on filldir of %s",rc ,pfindData->FileName)); } dput(tmp_dentry); return rc;}static intcifs_filldir_unix(struct qstr *pqstring, FILE_UNIX_INFO * pUnixFindData, struct file *file, filldir_t filldir, void *direntry){ struct inode *tmp_inode; struct dentry *tmp_dentry; int object_type, rc; pqstring->name = pUnixFindData->FileName; pqstring->len = strnlen(pUnixFindData->FileName, MAX_PATHCONF); construct_dentry(pqstring, file, &tmp_inode, &tmp_dentry); if((tmp_inode == NULL) || (tmp_dentry == NULL)) { return -ENOMEM; } unix_fill_in_inode(tmp_inode, pUnixFindData, &object_type); rc = filldir(direntry, pUnixFindData->FileName, pqstring->len, file->f_pos, tmp_inode->i_ino, object_type); if(rc) { /* due to readdir error we need to recalculate resume key so next readdir will restart on right entry */ cFYI(1,("Error %d on filldir of %s",rc ,pUnixFindData->FileName)); } dput(tmp_dentry); return rc;}intcifs_readdir(struct file *file, void *direntry, filldir_t filldir){ int rc = 0; int xid; int Unicode = FALSE; int UnixSearch = FALSE; unsigned int bufsize, i; __u16 searchHandle; struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; struct cifsFileInfo *cifsFile = NULL; char *full_path = NULL; char *data; struct qstr qstring; T2_FFIRST_RSP_PARMS findParms; T2_FNEXT_RSP_PARMS findNextParms; FILE_DIRECTORY_INFO *pfindData; FILE_DIRECTORY_INFO *lastFindData; FILE_UNIX_INFO *pfindDataUnix; xid = GetXid(); cifs_sb = CIFS_SB(file->f_dentry->d_sb); pTcon = cifs_sb->tcon; bufsize = pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE; if(bufsize > CIFS_MAX_MSGSIZE) { FreeXid(xid); return -EIO; } data = kmalloc(bufsize, GFP_KERNEL); pfindData = (FILE_DIRECTORY_INFO *) data; if(data == NULL) { FreeXid(xid); return -ENOMEM; } if(file->f_dentry == NULL) { kfree(data); FreeXid(xid); return -EIO; } down(&file->f_dentry->d_sb->s_vfs_rename_sem); full_path = build_wildcard_path_from_dentry(file->f_dentry); up(&file->f_dentry->d_sb->s_vfs_rename_sem); if(full_path == NULL) { kfree(data); FreeXid(xid); return -ENOMEM; } cFYI(1, ("Full path: %s start at: %lld ", full_path, file->f_pos)); switch ((int) file->f_pos) { case 0: if (filldir(direntry, ".", 1, file->f_pos, file->f_dentry->d_inode->i_ino, DT_DIR) < 0) { cERROR(1, ("Filldir for current dir failed ")); break; } file->f_pos++; /* fallthrough */ case 1: if (filldir(direntry, "..", 2, file->f_pos, file->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) { cERROR(1, ("Filldir for parent dir failed ")); break; } file->f_pos++; /* fallthrough */ case 2: if (file->private_data != NULL) { cifsFile = (struct cifsFileInfo *) file->private_data; if (cifsFile->endOfSearch) { if(cifsFile->emptyDir) { cFYI(1, ("End of search, empty dir")); rc = 0; break; } } else { cifsFile->invalidHandle = TRUE; CIFSFindClose(xid, pTcon, cifsFile->netfid); } if(cifsFile->search_resume_name) { kfree(cifsFile->search_resume_name); cifsFile->search_resume_name = NULL; } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -