static int CIFSQueryMFSymLink(const int xid, struct cifs_tcon *tcon, const unsigned char *searchName, char **symlinkinfo, const struct nls_table *nls_codepage, int remap) { int rc; int oplock = 0; __u16 netfid = 0; u8 *buf; char *pbuf; unsigned int bytes_read = 0; int buf_type = CIFS_NO_BUFFER; unsigned int link_len = 0; struct cifs_io_parms io_parms; FILE_ALL_INFO file_info; rc = CIFSSMBOpen(xid, tcon, searchName, FILE_OPEN, GENERIC_READ, CREATE_NOT_DIR, &netfid, &oplock, &file_info, nls_codepage, remap); if (rc != 0) return rc; if (file_info.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) { CIFSSMBClose(xid, tcon, netfid); /* it's not a symlink */ return -EINVAL; } buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL); if (!buf) return -ENOMEM; pbuf = buf; io_parms.netfid = netfid; io_parms.pid = current->tgid; io_parms.tcon = tcon; io_parms.offset = 0; io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE; rc = CIFSSMBRead(xid, &io_parms, &bytes_read, &pbuf, &buf_type); CIFSSMBClose(xid, tcon, netfid); if (rc != 0) { kfree(buf); return rc; } rc = CIFSParseMFSymlink(buf, bytes_read, &link_len, symlinkinfo); kfree(buf); if (rc != 0) return rc; return 0; }
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; }