Exemple #1
0
/* Note: caller must free return buffer */
char *
build_path_from_dentry(struct dentry *direntry)
{
	struct dentry *temp;
	int namelen;
	int dfsplen;
	char *full_path;
	char dirsep;
	struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);
	struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);

	if (direntry == NULL)
		return NULL;  /* not much we can do if dentry is freed and
		we need to reopen the file after it was closed implicitly
		when the server crashed */

	dirsep = CIFS_DIR_SEP(cifs_sb);
	if (tcon->Flags & SMB_SHARE_IS_IN_DFS)
		dfsplen = strnlen(tcon->treeName, MAX_TREE_SIZE + 1);
	else
		dfsplen = 0;
cifs_bp_rename_retry:
	namelen = dfsplen;
	for (temp = direntry; !IS_ROOT(temp);) {
		namelen += (1 + temp->d_name.len);
		temp = temp->d_parent;
		if (temp == NULL) {
			cERROR(1, "corrupt dentry");
			return NULL;
		}
	}

	full_path = kmalloc(namelen+1, GFP_KERNEL);
	if (full_path == NULL)
		return full_path;
	full_path[namelen] = 0;	/* trailing null */
	for (temp = direntry; !IS_ROOT(temp);) {
		namelen -= 1 + temp->d_name.len;
		if (namelen < 0) {
			break;
		} else {
			full_path[namelen] = dirsep;
			strncpy(full_path + namelen + 1, temp->d_name.name,
				temp->d_name.len);
			cFYI(0, "name: %s", full_path + namelen);
		}
		temp = temp->d_parent;
		if (temp == NULL) {
			cERROR(1, "corrupt dentry");
			kfree(full_path);
			return NULL;
		}
	}
	if (namelen != dfsplen) {
		cERROR(1, "did not end path lookup where expected namelen is %d",
			namelen);
		/* presumably this is only possible if racing with a rename
		of one of the parent directories  (we can not lock the dentries
		above us to prevent this, but retrying should be harmless) */
		kfree(full_path);
		goto cifs_bp_rename_retry;
	}
	/* DIR_SEP already set for byte  0 / vs \ but not for
	   subsequent slashes in prepath which currently must
	   be entered the right way - not sure if there is an alternative
	   since the '\' is a valid posix character so we can not switch
	   those safely to '/' if any are found in the middle of the prepath */
	/* BB test paths to Windows with '/' in the midst of prepath */

	if (dfsplen) {
		strncpy(full_path, tcon->treeName, dfsplen);
		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) {
			int i;
			for (i = 0; i < dfsplen; i++) {
				if (full_path[i] == '\\')
					full_path[i] = '/';
			}
		}
	}
	return full_path;
}
Exemple #2
0
/*
 * Get root dentry from superblock according to prefix path mount option.
 * Return dentry with refcount + 1 on success and NULL otherwise.
 */
static struct dentry *
cifs_get_root(struct smb_vol *vol, struct super_block *sb)
{
	int xid, rc;
	struct inode *inode;
	struct qstr name;
	struct dentry *dparent = NULL, *dchild = NULL, *alias;
	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
	unsigned int i, full_len, len;
	char *full_path = NULL, *pstart;
	char sep;

	full_path = cifs_build_path_to_root(vol, cifs_sb,
					    cifs_sb_master_tcon(cifs_sb));
	if (full_path == NULL)
		return NULL;

	cFYI(1, "Get root dentry for %s", full_path);

	xid = GetXid();
	sep = CIFS_DIR_SEP(cifs_sb);
	dparent = dget(sb->s_root);
	full_len = strlen(full_path);
	full_path[full_len] = sep;
	pstart = full_path + 1;

	for (i = 1, len = 0; i <= full_len; i++) {
		if (full_path[i] != sep || !len) {
			len++;
			continue;
		}

		full_path[i] = 0;
		cFYI(1, "get dentry for %s", pstart);

		name.name = pstart;
		name.len = len;
		name.hash = full_name_hash(pstart, len);
		dchild = d_lookup(dparent, &name);
		if (dchild == NULL) {
			cFYI(1, "not exists");
			dchild = d_alloc(dparent, &name);
			if (dchild == NULL) {
				dput(dparent);
				dparent = NULL;
				goto out;
			}
		}

		cFYI(1, "get inode");
		if (dchild->d_inode == NULL) {
			cFYI(1, "not exists");
			inode = NULL;
			if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext)
				rc = cifs_get_inode_info_unix(&inode, full_path,
							      sb, xid);
			else
				rc = cifs_get_inode_info(&inode, full_path,
							 NULL, sb, xid, NULL);
			if (rc) {
				dput(dchild);
				dput(dparent);
				dparent = NULL;
				goto out;
			}
			alias = d_materialise_unique(dchild, inode);
			if (alias != NULL) {
				dput(dchild);
				if (IS_ERR(alias)) {
					dput(dparent);
					dparent = NULL;
					goto out;
				}
				dchild = alias;
			}
		}
		cFYI(1, "parent %p, child %p", dparent, dchild);

		dput(dparent);
		dparent = dchild;
		len = 0;
		pstart = full_path + i + 1;
		full_path[i] = sep;
	}
out:
	_FreeXid(xid);
	kfree(full_path);
	return dparent;
}
Exemple #3
0
/* Note: caller must free return buffer */
char *
build_path_from_dentry(struct dentry *direntry)
{
	struct dentry *temp;
	int namelen;
	int pplen;
	char *full_path;
	char dirsep;

	if (direntry == NULL)
		return NULL;  /* not much we can do if dentry is freed and
		we need to reopen the file after it was closed implicitly
		when the server crashed */

	dirsep = CIFS_DIR_SEP(CIFS_SB(direntry->d_sb));
	pplen = CIFS_SB(direntry->d_sb)->prepathlen;
cifs_bp_rename_retry:
	namelen = pplen;
	for (temp = direntry; !IS_ROOT(temp);) {
		namelen += (1 + temp->d_name.len);
		temp = temp->d_parent;
		if (temp == NULL) {
			cERROR(1, ("corrupt dentry"));
			return NULL;
		}
	}

	full_path = kmalloc(namelen+1, GFP_KERNEL);
	if (full_path == NULL)
		return full_path;
	full_path[namelen] = 0;	/* trailing null */
	for (temp = direntry; !IS_ROOT(temp);) {
		namelen -= 1 + temp->d_name.len;
		if (namelen < 0) {
			break;
		} else {
			full_path[namelen] = dirsep;
			strncpy(full_path + namelen + 1, temp->d_name.name,
				temp->d_name.len);
			cFYI(0, ("name: %s", full_path + namelen));
		}
		temp = temp->d_parent;
		if (temp == NULL) {
			cERROR(1, ("corrupt dentry"));
			kfree(full_path);
			return NULL;
		}
	}
	if (namelen != pplen) {
		cERROR(1,
		       ("did not end path lookup where expected namelen is %d",
			namelen));
		/* presumably this is only possible if racing with a rename
		of one of the parent directories  (we can not lock the dentries
		above us to prevent this, but retrying should be harmless) */
		kfree(full_path);
		goto cifs_bp_rename_retry;
	}
	/* DIR_SEP already set for byte  0 / vs \ but not for
	   subsequent slashes in prepath which currently must
	   be entered the right way - not sure if there is an alternative
	   since the '\' is a valid posix character so we can not switch
	   those safely to '/' if any are found in the middle of the prepath */
	/* BB test paths to Windows with '/' in the midst of prepath */
	strncpy(full_path, CIFS_SB(direntry->d_sb)->prepath, pplen);
	return full_path;
}
Exemple #4
0
/* Note: caller must free return buffer */
char *
build_path_from_dentry(struct dentry *direntry)
{
	struct dentry *temp;
	int namelen;
	int dfsplen;
	char *full_path;
	char dirsep;
	struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);
	struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
	unsigned seq;

	dirsep = CIFS_DIR_SEP(cifs_sb);
	if (tcon->Flags & SMB_SHARE_IS_IN_DFS)
		dfsplen = strnlen(tcon->treeName, MAX_TREE_SIZE + 1);
	else
		dfsplen = 0;
cifs_bp_rename_retry:
	namelen = dfsplen;
	seq = read_seqbegin(&rename_lock);
	rcu_read_lock();
	for (temp = direntry; !IS_ROOT(temp);) {
		namelen += (1 + temp->d_name.len);
		temp = temp->d_parent;
		if (temp == NULL) {
			cifs_dbg(VFS, "corrupt dentry\n");
			rcu_read_unlock();
			return NULL;
		}
	}
	rcu_read_unlock();

	full_path = kmalloc(namelen+1, GFP_KERNEL);
	if (full_path == NULL)
		return full_path;
	full_path[namelen] = 0;	/* trailing null */
	rcu_read_lock();
	for (temp = direntry; !IS_ROOT(temp);) {
		spin_lock(&temp->d_lock);
		namelen -= 1 + temp->d_name.len;
		if (namelen < 0) {
			spin_unlock(&temp->d_lock);
			break;
		} else {
			full_path[namelen] = dirsep;
			strncpy(full_path + namelen + 1, temp->d_name.name,
				temp->d_name.len);
			cifs_dbg(FYI, "name: %s\n", full_path + namelen);
		}
		spin_unlock(&temp->d_lock);
		temp = temp->d_parent;
		if (temp == NULL) {
			cifs_dbg(VFS, "corrupt dentry\n");
			rcu_read_unlock();
			kfree(full_path);
			return NULL;
		}
	}
	rcu_read_unlock();
	if (namelen != dfsplen || read_seqretry(&rename_lock, seq)) {
		cifs_dbg(FYI, "did not end path lookup where expected. namelen=%ddfsplen=%d\n",
			 namelen, dfsplen);
		/* presumably this is only possible if racing with a rename
		of one of the parent directories  (we can not lock the dentries
		above us to prevent this, but retrying should be harmless) */
		kfree(full_path);
		goto cifs_bp_rename_retry;
	}
	/* DIR_SEP already set for byte  0 / vs \ but not for
	   subsequent slashes in prepath which currently must
	   be entered the right way - not sure if there is an alternative
	   since the '\' is a valid posix character so we can not switch
	   those safely to '/' if any are found in the middle of the prepath */
	/* BB test paths to Windows with '/' in the midst of prepath */

	if (dfsplen) {
		strncpy(full_path, tcon->treeName, dfsplen);
		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) {
			int i;
			for (i = 0; i < dfsplen; i++) {
				if (full_path[i] == '\\')
					full_path[i] = '/';
			}
		}
	}
	return full_path;
}
Exemple #5
0
static int initiate_cifs_search(const int xid, struct file *file)
{
	int rc = 0;
	char *full_path = NULL;
	struct cifsFileInfo *cifsFile;
	struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
	struct tcon_link *tlink = NULL;
	struct cifs_tcon *pTcon;

	if (file->private_data == NULL) {
		tlink = cifs_sb_tlink(cifs_sb);
		if (IS_ERR(tlink))
			return PTR_ERR(tlink);

		cifsFile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
		if (cifsFile == NULL) {
			rc = -ENOMEM;
			goto error_exit;
		}
		file->private_data = cifsFile;
		cifsFile->tlink = cifs_get_tlink(tlink);
		pTcon = tlink_tcon(tlink);
	} else {
		cifsFile = file->private_data;
		pTcon = tlink_tcon(cifsFile->tlink);
	}

	cifsFile->invalidHandle = true;
	cifsFile->srch_inf.endOfSearch = false;

	full_path = build_path_from_dentry(file->f_path.dentry);
	if (full_path == NULL) {
		rc = -ENOMEM;
		goto error_exit;
	}

	cFYI(1, "Full path: %s start at: %lld", full_path, file->f_pos);

ffirst_retry:
	/* test for Unix extensions */
	/* but now check for them on the share/mount not on the SMB session */
/*	if (pTcon->ses->capabilities & CAP_UNIX) { */
	if (pTcon->unix_ext)
		cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX;
	else if ((pTcon->ses->capabilities &
			(CAP_NT_SMBS | CAP_NT_FIND)) == 0) {
		cifsFile->srch_inf.info_level = SMB_FIND_FILE_INFO_STANDARD;
	} else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
		cifsFile->srch_inf.info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO;
	} else /* not srvinos - BB fixme add check for backlevel? */ {
		cifsFile->srch_inf.info_level = SMB_FIND_FILE_DIRECTORY_INFO;
	}

	rc = CIFSFindFirst(xid, pTcon, full_path, cifs_sb->local_nls,
		&cifsFile->netfid, &cifsFile->srch_inf,
		cifs_sb->mnt_cifs_flags &
			CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb));
	if (rc == 0)
		cifsFile->invalidHandle = false;
	/* BB add following call to handle readdir on new NTFS symlink errors
	else if STATUS_STOPPED_ON_SYMLINK
		call get_symlink_reparse_path and retry with new path */
	else if ((rc == -EOPNOTSUPP) &&
		(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) {
		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM;
		goto ffirst_retry;
	}
error_exit:
	kfree(full_path);
	cifs_put_tlink(tlink);
	return rc;
}
Exemple #6
0
static int initiate_cifs_search(const int xid, struct file *file)
{
	int rc = 0;
	char *full_path;
	struct cifsFileInfo *cifsFile;
	struct cifs_sb_info *cifs_sb;
	struct cifsTconInfo *pTcon;

	if (file->private_data == NULL) {
		file->private_data =
			kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
	}

	if (file->private_data == NULL)
		return -ENOMEM;
	cifsFile = file->private_data;
	cifsFile->invalidHandle = true;
	cifsFile->srch_inf.endOfSearch = false;

	cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
	if (cifs_sb == NULL)
		return -EINVAL;

	pTcon = cifs_sb->tcon;
	if (pTcon == NULL)
		return -EINVAL;

	full_path = build_path_from_dentry(file->f_path.dentry);

	if (full_path == NULL)
		return -ENOMEM;

	cFYI(1, ("Full path: %s start at: %lld", full_path, file->f_pos));

ffirst_retry:
	/* test for Unix extensions */
	/* but now check for them on the share/mount not on the SMB session */
/*	if (pTcon->ses->capabilities & CAP_UNIX) { */
	if (pTcon->unix_ext)
		cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX;
	else if ((pTcon->ses->capabilities &
			(CAP_NT_SMBS | CAP_NT_FIND)) == 0) {
		cifsFile->srch_inf.info_level = SMB_FIND_FILE_INFO_STANDARD;
	} else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
		cifsFile->srch_inf.info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO;
	} else /* not srvinos - BB fixme add check for backlevel? */ {
		cifsFile->srch_inf.info_level = SMB_FIND_FILE_DIRECTORY_INFO;
	}

	rc = CIFSFindFirst(xid, pTcon, full_path, cifs_sb->local_nls,
		&cifsFile->netfid, &cifsFile->srch_inf,
		cifs_sb->mnt_cifs_flags &
			CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb));
	if (rc == 0)
		cifsFile->invalidHandle = false;
	if ((rc == -EOPNOTSUPP) &&
		(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) {
		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM;
		goto ffirst_retry;
	}
	kfree(full_path);
	return rc;
}