linux/fs/cifs/link.c
<<
>>
Prefs
   1/*
   2 *   fs/cifs/link.c
   3 *
   4 *   Copyright (C) International Business Machines  Corp., 2002,2008
   5 *   Author(s): Steve French (sfrench@us.ibm.com)
   6 *
   7 *   This library is free software; you can redistribute it and/or modify
   8 *   it under the terms of the GNU Lesser General Public License as published
   9 *   by the Free Software Foundation; either version 2.1 of the License, or
  10 *   (at your option) any later version.
  11 *
  12 *   This library is distributed in the hope that it will be useful,
  13 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
  15 *   the GNU Lesser General Public License for more details.
  16 *
  17 *   You should have received a copy of the GNU Lesser General Public License
  18 *   along with this library; if not, write to the Free Software
  19 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  20 */
  21#include <linux/fs.h>
  22#include <linux/stat.h>
  23#include <linux/slab.h>
  24#include <linux/namei.h>
  25#include "cifsfs.h"
  26#include "cifspdu.h"
  27#include "cifsglob.h"
  28#include "cifsproto.h"
  29#include "cifs_debug.h"
  30#include "cifs_fs_sb.h"
  31
  32int
  33cifs_hardlink(struct dentry *old_file, struct inode *inode,
  34              struct dentry *direntry)
  35{
  36        int rc = -EACCES;
  37        int xid;
  38        char *fromName = NULL;
  39        char *toName = NULL;
  40        struct cifs_sb_info *cifs_sb_target;
  41        struct cifsTconInfo *pTcon;
  42        struct cifsInodeInfo *cifsInode;
  43
  44        xid = GetXid();
  45
  46        cifs_sb_target = CIFS_SB(inode->i_sb);
  47        pTcon = cifs_sb_target->tcon;
  48
  49/* No need to check for cross device links since server will do that
  50   BB note DFS case in future though (when we may have to check) */
  51
  52        fromName = build_path_from_dentry(old_file);
  53        toName = build_path_from_dentry(direntry);
  54        if ((fromName == NULL) || (toName == NULL)) {
  55                rc = -ENOMEM;
  56                goto cifs_hl_exit;
  57        }
  58
  59/*      if (cifs_sb_target->tcon->ses->capabilities & CAP_UNIX)*/
  60        if (pTcon->unix_ext)
  61                rc = CIFSUnixCreateHardLink(xid, pTcon, fromName, toName,
  62                                            cifs_sb_target->local_nls,
  63                                            cifs_sb_target->mnt_cifs_flags &
  64                                                CIFS_MOUNT_MAP_SPECIAL_CHR);
  65        else {
  66                rc = CIFSCreateHardLink(xid, pTcon, fromName, toName,
  67                                        cifs_sb_target->local_nls,
  68                                        cifs_sb_target->mnt_cifs_flags &
  69                                                CIFS_MOUNT_MAP_SPECIAL_CHR);
  70                if ((rc == -EIO) || (rc == -EINVAL))
  71                        rc = -EOPNOTSUPP;
  72        }
  73
  74        d_drop(direntry);       /* force new lookup from server of target */
  75
  76        /* if source file is cached (oplocked) revalidate will not go to server
  77           until the file is closed or oplock broken so update nlinks locally */
  78        if (old_file->d_inode) {
  79                cifsInode = CIFS_I(old_file->d_inode);
  80                if (rc == 0) {
  81                        old_file->d_inode->i_nlink++;
  82/* BB should we make this contingent on superblock flag NOATIME? */
  83/*                      old_file->d_inode->i_ctime = CURRENT_TIME;*/
  84                        /* parent dir timestamps will update from srv
  85                        within a second, would it really be worth it
  86                        to set the parent dir cifs inode time to zero
  87                        to force revalidate (faster) for it too? */
  88                }
  89                /* if not oplocked will force revalidate to get info
  90                   on source file from srv */
  91                cifsInode->time = 0;
  92
  93                /* Will update parent dir timestamps from srv within a second.
  94                   Would it really be worth it to set the parent dir (cifs
  95                   inode) time field to zero to force revalidate on parent
  96                   directory faster ie
  97                        CIFS_I(inode)->time = 0;  */
  98        }
  99
 100cifs_hl_exit:
 101        kfree(fromName);
 102        kfree(toName);
 103        FreeXid(xid);
 104        return rc;
 105}
 106
 107void *
 108cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
 109{
 110        struct inode *inode = direntry->d_inode;
 111        int rc = -ENOMEM;
 112        int xid;
 113        char *full_path = NULL;
 114        char *target_path = NULL;
 115        struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
 116        struct cifsTconInfo *tcon = cifs_sb->tcon;
 117
 118        xid = GetXid();
 119
 120        /*
 121         * For now, we just handle symlinks with unix extensions enabled.
 122         * Eventually we should handle NTFS reparse points, and MacOS
 123         * symlink support. For instance...
 124         *
 125         * rc = CIFSSMBQueryReparseLinkInfo(...)
 126         *
 127         * For now, just return -EACCES when the server doesn't support posix
 128         * extensions. Note that we still allow querying symlinks when posix
 129         * extensions are manually disabled. We could disable these as well
 130         * but there doesn't seem to be any harm in allowing the client to
 131         * read them.
 132         */
 133        if (!(tcon->ses->capabilities & CAP_UNIX)) {
 134                rc = -EACCES;
 135                goto out;
 136        }
 137
 138        full_path = build_path_from_dentry(direntry);
 139        if (!full_path)
 140                goto out;
 141
 142        cFYI(1, "Full path: %s inode = 0x%p", full_path, inode);
 143
 144        rc = CIFSSMBUnixQuerySymLink(xid, tcon, full_path, &target_path,
 145                                     cifs_sb->local_nls);
 146        kfree(full_path);
 147out:
 148        if (rc != 0) {
 149                kfree(target_path);
 150                target_path = ERR_PTR(rc);
 151        }
 152
 153        FreeXid(xid);
 154        nd_set_link(nd, target_path);
 155        return NULL;
 156}
 157
 158int
 159cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
 160{
 161        int rc = -EOPNOTSUPP;
 162        int xid;
 163        struct cifs_sb_info *cifs_sb;
 164        struct cifsTconInfo *pTcon;
 165        char *full_path = NULL;
 166        struct inode *newinode = NULL;
 167
 168        xid = GetXid();
 169
 170        cifs_sb = CIFS_SB(inode->i_sb);
 171        pTcon = cifs_sb->tcon;
 172
 173        full_path = build_path_from_dentry(direntry);
 174
 175        if (full_path == NULL) {
 176                rc = -ENOMEM;
 177                FreeXid(xid);
 178                return rc;
 179        }
 180
 181        cFYI(1, "Full path: %s", full_path);
 182        cFYI(1, "symname is %s", symname);
 183
 184        /* BB what if DFS and this volume is on different share? BB */
 185        if (pTcon->unix_ext)
 186                rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname,
 187                                           cifs_sb->local_nls);
 188        /* else
 189           rc = CIFSCreateReparseSymLink(xid, pTcon, fromName, toName,
 190                                        cifs_sb_target->local_nls); */
 191
 192        if (rc == 0) {
 193                if (pTcon->unix_ext)
 194                        rc = cifs_get_inode_info_unix(&newinode, full_path,
 195                                                      inode->i_sb, xid);
 196                else
 197                        rc = cifs_get_inode_info(&newinode, full_path, NULL,
 198                                                 inode->i_sb, xid, NULL);
 199
 200                if (rc != 0) {
 201                        cFYI(1, "Create symlink ok, getinodeinfo fail rc = %d",
 202                              rc);
 203                } else {
 204                        if (pTcon->nocase)
 205                                direntry->d_op = &cifs_ci_dentry_ops;
 206                        else
 207                                direntry->d_op = &cifs_dentry_ops;
 208                        d_instantiate(direntry, newinode);
 209                }
 210        }
 211
 212        kfree(full_path);
 213        FreeXid(xid);
 214        return rc;
 215}
 216
 217void cifs_put_link(struct dentry *direntry, struct nameidata *nd, void *cookie)
 218{
 219        char *p = nd_get_link(nd);
 220        if (!IS_ERR(p))
 221                kfree(p);
 222}
 223
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.