static int cifs_filldir(char *find_entry, struct file *file, struct dir_context *ctx, char *scratch_buf, unsigned int max_len) { struct cifsFileInfo *file_info = file->private_data; struct super_block *sb = file_inode(file)->i_sb; struct cifs_sb_info *cifs_sb = CIFS_SB(sb); struct cifs_dirent de = { NULL, }; struct cifs_fattr fattr; struct qstr name; int rc = 0; ino_t ino; rc = cifs_fill_dirent(&de, find_entry, file_info->srch_inf.info_level, file_info->srch_inf.unicode); if (rc) return rc; if (de.namelen > max_len) { cifs_dbg(VFS, "bad search response length %zd past smb end\n", de.namelen); return -EINVAL; } /* skip . and .. since we added them first */ if (cifs_entry_is_dot(&de, file_info->srch_inf.unicode)) return 0; if (file_info->srch_inf.unicode) { struct nls_table *nlt = cifs_sb->local_nls; int map_type; map_type = cifs_remap(cifs_sb); name.name = scratch_buf; name.len = cifs_from_utf16((char *)name.name, (__le16 *)de.name, UNICODE_NAME_MAX, min_t(size_t, de.namelen, (size_t)max_len), nlt, map_type); name.len -= nls_nullsize(nlt); } else { name.name = de.name; name.len = de.namelen; } switch (file_info->srch_inf.info_level) { case SMB_FIND_FILE_UNIX: cifs_unix_basic_to_fattr(&fattr, &((FILE_UNIX_INFO *)find_entry)->basic, cifs_sb); break; case SMB_FIND_FILE_INFO_STANDARD: cifs_std_info_to_fattr(&fattr, (FIND_FILE_STANDARD_INFO *)find_entry, cifs_sb); break; default: cifs_dir_info_to_fattr(&fattr, (FILE_DIRECTORY_INFO *)find_entry, cifs_sb); break; } if (de.ino && (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) { fattr.cf_uniqueid = de.ino; } else { fattr.cf_uniqueid = iunique(sb, ROOT_I); cifs_autodisable_serverino(cifs_sb); } if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) && couldbe_mf_symlink(&fattr)) /* * trying to get the type and mode can be slow, * so just call those regular files for now, and mark * for reval */ fattr.cf_flags |= CIFS_FATTR_NEED_REVAL; cifs_prime_dcache(file->f_path.dentry, &name, &fattr); ino = cifs_uniqueid_to_ino_t(fattr.cf_uniqueid); return !dir_emit(ctx, name.name, name.len, ino, fattr.cf_dtype); }
static int cifs_filldir(char *find_entry, struct file *file, filldir_t filldir, void *dirent, char *scratch_buf, unsigned int max_len) { struct cifsFileInfo *file_info = file->private_data; struct super_block *sb = file->f_path.dentry->d_sb; struct cifs_sb_info *cifs_sb = CIFS_SB(sb); struct cifs_dirent de = { NULL, }; struct cifs_fattr fattr; struct dentry *dentry; struct qstr name; int rc = 0; ino_t ino; rc = cifs_fill_dirent(&de, find_entry, file_info->srch_inf.info_level, file_info->srch_inf.unicode); if (rc) return rc; if (de.namelen > max_len) { cERROR(1, "bad search response length %zd past smb end", de.namelen); return -EINVAL; } if (cifs_entry_is_dot(&de, file_info->srch_inf.unicode)) return 0; if (file_info->srch_inf.unicode) { struct nls_table *nlt = cifs_sb->local_nls; name.name = scratch_buf; name.len = cifs_from_utf16((char *)name.name, (__le16 *)de.name, UNICODE_NAME_MAX, min_t(size_t, de.namelen, (size_t)max_len), nlt, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); name.len -= nls_nullsize(nlt); } else { name.name = de.name; name.len = de.namelen; } switch (file_info->srch_inf.info_level) { case SMB_FIND_FILE_UNIX: cifs_unix_basic_to_fattr(&fattr, &((FILE_UNIX_INFO *)find_entry)->basic, cifs_sb); break; case SMB_FIND_FILE_INFO_STANDARD: cifs_std_info_to_fattr(&fattr, (FIND_FILE_STANDARD_INFO *)find_entry, cifs_sb); break; default: cifs_dir_info_to_fattr(&fattr, (FILE_DIRECTORY_INFO *)find_entry, cifs_sb); break; } if (de.ino && (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) { fattr.cf_uniqueid = de.ino; } else { fattr.cf_uniqueid = iunique(sb, ROOT_I); cifs_autodisable_serverino(cifs_sb); } if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) && CIFSCouldBeMFSymlink(&fattr)) fattr.cf_flags |= CIFS_FATTR_NEED_REVAL; ino = cifs_uniqueid_to_ino_t(fattr.cf_uniqueid); dentry = cifs_readdir_lookup(file->f_dentry, &name, &fattr); rc = filldir(dirent, name.name, name.len, file->f_pos, ino, fattr.cf_dtype); dput(dentry); return rc; }
int cifs_posix_open(char *full_path, struct inode **pinode, struct super_block *sb, int mode, int oflags, __u32 *poplock, __u16 *pnetfid, int xid) { int rc; FILE_UNIX_BASIC_INFO *presp_data; __u32 posix_flags = 0; struct cifs_sb_info *cifs_sb = CIFS_SB(sb); struct cifs_fattr fattr; cFYI(1, "posix open %s", full_path); presp_data = kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL); if (presp_data == NULL) return -ENOMEM; /* So far cifs posix extensions can only map the following flags. There are other valid fmode oflags such as FMODE_LSEEK, FMODE_PREAD, but so far we do not seem to need them, and we can treat them as local only */ if ((oflags & (FMODE_READ | FMODE_WRITE)) == (FMODE_READ | FMODE_WRITE)) posix_flags = SMB_O_RDWR; else if (oflags & FMODE_READ) posix_flags = SMB_O_RDONLY; else if (oflags & FMODE_WRITE) posix_flags = SMB_O_WRONLY; if (oflags & O_CREAT) posix_flags |= SMB_O_CREAT; if (oflags & O_EXCL) posix_flags |= SMB_O_EXCL; if (oflags & O_TRUNC) posix_flags |= SMB_O_TRUNC; /* be safe and imply O_SYNC for O_DSYNC */ if (oflags & O_DSYNC) posix_flags |= SMB_O_SYNC; if (oflags & O_DIRECTORY) posix_flags |= SMB_O_DIRECTORY; if (oflags & O_NOFOLLOW) posix_flags |= SMB_O_NOFOLLOW; if (oflags & O_DIRECT) posix_flags |= SMB_O_DIRECT; mode &= ~current_umask(); rc = CIFSPOSIXCreate(xid, cifs_sb->tcon, posix_flags, mode, pnetfid, presp_data, poplock, full_path, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc) goto posix_open_ret; if (presp_data->Type == cpu_to_le32(-1)) goto posix_open_ret; /* open ok, caller does qpathinfo */ if (!pinode) goto posix_open_ret; /* caller does not need info */ cifs_unix_basic_to_fattr(&fattr, presp_data, cifs_sb); /* get new inode and set it up */ if (*pinode == NULL) { cifs_fill_uniqueid(sb, &fattr); *pinode = cifs_iget(sb, &fattr); if (!*pinode) { rc = -ENOMEM; goto posix_open_ret; } } else { cifs_fattr_to_inode(*pinode, &fattr); } posix_open_ret: kfree(presp_data); return rc; }
static int cifs_filldir(char *pfindEntry, struct file *file, filldir_t filldir, void *direntry, char *scratch_buf, unsigned int max_len) { int rc = 0; struct qstr qstring; struct cifsFileInfo *pCifsF; u64 inum; ino_t ino; struct super_block *sb; struct cifs_sb_info *cifs_sb; struct dentry *tmp_dentry; struct cifs_fattr fattr; /* get filename and len into qstring */ /* get dentry */ /* decide whether to create and populate ionde */ if ((direntry == NULL) || (file == NULL)) return -EINVAL; pCifsF = file->private_data; if ((scratch_buf == NULL) || (pfindEntry == NULL) || (pCifsF == NULL)) return -ENOENT; rc = cifs_entry_is_dot(pfindEntry, pCifsF); /* skip . and .. since we added them first */ if (rc != 0) return 0; sb = file->f_path.dentry->d_sb; cifs_sb = CIFS_SB(sb); qstring.name = scratch_buf; rc = cifs_get_name_from_search_buf(&qstring, pfindEntry, pCifsF->srch_inf.info_level, pCifsF->srch_inf.unicode, cifs_sb, max_len, &inum /* returned */); if (rc) return rc; if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX) cifs_unix_basic_to_fattr(&fattr, &((FILE_UNIX_INFO *) pfindEntry)->basic, cifs_sb); else if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD) cifs_std_info_to_fattr(&fattr, (FIND_FILE_STANDARD_INFO *) pfindEntry, cifs_sb); else cifs_dir_info_to_fattr(&fattr, (FILE_DIRECTORY_INFO *) pfindEntry, cifs_sb); if (inum && (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) { fattr.cf_uniqueid = inum; } else { fattr.cf_uniqueid = iunique(sb, ROOT_I); cifs_autodisable_serverino(cifs_sb); } if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) && CIFSCouldBeMFSymlink(&fattr)) /* * trying to get the type and mode can be slow, * so just call those regular files for now, and mark * for reval */ fattr.cf_flags |= CIFS_FATTR_NEED_REVAL; ino = cifs_uniqueid_to_ino_t(fattr.cf_uniqueid); tmp_dentry = cifs_readdir_lookup(file->f_dentry, &qstring, &fattr); rc = filldir(direntry, qstring.name, qstring.len, file->f_pos, ino, fattr.cf_dtype); dput(tmp_dentry); return rc; }
static int cifs_filldir(char *pfindEntry, struct file *file, filldir_t filldir, void *direntry, char *scratch_buf, unsigned int max_len) { int rc = 0; struct qstr qstring; struct cifsFileInfo *pCifsF; u64 inum; ino_t ino; struct super_block *sb; struct cifs_sb_info *cifs_sb; struct dentry *tmp_dentry; struct cifs_fattr fattr; /* get filename and len into qstring */ /* get dentry */ /* decide whether to create and populate ionde */ if ((direntry == NULL) || (file == NULL)) return -EINVAL; pCifsF = file->private_data; if ((scratch_buf == NULL) || (pfindEntry == NULL) || (pCifsF == NULL)) return -ENOENT; rc = cifs_entry_is_dot(pfindEntry, pCifsF); /* skip . and .. since we added them first */ if (rc != 0) return 0; sb = file->f_path.dentry->d_sb; cifs_sb = CIFS_SB(sb); qstring.name = scratch_buf; rc = cifs_get_name_from_search_buf(&qstring, pfindEntry, pCifsF->srch_inf.info_level, pCifsF->srch_inf.unicode, cifs_sb, max_len, &inum /* returned */); if (rc) return rc; if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX) cifs_unix_basic_to_fattr(&fattr, &((FILE_UNIX_INFO *) pfindEntry)->basic, cifs_sb); else if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD) cifs_std_info_to_fattr(&fattr, (FIND_FILE_STANDARD_INFO *) pfindEntry, cifs_sb); else cifs_dir_info_to_fattr(&fattr, (FILE_DIRECTORY_INFO *) pfindEntry, cifs_sb); if (inum && (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) { fattr.cf_uniqueid = inum; } else { fattr.cf_uniqueid = iunique(sb, ROOT_I); cifs_autodisable_serverino(cifs_sb); } ino = cifs_uniqueid_to_ino_t(fattr.cf_uniqueid); tmp_dentry = cifs_readdir_lookup(file->f_dentry, &qstring, &fattr); rc = filldir(direntry, qstring.name, qstring.len, file->f_pos, ino, fattr.cf_dtype); /* * we can not return filldir errors to the caller since they are * "normal" when the stat blocksize is too small - we return remapped * error instead * * FIXME: This looks bogus. filldir returns -EOVERFLOW in the above * case already. Why should we be clobbering other errors from it? */ if (rc) { cFYI(1, ("filldir rc = %d", rc)); rc = -EOVERFLOW; } dput(tmp_dentry); return rc; }