diff options
author | Stefan Metzmacher <metze@samba.org> | 2010-07-31 03:15:10 -0400 |
---|---|---|
committer | Steve French <sfrench@us.ibm.com> | 2010-09-29 15:04:30 -0400 |
commit | 8bfb50a882ccd9804929876470f74edcb23d2326 (patch) | |
tree | ad4aa06e04fd2146edc4492aa8fbd3e87258356a | |
parent | c69c1b6eaea1b3e1eecf7ad2fba0208ac4a11131 (diff) |
cifs: implement CIFSCouldBeMFSymlink() and CIFSCheckMFSymlink()
Signed-off-by: Stefan Metzmacher <metze@samba.org>
Signed-off-by: Steve French <sfrench@us.ibm.com>
-rw-r--r-- | fs/cifs/cifsproto.h | 4 | ||||
-rw-r--r-- | fs/cifs/link.c | 79 |
2 files changed, 83 insertions, 0 deletions
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 588612867451..8604a45c1107 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
@@ -409,4 +409,8 @@ extern int CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon, | |||
409 | extern int CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon, | 409 | extern int CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon, |
410 | const int netfid, __u64 *pExtAttrBits, __u64 *pMask); | 410 | const int netfid, __u64 *pExtAttrBits, __u64 *pMask); |
411 | extern void cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb); | 411 | extern void cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb); |
412 | extern bool CIFSCouldBeMFSymlink(const struct cifs_fattr *fattr); | ||
413 | extern int CIFSCheckMFSymlink(struct cifs_fattr *fattr, | ||
414 | const unsigned char *path, | ||
415 | struct cifs_sb_info *cifs_sb, int xid); | ||
412 | #endif /* _CIFSPROTO_H */ | 416 | #endif /* _CIFSPROTO_H */ |
diff --git a/fs/cifs/link.c b/fs/cifs/link.c index 12eb491d4c52..bec212b09a02 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c | |||
@@ -91,6 +91,85 @@ CIFSParseMFSymlink(const u8 *buf, | |||
91 | return 0; | 91 | return 0; |
92 | } | 92 | } |
93 | 93 | ||
94 | bool | ||
95 | CIFSCouldBeMFSymlink(const struct cifs_fattr *fattr) | ||
96 | { | ||
97 | if (!(fattr->cf_mode & S_IFREG)) | ||
98 | /* it's not a symlink */ | ||
99 | return false; | ||
100 | |||
101 | if (fattr->cf_eof != CIFS_MF_SYMLINK_FILE_SIZE) | ||
102 | /* it's not a symlink */ | ||
103 | return false; | ||
104 | |||
105 | return true; | ||
106 | } | ||
107 | |||
108 | int | ||
109 | CIFSCheckMFSymlink(struct cifs_fattr *fattr, | ||
110 | const unsigned char *path, | ||
111 | struct cifs_sb_info *cifs_sb, int xid) | ||
112 | { | ||
113 | int rc; | ||
114 | int oplock = 0; | ||
115 | __u16 netfid = 0; | ||
116 | struct cifsTconInfo *pTcon = cifs_sb->tcon; | ||
117 | u8 *buf; | ||
118 | char *pbuf; | ||
119 | unsigned int bytes_read = 0; | ||
120 | int buf_type = CIFS_NO_BUFFER; | ||
121 | unsigned int link_len = 0; | ||
122 | FILE_ALL_INFO file_info; | ||
123 | |||
124 | if (!CIFSCouldBeMFSymlink(fattr)) | ||
125 | /* it's not a symlink */ | ||
126 | return 0; | ||
127 | |||
128 | rc = CIFSSMBOpen(xid, pTcon, path, FILE_OPEN, GENERIC_READ, | ||
129 | CREATE_NOT_DIR, &netfid, &oplock, &file_info, | ||
130 | cifs_sb->local_nls, | ||
131 | cifs_sb->mnt_cifs_flags & | ||
132 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
133 | if (rc != 0) | ||
134 | return rc; | ||
135 | |||
136 | if (file_info.EndOfFile != CIFS_MF_SYMLINK_FILE_SIZE) { | ||
137 | CIFSSMBClose(xid, pTcon, netfid); | ||
138 | /* it's not a symlink */ | ||
139 | return 0; | ||
140 | } | ||
141 | |||
142 | buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL); | ||
143 | if (!buf) | ||
144 | return -ENOMEM; | ||
145 | pbuf = buf; | ||
146 | |||
147 | rc = CIFSSMBRead(xid, pTcon, netfid, | ||
148 | CIFS_MF_SYMLINK_FILE_SIZE /* length */, | ||
149 | 0 /* offset */, | ||
150 | &bytes_read, &pbuf, &buf_type); | ||
151 | CIFSSMBClose(xid, pTcon, netfid); | ||
152 | if (rc != 0) { | ||
153 | kfree(buf); | ||
154 | return rc; | ||
155 | } | ||
156 | |||
157 | rc = CIFSParseMFSymlink(buf, bytes_read, &link_len, NULL); | ||
158 | kfree(buf); | ||
159 | if (rc == -EINVAL) | ||
160 | /* it's not a symlink */ | ||
161 | return 0; | ||
162 | if (rc != 0) | ||
163 | return rc; | ||
164 | |||
165 | /* it is a symlink */ | ||
166 | fattr->cf_eof = link_len; | ||
167 | fattr->cf_mode &= ~S_IFMT; | ||
168 | fattr->cf_mode |= S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO; | ||
169 | fattr->cf_dtype = DT_LNK; | ||
170 | return 0; | ||
171 | } | ||
172 | |||
94 | int | 173 | int |
95 | cifs_hardlink(struct dentry *old_file, struct inode *inode, | 174 | cifs_hardlink(struct dentry *old_file, struct inode *inode, |
96 | struct dentry *direntry) | 175 | struct dentry *direntry) |