예제 #1
0
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;
	}

	/* 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;

		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))
		/*
		 * 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);
	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;
}
예제 #2
0
파일: link.c 프로젝트: ANFS/ANFS-kernel
int
CIFSCheckMFSymlink(struct cifs_fattr *fattr,
		   const unsigned char *path,
		   struct cifs_sb_info *cifs_sb, int xid)
{
	int rc;
	int oplock = 0;
	__u16 netfid = 0;
	struct tcon_link *tlink;
	struct cifsTconInfo *pTcon;
	u8 *buf;
	char *pbuf;
	unsigned int bytes_read = 0;
	int buf_type = CIFS_NO_BUFFER;
	unsigned int link_len = 0;
	FILE_ALL_INFO file_info;

	if (!CIFSCouldBeMFSymlink(fattr))
		/* it's not a symlink */
		return 0;

	tlink = cifs_sb_tlink(cifs_sb);
	if (IS_ERR(tlink))
		return PTR_ERR(tlink);
	pTcon = tlink_tcon(tlink);

	rc = CIFSSMBOpen(xid, pTcon, path, FILE_OPEN, GENERIC_READ,
			 CREATE_NOT_DIR, &netfid, &oplock, &file_info,
			 cifs_sb->local_nls,
			 cifs_sb->mnt_cifs_flags &
				CIFS_MOUNT_MAP_SPECIAL_CHR);
	if (rc != 0)
		goto out;

	if (file_info.EndOfFile != CIFS_MF_SYMLINK_FILE_SIZE) {
		CIFSSMBClose(xid, pTcon, netfid);
		/* it's not a symlink */
		goto out;
	}

	buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL);
	if (!buf) {
		rc = -ENOMEM;
		goto out;
	}
	pbuf = buf;

	rc = CIFSSMBRead(xid, pTcon, netfid,
			 CIFS_MF_SYMLINK_FILE_SIZE /* length */,
			 0 /* offset */,
			 &bytes_read, &pbuf, &buf_type);
	CIFSSMBClose(xid, pTcon, netfid);
	if (rc != 0) {
		kfree(buf);
		goto out;
	}

	rc = CIFSParseMFSymlink(buf, bytes_read, &link_len, NULL);
	kfree(buf);
	if (rc == -EINVAL) {
		/* it's not a symlink */
		rc = 0;
		goto out;
	}

	if (rc != 0)
		goto out;

	/* it is a symlink */
	fattr->cf_eof = link_len;
	fattr->cf_mode &= ~S_IFMT;
	fattr->cf_mode |= S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO;
	fattr->cf_dtype = DT_LNK;
out:
	cifs_put_tlink(tlink);
	return rc;
}
예제 #3
0
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;
}