cifs: implement CIFSCouldBeMFSymlink() and CIFSCheckMFSymlink()
authorStefan Metzmacher <metze@samba.org>
Sat, 31 Jul 2010 07:15:10 +0000 (09:15 +0200)
committerSteve French <sfrench@us.ibm.com>
Wed, 29 Sep 2010 19:04:30 +0000 (19:04 +0000)
Signed-off-by: Stefan Metzmacher <metze@samba.org>
Signed-off-by: Steve French <sfrench@us.ibm.com>
fs/cifs/cifsproto.h
fs/cifs/link.c

index 588612867451c70e33c5b5885db7fa156c93d3c1..8604a45c1107c7394f010bb883b75b3f4f561612 100644 (file)
@@ -409,4 +409,8 @@ extern int CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
 extern int CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
                        const int netfid, __u64 *pExtAttrBits, __u64 *pMask);
 extern void cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb);
+extern bool CIFSCouldBeMFSymlink(const struct cifs_fattr *fattr);
+extern int CIFSCheckMFSymlink(struct cifs_fattr *fattr,
+               const unsigned char *path,
+               struct cifs_sb_info *cifs_sb, int xid);
 #endif                 /* _CIFSPROTO_H */
index 12eb491d4c523fcc0c4eb71293b6a86e5a6b3255..bec212b09a02ff36a79b7b4e186412a8d2bb5d2e 100644 (file)
@@ -91,6 +91,85 @@ CIFSParseMFSymlink(const u8 *buf,
        return 0;
 }
 
+bool
+CIFSCouldBeMFSymlink(const struct cifs_fattr *fattr)
+{
+       if (!(fattr->cf_mode & S_IFREG))
+               /* it's not a symlink */
+               return false;
+
+       if (fattr->cf_eof != CIFS_MF_SYMLINK_FILE_SIZE)
+               /* it's not a symlink */
+               return false;
+
+       return true;
+}
+
+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 cifsTconInfo *pTcon = cifs_sb->tcon;
+       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;
+
+       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)
+               return rc;
+
+       if (file_info.EndOfFile != CIFS_MF_SYMLINK_FILE_SIZE) {
+               CIFSSMBClose(xid, pTcon, netfid);
+               /* it's not a symlink */
+               return 0;
+       }
+
+       buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+       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);
+               return rc;
+       }
+
+       rc = CIFSParseMFSymlink(buf, bytes_read, &link_len, NULL);
+       kfree(buf);
+       if (rc == -EINVAL)
+               /* it's not a symlink */
+               return 0;
+       if (rc != 0)
+               return rc;
+
+       /* 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;
+       return 0;
+}
+
 int
 cifs_hardlink(struct dentry *old_file, struct inode *inode,
              struct dentry *direntry)