/*
* fs/cifs/inode.c
*
- * Copyright (C) International Business Machines Corp., 2002,2007
+ * Copyright (C) International Business Machines Corp., 2002,2008
* Author(s): Steve French (sfrench@us.ibm.com)
*
* This library is free software; you can redistribute it and/or modify
.lookup = cifs_lookup,
};
+static char *build_path_to_root(struct cifs_sb_info *cifs_sb)
+{
+ int pplen = cifs_sb->prepathlen;
+ int dfsplen;
+ char *full_path = NULL;
+
+ /* if no prefix path, simply set path to the root of share to "" */
+ if (pplen == 0) {
+ full_path = kmalloc(1, GFP_KERNEL);
+ if (full_path)
+ full_path[0] = 0;
+ return full_path;
+ }
+
+ if (cifs_sb->tcon && (cifs_sb->tcon->Flags & SMB_SHARE_IS_IN_DFS))
+ dfsplen = strnlen(cifs_sb->tcon->treeName, MAX_TREE_SIZE + 1);
+ else
+ dfsplen = 0;
+
+ full_path = kmalloc(dfsplen + pplen + 1, GFP_KERNEL);
+ if (full_path == NULL)
+ return full_path;
+
+ if (dfsplen) {
+ strncpy(full_path, cifs_sb->tcon->treeName, dfsplen);
+ /* switch slash direction in prepath depending on whether
+ * windows or posix style path names
+ */
+ 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] = '/';
+ }
+ }
+ }
+ strncpy(full_path + dfsplen, cifs_sb->prepath, pplen);
+ full_path[dfsplen + pplen] = 0; /* add trailing null */
+ return full_path;
+}
+
/* gets root inode */
struct inode *cifs_iget(struct super_block *sb, unsigned long ino)
{
struct cifs_sb_info *cifs_sb;
struct inode *inode;
long rc;
+ char *full_path;
inode = iget_locked(sb, ino);
if (!inode)
return inode;
cifs_sb = CIFS_SB(inode->i_sb);
- xid = GetXid();
+ full_path = build_path_to_root(cifs_sb);
+ if (full_path == NULL)
+ return ERR_PTR(-ENOMEM);
+ xid = GetXid();
if (cifs_sb->tcon->unix_ext)
- rc = cifs_get_inode_info_unix(&inode, "", inode->i_sb, xid);
+ rc = cifs_get_inode_info_unix(&inode, full_path, inode->i_sb,
+ xid);
else
- rc = cifs_get_inode_info(&inode, "", NULL, inode->i_sb, xid,
- NULL);
+ rc = cifs_get_inode_info(&inode, full_path, NULL, inode->i_sb,
+ xid, NULL);
if (rc && cifs_sb->tcon->ipc) {
cFYI(1, ("ipc connection - fake read inode"));
inode->i_mode |= S_IFDIR;
inode->i_uid = cifs_sb->mnt_uid;
inode->i_gid = cifs_sb->mnt_gid;
} else if (rc) {
+ kfree(full_path);
_FreeXid(xid);
iget_failed(inode);
return ERR_PTR(rc);
unlock_new_inode(inode);
+ kfree(full_path);
/* can not call macro FreeXid here since in a void func
* TODO: This is no longer true
*/
struct cifs_sb_info *cifs_sb_source;
struct cifs_sb_info *cifs_sb_target;
struct cifsTconInfo *tcon;
- struct cifsInodeInfo *target_cinode;
FILE_UNIX_BASIC_INFO *info_buf_source = NULL;
FILE_UNIX_BASIC_INFO *info_buf_target;
- __u16 dstfid;
- int xid, rc, tmprc, oplock = 0;
- bool delete_already_pending;
+ int xid, rc, tmprc;
cifs_sb_target = CIFS_SB(target_dir->i_sb);
cifs_sb_source = CIFS_SB(source_dir->i_sb);
}
info_buf_target = info_buf_source + 1;
- rc = CIFSSMBUnixQPathInfo(xid, tcon, fromName,
+ tmprc = CIFSSMBUnixQPathInfo(xid, tcon, fromName,
info_buf_source,
cifs_sb_source->local_nls,
cifs_sb_source->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
- if (rc != 0)
+ if (tmprc != 0)
goto unlink_target;
- rc = CIFSSMBUnixQPathInfo(xid, tcon,
+ tmprc = CIFSSMBUnixQPathInfo(xid, tcon,
toName, info_buf_target,
cifs_sb_target->local_nls,
/* remap based on source sb */
cifs_sb_source->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
- if (rc == 0 && (info_buf_source->UniqueId ==
- info_buf_target->UniqueId))
+ if (tmprc == 0 && (info_buf_source->UniqueId ==
+ info_buf_target->UniqueId)) {
/* same file, POSIX says that this is a noop */
+ rc = 0;
goto cifs_rename_exit;
-
- rc = -EEXIST;
+ }
} /* else ... BB we could add the same check for Windows by
checking the UniqueId via FILE_INTERNAL_INFO */
- if ((rc == -EACCES) || (rc == -EEXIST)) {
unlink_target:
- /* don't bother if this is a negative dentry */
- if (!target_dentry->d_inode)
- goto cifs_rename_exit;
-
- target_cinode = CIFS_I(target_dentry->d_inode);
-
- /* try to move the target out of the way */
- tmprc = CIFSSMBOpen(xid, tcon, toName, FILE_OPEN, DELETE,
- CREATE_NOT_DIR, &dstfid, &oplock, NULL,
- cifs_sb_target->local_nls,
- cifs_sb_target->mnt_cifs_flags &
- CIFS_MOUNT_MAP_SPECIAL_CHR);
+ if ((rc == -EACCES) || (rc == -EEXIST)) {
+ tmprc = cifs_unlink(target_dir, target_dentry);
if (tmprc)
goto cifs_rename_exit;
- /* rename the file to random name */
- tmprc = CIFSSMBRenameOpenFile(xid, tcon, dstfid, NULL,
- cifs_sb_target->local_nls,
- cifs_sb_target->mnt_cifs_flags &
- CIFS_MOUNT_MAP_SPECIAL_CHR);
-
- if (tmprc)
- goto close_target;
-
- delete_already_pending = target_cinode->delete_pending;
-
- if (!delete_already_pending) {
- /* set delete on close */
- tmprc = CIFSSMBSetFileDisposition(xid, tcon,
- true, dstfid,
- current->tgid);
- /*
- * This hack is for broken samba servers, remove this
- * once more fixed ones are in the field.
- */
- if (tmprc == -ENOENT)
- delete_already_pending = false;
- else if (tmprc)
- goto undo_target_rename;
-
- target_cinode->delete_pending = true;
- }
-
-
rc = cifs_do_rename(xid, source_dentry, fromName,
target_dentry, toName);
-
- if (rc == 0)
- goto close_target;
-
- /*
- * after this point, we can't bother with error handling on
- * the undo's. This is best effort since we can't do anything
- * about failures here.
- */
- if (!delete_already_pending) {
- tmprc = CIFSSMBSetFileDisposition(xid, tcon,
- false, dstfid,
- current->tgid);
- if (tmprc == 0)
- target_cinode->delete_pending = false;
- }
-
-undo_target_rename:
- /* rename failed: undo target rename */
- CIFSSMBRenameOpenFile(xid, tcon, dstfid,
- target_dentry->d_name.name,
- cifs_sb_target->local_nls,
- cifs_sb_target->mnt_cifs_flags &
- CIFS_MOUNT_MAP_SPECIAL_CHR);
-close_target:
- CIFSSMBClose(xid, tcon, dstfid);
}
cifs_rename_exit: