~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/smb/client/smb2inode.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: LGPL-2.1
  2 /*
  3  *
  4  *   Copyright (C) International Business Machines  Corp., 2002, 2011
  5  *                 Etersoft, 2012
  6  *   Author(s): Pavel Shilovsky (pshilovsky@samba.org),
  7  *              Steve French (sfrench@us.ibm.com)
  8  *
  9  */
 10 #include <linux/fs.h>
 11 #include <linux/stat.h>
 12 #include <linux/slab.h>
 13 #include <linux/pagemap.h>
 14 #include <asm/div64.h>
 15 #include "cifsfs.h"
 16 #include "cifspdu.h"
 17 #include "cifsglob.h"
 18 #include "cifsproto.h"
 19 #include "cifs_debug.h"
 20 #include "cifs_fs_sb.h"
 21 #include "cifs_unicode.h"
 22 #include "fscache.h"
 23 #include "smb2glob.h"
 24 #include "smb2pdu.h"
 25 #include "smb2proto.h"
 26 #include "cached_dir.h"
 27 #include "smb2status.h"
 28 
 29 static struct reparse_data_buffer *reparse_buf_ptr(struct kvec *iov)
 30 {
 31         struct reparse_data_buffer *buf;
 32         struct smb2_ioctl_rsp *io = iov->iov_base;
 33         u32 off, count, len;
 34 
 35         count = le32_to_cpu(io->OutputCount);
 36         off = le32_to_cpu(io->OutputOffset);
 37         if (check_add_overflow(off, count, &len) || len > iov->iov_len)
 38                 return ERR_PTR(-EIO);
 39 
 40         buf = (struct reparse_data_buffer *)((u8 *)io + off);
 41         len = sizeof(*buf);
 42         if (count < len || count < le16_to_cpu(buf->ReparseDataLength) + len)
 43                 return ERR_PTR(-EIO);
 44         return buf;
 45 }
 46 
 47 static inline __u32 file_create_options(struct dentry *dentry)
 48 {
 49         struct cifsInodeInfo *ci;
 50 
 51         if (dentry) {
 52                 ci = CIFS_I(d_inode(dentry));
 53                 if (ci->cifsAttrs & ATTR_REPARSE)
 54                         return OPEN_REPARSE_POINT;
 55         }
 56         return 0;
 57 }
 58 
 59 /* Parse owner and group from SMB3.1.1 POSIX query info */
 60 static int parse_posix_sids(struct cifs_open_info_data *data,
 61                             struct kvec *rsp_iov)
 62 {
 63         struct smb2_query_info_rsp *qi = rsp_iov->iov_base;
 64         unsigned int out_len = le32_to_cpu(qi->OutputBufferLength);
 65         unsigned int qi_len = sizeof(data->posix_fi);
 66         int owner_len, group_len;
 67         u8 *sidsbuf, *sidsbuf_end;
 68 
 69         if (out_len <= qi_len)
 70                 return -EINVAL;
 71 
 72         sidsbuf = (u8 *)qi + le16_to_cpu(qi->OutputBufferOffset) + qi_len;
 73         sidsbuf_end = sidsbuf + out_len - qi_len;
 74 
 75         owner_len = posix_info_sid_size(sidsbuf, sidsbuf_end);
 76         if (owner_len == -1)
 77                 return -EINVAL;
 78 
 79         memcpy(&data->posix_owner, sidsbuf, owner_len);
 80         group_len = posix_info_sid_size(sidsbuf + owner_len, sidsbuf_end);
 81         if (group_len == -1)
 82                 return -EINVAL;
 83 
 84         memcpy(&data->posix_group, sidsbuf + owner_len, group_len);
 85         return 0;
 86 }
 87 
 88 struct wsl_query_ea {
 89         __le32  next;
 90         __u8    name_len;
 91         __u8    name[SMB2_WSL_XATTR_NAME_LEN + 1];
 92 } __packed;
 93 
 94 #define NEXT_OFF cpu_to_le32(sizeof(struct wsl_query_ea))
 95 
 96 static const struct wsl_query_ea wsl_query_eas[] = {
 97         { .next = NEXT_OFF, .name_len = SMB2_WSL_XATTR_NAME_LEN, .name = SMB2_WSL_XATTR_UID, },
 98         { .next = NEXT_OFF, .name_len = SMB2_WSL_XATTR_NAME_LEN, .name = SMB2_WSL_XATTR_GID, },
 99         { .next = NEXT_OFF, .name_len = SMB2_WSL_XATTR_NAME_LEN, .name = SMB2_WSL_XATTR_MODE, },
100         { .next = 0,        .name_len = SMB2_WSL_XATTR_NAME_LEN, .name = SMB2_WSL_XATTR_DEV, },
101 };
102 
103 static int check_wsl_eas(struct kvec *rsp_iov)
104 {
105         struct smb2_file_full_ea_info *ea;
106         struct smb2_query_info_rsp *rsp = rsp_iov->iov_base;
107         unsigned long addr;
108         u32 outlen, next;
109         u16 vlen;
110         u8 nlen;
111         u8 *end;
112 
113         outlen = le32_to_cpu(rsp->OutputBufferLength);
114         if (outlen < SMB2_WSL_MIN_QUERY_EA_RESP_SIZE ||
115             outlen > SMB2_WSL_MAX_QUERY_EA_RESP_SIZE)
116                 return -EINVAL;
117 
118         ea = (void *)((u8 *)rsp_iov->iov_base +
119                       le16_to_cpu(rsp->OutputBufferOffset));
120         end = (u8 *)rsp_iov->iov_base + rsp_iov->iov_len;
121         for (;;) {
122                 if ((u8 *)ea > end - sizeof(*ea))
123                         return -EINVAL;
124 
125                 nlen = ea->ea_name_length;
126                 vlen = le16_to_cpu(ea->ea_value_length);
127                 if (nlen != SMB2_WSL_XATTR_NAME_LEN ||
128                     (u8 *)ea + nlen + 1 + vlen > end)
129                         return -EINVAL;
130 
131                 switch (vlen) {
132                 case 4:
133                         if (strncmp(ea->ea_data, SMB2_WSL_XATTR_UID, nlen) &&
134                             strncmp(ea->ea_data, SMB2_WSL_XATTR_GID, nlen) &&
135                             strncmp(ea->ea_data, SMB2_WSL_XATTR_MODE, nlen))
136                                 return -EINVAL;
137                         break;
138                 case 8:
139                         if (strncmp(ea->ea_data, SMB2_WSL_XATTR_DEV, nlen))
140                                 return -EINVAL;
141                         break;
142                 case 0:
143                         if (!strncmp(ea->ea_data, SMB2_WSL_XATTR_UID, nlen) ||
144                             !strncmp(ea->ea_data, SMB2_WSL_XATTR_GID, nlen) ||
145                             !strncmp(ea->ea_data, SMB2_WSL_XATTR_MODE, nlen) ||
146                             !strncmp(ea->ea_data, SMB2_WSL_XATTR_DEV, nlen))
147                                 break;
148                         fallthrough;
149                 default:
150                         return -EINVAL;
151                 }
152 
153                 next = le32_to_cpu(ea->next_entry_offset);
154                 if (!next)
155                         break;
156                 if (!IS_ALIGNED(next, 4) ||
157                     check_add_overflow((unsigned long)ea, next, &addr))
158                         return -EINVAL;
159                 ea = (void *)addr;
160         }
161         return 0;
162 }
163 
164 /*
165  * note: If cfile is passed, the reference to it is dropped here.
166  * So make sure that you do not reuse cfile after return from this func.
167  *
168  * If passing @out_iov and @out_buftype, ensure to make them both large enough
169  * (>= 3) to hold all compounded responses.  Caller is also responsible for
170  * freeing them up with free_rsp_buf().
171  */
172 static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
173                             struct cifs_sb_info *cifs_sb, const char *full_path,
174                             struct cifs_open_parms *oparms, struct kvec *in_iov,
175                             int *cmds, int num_cmds, struct cifsFileInfo *cfile,
176                             struct kvec *out_iov, int *out_buftype, struct dentry *dentry)
177 {
178 
179         struct reparse_data_buffer *rbuf;
180         struct smb2_compound_vars *vars = NULL;
181         struct kvec *rsp_iov, *iov;
182         struct smb_rqst *rqst;
183         int rc;
184         __le16 *utf16_path = NULL;
185         __u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
186         struct cifs_fid fid;
187         struct cifs_ses *ses = tcon->ses;
188         struct TCP_Server_Info *server;
189         int num_rqst = 0, i;
190         int resp_buftype[MAX_COMPOUND];
191         struct smb2_query_info_rsp *qi_rsp = NULL;
192         struct cifs_open_info_data *idata;
193         struct inode *inode = NULL;
194         int flags = 0;
195         __u8 delete_pending[8] = {1, 0, 0, 0, 0, 0, 0, 0};
196         unsigned int size[2];
197         void *data[2];
198         unsigned int len;
199         int retries = 0, cur_sleep = 1;
200 
201 replay_again:
202         /* reinitialize for possible replay */
203         flags = 0;
204         oplock = SMB2_OPLOCK_LEVEL_NONE;
205         num_rqst = 0;
206         server = cifs_pick_channel(ses);
207 
208         vars = kzalloc(sizeof(*vars), GFP_ATOMIC);
209         if (vars == NULL)
210                 return -ENOMEM;
211         rqst = &vars->rqst[0];
212         rsp_iov = &vars->rsp_iov[0];
213 
214         if (smb3_encryption_required(tcon))
215                 flags |= CIFS_TRANSFORM_REQ;
216 
217         for (i = 0; i < ARRAY_SIZE(resp_buftype); i++)
218                 resp_buftype[i] = CIFS_NO_BUFFER;
219 
220         /* We already have a handle so we can skip the open */
221         if (cfile)
222                 goto after_open;
223 
224         /* Open */
225         utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
226         if (!utf16_path) {
227                 rc = -ENOMEM;
228                 goto finished;
229         }
230 
231         /* if there is an existing lease, reuse it */
232 
233         /*
234          * note: files with hardlinks cause unexpected behaviour. As per MS-SMB2,
235          * lease keys are associated with the filepath. We are maintaining lease keys
236          * with the inode on the client. If the file has hardlinks, it is possible
237          * that the lease for a file be reused for an operation on its hardlink or
238          * vice versa.
239          * As a workaround, send request using an existing lease key and if the server
240          * returns STATUS_INVALID_PARAMETER, which maps to EINVAL, send the request
241          * again without the lease.
242          */
243         if (dentry) {
244                 inode = d_inode(dentry);
245                 if (CIFS_I(inode)->lease_granted && server->ops->get_lease_key) {
246                         oplock = SMB2_OPLOCK_LEVEL_LEASE;
247                         server->ops->get_lease_key(inode, &fid);
248                 }
249         }
250 
251         vars->oparms = *oparms;
252         vars->oparms.fid = &fid;
253 
254         rqst[num_rqst].rq_iov = &vars->open_iov[0];
255         rqst[num_rqst].rq_nvec = SMB2_CREATE_IOV_SIZE;
256         rc = SMB2_open_init(tcon, server,
257                             &rqst[num_rqst], &oplock, &vars->oparms,
258                             utf16_path);
259         kfree(utf16_path);
260         if (rc)
261                 goto finished;
262 
263         smb2_set_next_command(tcon, &rqst[num_rqst]);
264  after_open:
265         num_rqst++;
266         rc = 0;
267 
268         for (i = 0; i < num_cmds; i++) {
269                 /* Operation */
270                 switch (cmds[i]) {
271                 case SMB2_OP_QUERY_INFO:
272                         rqst[num_rqst].rq_iov = &vars->qi_iov;
273                         rqst[num_rqst].rq_nvec = 1;
274 
275                         if (cfile) {
276                                 rc = SMB2_query_info_init(tcon, server,
277                                                           &rqst[num_rqst],
278                                                           cfile->fid.persistent_fid,
279                                                           cfile->fid.volatile_fid,
280                                                           FILE_ALL_INFORMATION,
281                                                           SMB2_O_INFO_FILE, 0,
282                                                           sizeof(struct smb2_file_all_info) +
283                                                           PATH_MAX * 2, 0, NULL);
284                         } else {
285                                 rc = SMB2_query_info_init(tcon, server,
286                                                           &rqst[num_rqst],
287                                                           COMPOUND_FID,
288                                                           COMPOUND_FID,
289                                                           FILE_ALL_INFORMATION,
290                                                           SMB2_O_INFO_FILE, 0,
291                                                           sizeof(struct smb2_file_all_info) +
292                                                           PATH_MAX * 2, 0, NULL);
293                         }
294                         if (!rc && (!cfile || num_rqst > 1)) {
295                                 smb2_set_next_command(tcon, &rqst[num_rqst]);
296                                 smb2_set_related(&rqst[num_rqst]);
297                         } else if (rc) {
298                                 goto finished;
299                         }
300                         num_rqst++;
301                         trace_smb3_query_info_compound_enter(xid, ses->Suid,
302                                                              tcon->tid, full_path);
303                         break;
304                 case SMB2_OP_POSIX_QUERY_INFO:
305                         rqst[num_rqst].rq_iov = &vars->qi_iov;
306                         rqst[num_rqst].rq_nvec = 1;
307 
308                         if (cfile) {
309                                 /* TBD: fix following to allow for longer SIDs */
310                                 rc = SMB2_query_info_init(tcon, server,
311                                                           &rqst[num_rqst],
312                                                           cfile->fid.persistent_fid,
313                                                           cfile->fid.volatile_fid,
314                                                           SMB_FIND_FILE_POSIX_INFO,
315                                                           SMB2_O_INFO_FILE, 0,
316                                                           sizeof(struct smb311_posix_qinfo *) +
317                                                           (PATH_MAX * 2) +
318                                                           (sizeof(struct cifs_sid) * 2), 0, NULL);
319                         } else {
320                                 rc = SMB2_query_info_init(tcon, server,
321                                                           &rqst[num_rqst],
322                                                           COMPOUND_FID,
323                                                           COMPOUND_FID,
324                                                           SMB_FIND_FILE_POSIX_INFO,
325                                                           SMB2_O_INFO_FILE, 0,
326                                                           sizeof(struct smb311_posix_qinfo *) +
327                                                           (PATH_MAX * 2) +
328                                                           (sizeof(struct cifs_sid) * 2), 0, NULL);
329                         }
330                         if (!rc && (!cfile || num_rqst > 1)) {
331                                 smb2_set_next_command(tcon, &rqst[num_rqst]);
332                                 smb2_set_related(&rqst[num_rqst]);
333                         } else if (rc) {
334                                 goto finished;
335                         }
336                         num_rqst++;
337                         trace_smb3_posix_query_info_compound_enter(xid, ses->Suid,
338                                                                    tcon->tid, full_path);
339                         break;
340                 case SMB2_OP_DELETE:
341                         trace_smb3_delete_enter(xid, ses->Suid, tcon->tid, full_path);
342                         break;
343                 case SMB2_OP_MKDIR:
344                         /*
345                          * Directories are created through parameters in the
346                          * SMB2_open() call.
347                          */
348                         trace_smb3_mkdir_enter(xid, ses->Suid, tcon->tid, full_path);
349                         break;
350                 case SMB2_OP_RMDIR:
351                         rqst[num_rqst].rq_iov = &vars->si_iov[0];
352                         rqst[num_rqst].rq_nvec = 1;
353 
354                         size[0] = 1; /* sizeof __u8 See MS-FSCC section 2.4.11 */
355                         data[0] = &delete_pending[0];
356 
357                         rc = SMB2_set_info_init(tcon, server,
358                                                 &rqst[num_rqst], COMPOUND_FID,
359                                                 COMPOUND_FID, current->tgid,
360                                                 FILE_DISPOSITION_INFORMATION,
361                                                 SMB2_O_INFO_FILE, 0, data, size);
362                         if (rc)
363                                 goto finished;
364                         smb2_set_next_command(tcon, &rqst[num_rqst]);
365                         smb2_set_related(&rqst[num_rqst++]);
366                         trace_smb3_rmdir_enter(xid, ses->Suid, tcon->tid, full_path);
367                         break;
368                 case SMB2_OP_SET_EOF:
369                         rqst[num_rqst].rq_iov = &vars->si_iov[0];
370                         rqst[num_rqst].rq_nvec = 1;
371 
372                         size[0] = in_iov[i].iov_len;
373                         data[0] = in_iov[i].iov_base;
374 
375                         if (cfile) {
376                                 rc = SMB2_set_info_init(tcon, server,
377                                                         &rqst[num_rqst],
378                                                         cfile->fid.persistent_fid,
379                                                         cfile->fid.volatile_fid,
380                                                         current->tgid,
381                                                         FILE_END_OF_FILE_INFORMATION,
382                                                         SMB2_O_INFO_FILE, 0,
383                                                         data, size);
384                         } else {
385                                 rc = SMB2_set_info_init(tcon, server,
386                                                         &rqst[num_rqst],
387                                                         COMPOUND_FID,
388                                                         COMPOUND_FID,
389                                                         current->tgid,
390                                                         FILE_END_OF_FILE_INFORMATION,
391                                                         SMB2_O_INFO_FILE, 0,
392                                                         data, size);
393                         }
394                         if (!rc && (!cfile || num_rqst > 1)) {
395                                 smb2_set_next_command(tcon, &rqst[num_rqst]);
396                                 smb2_set_related(&rqst[num_rqst]);
397                         } else if (rc) {
398                                 goto finished;
399                         }
400                         num_rqst++;
401                         trace_smb3_set_eof_enter(xid, ses->Suid, tcon->tid, full_path);
402                         break;
403                 case SMB2_OP_SET_INFO:
404                         rqst[num_rqst].rq_iov = &vars->si_iov[0];
405                         rqst[num_rqst].rq_nvec = 1;
406 
407                         size[0] = in_iov[i].iov_len;
408                         data[0] = in_iov[i].iov_base;
409 
410                         if (cfile) {
411                                 rc = SMB2_set_info_init(tcon, server,
412                                                         &rqst[num_rqst],
413                                                         cfile->fid.persistent_fid,
414                                                         cfile->fid.volatile_fid, current->tgid,
415                                                         FILE_BASIC_INFORMATION,
416                                                         SMB2_O_INFO_FILE, 0, data, size);
417                         } else {
418                                 rc = SMB2_set_info_init(tcon, server,
419                                                         &rqst[num_rqst],
420                                                         COMPOUND_FID,
421                                                         COMPOUND_FID, current->tgid,
422                                                         FILE_BASIC_INFORMATION,
423                                                         SMB2_O_INFO_FILE, 0, data, size);
424                         }
425                         if (!rc && (!cfile || num_rqst > 1)) {
426                                 smb2_set_next_command(tcon, &rqst[num_rqst]);
427                                 smb2_set_related(&rqst[num_rqst]);
428                         } else if (rc) {
429                                 goto finished;
430                         }
431                         num_rqst++;
432                         trace_smb3_set_info_compound_enter(xid, ses->Suid,
433                                                            tcon->tid, full_path);
434                         break;
435                 case SMB2_OP_RENAME:
436                         rqst[num_rqst].rq_iov = &vars->si_iov[0];
437                         rqst[num_rqst].rq_nvec = 2;
438 
439                         len = in_iov[i].iov_len;
440 
441                         vars->rename_info.ReplaceIfExists = 1;
442                         vars->rename_info.RootDirectory = 0;
443                         vars->rename_info.FileNameLength = cpu_to_le32(len);
444 
445                         size[0] = sizeof(struct smb2_file_rename_info);
446                         data[0] = &vars->rename_info;
447 
448                         size[1] = len + 2 /* null */;
449                         data[1] = in_iov[i].iov_base;
450 
451                         if (cfile) {
452                                 rc = SMB2_set_info_init(tcon, server,
453                                                         &rqst[num_rqst],
454                                                         cfile->fid.persistent_fid,
455                                                         cfile->fid.volatile_fid,
456                                                         current->tgid, FILE_RENAME_INFORMATION,
457                                                         SMB2_O_INFO_FILE, 0, data, size);
458                         } else {
459                                 rc = SMB2_set_info_init(tcon, server,
460                                                         &rqst[num_rqst],
461                                                         COMPOUND_FID, COMPOUND_FID,
462                                                         current->tgid, FILE_RENAME_INFORMATION,
463                                                         SMB2_O_INFO_FILE, 0, data, size);
464                         }
465                         if (!rc && (!cfile || num_rqst > 1)) {
466                                 smb2_set_next_command(tcon, &rqst[num_rqst]);
467                                 smb2_set_related(&rqst[num_rqst]);
468                         } else if (rc) {
469                                 goto finished;
470                         }
471                         num_rqst++;
472                         trace_smb3_rename_enter(xid, ses->Suid, tcon->tid, full_path);
473                         break;
474                 case SMB2_OP_HARDLINK:
475                         rqst[num_rqst].rq_iov = &vars->si_iov[0];
476                         rqst[num_rqst].rq_nvec = 2;
477 
478                         len = in_iov[i].iov_len;
479 
480                         vars->link_info.ReplaceIfExists = 0;
481                         vars->link_info.RootDirectory = 0;
482                         vars->link_info.FileNameLength = cpu_to_le32(len);
483 
484                         size[0] = sizeof(struct smb2_file_link_info);
485                         data[0] = &vars->link_info;
486 
487                         size[1] = len + 2 /* null */;
488                         data[1] = in_iov[i].iov_base;
489 
490                         rc = SMB2_set_info_init(tcon, server,
491                                                 &rqst[num_rqst], COMPOUND_FID,
492                                                 COMPOUND_FID, current->tgid,
493                                                 FILE_LINK_INFORMATION,
494                                                 SMB2_O_INFO_FILE, 0, data, size);
495                         if (rc)
496                                 goto finished;
497                         smb2_set_next_command(tcon, &rqst[num_rqst]);
498                         smb2_set_related(&rqst[num_rqst++]);
499                         trace_smb3_hardlink_enter(xid, ses->Suid, tcon->tid, full_path);
500                         break;
501                 case SMB2_OP_SET_REPARSE:
502                         rqst[num_rqst].rq_iov = vars->io_iov;
503                         rqst[num_rqst].rq_nvec = ARRAY_SIZE(vars->io_iov);
504 
505                         if (cfile) {
506                                 rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst],
507                                                      cfile->fid.persistent_fid,
508                                                      cfile->fid.volatile_fid,
509                                                      FSCTL_SET_REPARSE_POINT,
510                                                      in_iov[i].iov_base,
511                                                      in_iov[i].iov_len, 0);
512                         } else {
513                                 rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst],
514                                                      COMPOUND_FID, COMPOUND_FID,
515                                                      FSCTL_SET_REPARSE_POINT,
516                                                      in_iov[i].iov_base,
517                                                      in_iov[i].iov_len, 0);
518                         }
519                         if (!rc && (!cfile || num_rqst > 1)) {
520                                 smb2_set_next_command(tcon, &rqst[num_rqst]);
521                                 smb2_set_related(&rqst[num_rqst]);
522                         } else if (rc) {
523                                 goto finished;
524                         }
525                         num_rqst++;
526                         trace_smb3_set_reparse_compound_enter(xid, ses->Suid,
527                                                               tcon->tid, full_path);
528                         break;
529                 case SMB2_OP_GET_REPARSE:
530                         rqst[num_rqst].rq_iov = vars->io_iov;
531                         rqst[num_rqst].rq_nvec = ARRAY_SIZE(vars->io_iov);
532 
533                         if (cfile) {
534                                 rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst],
535                                                      cfile->fid.persistent_fid,
536                                                      cfile->fid.volatile_fid,
537                                                      FSCTL_GET_REPARSE_POINT,
538                                                      NULL, 0, CIFSMaxBufSize);
539                         } else {
540                                 rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst],
541                                                      COMPOUND_FID, COMPOUND_FID,
542                                                      FSCTL_GET_REPARSE_POINT,
543                                                      NULL, 0, CIFSMaxBufSize);
544                         }
545                         if (!rc && (!cfile || num_rqst > 1)) {
546                                 smb2_set_next_command(tcon, &rqst[num_rqst]);
547                                 smb2_set_related(&rqst[num_rqst]);
548                         } else if (rc) {
549                                 goto finished;
550                         }
551                         num_rqst++;
552                         trace_smb3_get_reparse_compound_enter(xid, ses->Suid,
553                                                               tcon->tid, full_path);
554                         break;
555                 case SMB2_OP_QUERY_WSL_EA:
556                         rqst[num_rqst].rq_iov = &vars->ea_iov;
557                         rqst[num_rqst].rq_nvec = 1;
558 
559                         if (cfile) {
560                                 rc = SMB2_query_info_init(tcon, server,
561                                                           &rqst[num_rqst],
562                                                           cfile->fid.persistent_fid,
563                                                           cfile->fid.volatile_fid,
564                                                           FILE_FULL_EA_INFORMATION,
565                                                           SMB2_O_INFO_FILE, 0,
566                                                           SMB2_WSL_MAX_QUERY_EA_RESP_SIZE,
567                                                           sizeof(wsl_query_eas),
568                                                           (void *)wsl_query_eas);
569                         } else {
570                                 rc = SMB2_query_info_init(tcon, server,
571                                                           &rqst[num_rqst],
572                                                           COMPOUND_FID,
573                                                           COMPOUND_FID,
574                                                           FILE_FULL_EA_INFORMATION,
575                                                           SMB2_O_INFO_FILE, 0,
576                                                           SMB2_WSL_MAX_QUERY_EA_RESP_SIZE,
577                                                           sizeof(wsl_query_eas),
578                                                           (void *)wsl_query_eas);
579                         }
580                         if (!rc && (!cfile || num_rqst > 1)) {
581                                 smb2_set_next_command(tcon, &rqst[num_rqst]);
582                                 smb2_set_related(&rqst[num_rqst]);
583                         } else if (rc) {
584                                 goto finished;
585                         }
586                         num_rqst++;
587                         break;
588                 default:
589                         cifs_dbg(VFS, "Invalid command\n");
590                         rc = -EINVAL;
591                 }
592         }
593         if (rc)
594                 goto finished;
595 
596         /* We already have a handle so we can skip the close */
597         if (cfile)
598                 goto after_close;
599         /* Close */
600         flags |= CIFS_CP_CREATE_CLOSE_OP;
601         rqst[num_rqst].rq_iov = &vars->close_iov;
602         rqst[num_rqst].rq_nvec = 1;
603         rc = SMB2_close_init(tcon, server,
604                              &rqst[num_rqst], COMPOUND_FID,
605                              COMPOUND_FID, false);
606         smb2_set_related(&rqst[num_rqst]);
607         if (rc)
608                 goto finished;
609  after_close:
610         num_rqst++;
611 
612         if (cfile) {
613                 if (retries)
614                         for (i = 1; i < num_rqst - 2; i++)
615                                 smb2_set_replay(server, &rqst[i]);
616 
617                 rc = compound_send_recv(xid, ses, server,
618                                         flags, num_rqst - 2,
619                                         &rqst[1], &resp_buftype[1],
620                                         &rsp_iov[1]);
621         } else {
622                 if (retries)
623                         for (i = 0; i < num_rqst; i++)
624                                 smb2_set_replay(server, &rqst[i]);
625 
626                 rc = compound_send_recv(xid, ses, server,
627                                         flags, num_rqst,
628                                         rqst, resp_buftype,
629                                         rsp_iov);
630         }
631 
632 finished:
633         num_rqst = 0;
634         SMB2_open_free(&rqst[num_rqst++]);
635         if (rc == -EREMCHG) {
636                 pr_warn_once("server share %s deleted\n", tcon->tree_name);
637                 tcon->need_reconnect = true;
638         }
639 
640         for (i = 0; i < num_cmds; i++) {
641                 switch (cmds[i]) {
642                 case SMB2_OP_QUERY_INFO:
643                         idata = in_iov[i].iov_base;
644                         if (rc == 0 && cfile && cfile->symlink_target) {
645                                 idata->symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL);
646                                 if (!idata->symlink_target)
647                                         rc = -ENOMEM;
648                         }
649                         if (rc == 0) {
650                                 qi_rsp = (struct smb2_query_info_rsp *)
651                                         rsp_iov[i + 1].iov_base;
652                                 rc = smb2_validate_and_copy_iov(
653                                         le16_to_cpu(qi_rsp->OutputBufferOffset),
654                                         le32_to_cpu(qi_rsp->OutputBufferLength),
655                                         &rsp_iov[i + 1], sizeof(idata->fi), (char *)&idata->fi);
656                         }
657                         SMB2_query_info_free(&rqst[num_rqst++]);
658                         if (rc)
659                                 trace_smb3_query_info_compound_err(xid,  ses->Suid,
660                                                                    tcon->tid, rc);
661                         else
662                                 trace_smb3_query_info_compound_done(xid, ses->Suid,
663                                                                     tcon->tid);
664                         break;
665                 case SMB2_OP_POSIX_QUERY_INFO:
666                         idata = in_iov[i].iov_base;
667                         if (rc == 0 && cfile && cfile->symlink_target) {
668                                 idata->symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL);
669                                 if (!idata->symlink_target)
670                                         rc = -ENOMEM;
671                         }
672                         if (rc == 0) {
673                                 qi_rsp = (struct smb2_query_info_rsp *)
674                                         rsp_iov[i + 1].iov_base;
675                                 rc = smb2_validate_and_copy_iov(
676                                         le16_to_cpu(qi_rsp->OutputBufferOffset),
677                                         le32_to_cpu(qi_rsp->OutputBufferLength),
678                                         &rsp_iov[i + 1], sizeof(idata->posix_fi) /* add SIDs */,
679                                         (char *)&idata->posix_fi);
680                         }
681                         if (rc == 0)
682                                 rc = parse_posix_sids(idata, &rsp_iov[i + 1]);
683 
684                         SMB2_query_info_free(&rqst[num_rqst++]);
685                         if (rc)
686                                 trace_smb3_posix_query_info_compound_err(xid,  ses->Suid,
687                                                                          tcon->tid, rc);
688                         else
689                                 trace_smb3_posix_query_info_compound_done(xid, ses->Suid,
690                                                                           tcon->tid);
691                         break;
692                 case SMB2_OP_DELETE:
693                         if (rc)
694                                 trace_smb3_delete_err(xid,  ses->Suid, tcon->tid, rc);
695                         else {
696                                 /*
697                                  * If dentry (hence, inode) is NULL, lease break is going to
698                                  * take care of degrading leases on handles for deleted files.
699                                  */
700                                 if (inode)
701                                         cifs_mark_open_handles_for_deleted_file(inode, full_path);
702                                 trace_smb3_delete_done(xid, ses->Suid, tcon->tid);
703                         }
704                         break;
705                 case SMB2_OP_MKDIR:
706                         if (rc)
707                                 trace_smb3_mkdir_err(xid,  ses->Suid, tcon->tid, rc);
708                         else
709                                 trace_smb3_mkdir_done(xid, ses->Suid, tcon->tid);
710                         break;
711                 case SMB2_OP_HARDLINK:
712                         if (rc)
713                                 trace_smb3_hardlink_err(xid,  ses->Suid, tcon->tid, rc);
714                         else
715                                 trace_smb3_hardlink_done(xid, ses->Suid, tcon->tid);
716                         SMB2_set_info_free(&rqst[num_rqst++]);
717                         break;
718                 case SMB2_OP_RENAME:
719                         if (rc)
720                                 trace_smb3_rename_err(xid,  ses->Suid, tcon->tid, rc);
721                         else
722                                 trace_smb3_rename_done(xid, ses->Suid, tcon->tid);
723                         SMB2_set_info_free(&rqst[num_rqst++]);
724                         break;
725                 case SMB2_OP_RMDIR:
726                         if (rc)
727                                 trace_smb3_rmdir_err(xid,  ses->Suid, tcon->tid, rc);
728                         else
729                                 trace_smb3_rmdir_done(xid, ses->Suid, tcon->tid);
730                         SMB2_set_info_free(&rqst[num_rqst++]);
731                         break;
732                 case SMB2_OP_SET_EOF:
733                         if (rc)
734                                 trace_smb3_set_eof_err(xid,  ses->Suid, tcon->tid, rc);
735                         else
736                                 trace_smb3_set_eof_done(xid, ses->Suid, tcon->tid);
737                         SMB2_set_info_free(&rqst[num_rqst++]);
738                         break;
739                 case SMB2_OP_SET_INFO:
740                         if (rc)
741                                 trace_smb3_set_info_compound_err(xid,  ses->Suid,
742                                                                  tcon->tid, rc);
743                         else
744                                 trace_smb3_set_info_compound_done(xid, ses->Suid,
745                                                                   tcon->tid);
746                         SMB2_set_info_free(&rqst[num_rqst++]);
747                         break;
748                 case SMB2_OP_SET_REPARSE:
749                         if (rc) {
750                                 trace_smb3_set_reparse_compound_err(xid,  ses->Suid,
751                                                                     tcon->tid, rc);
752                         } else {
753                                 trace_smb3_set_reparse_compound_done(xid, ses->Suid,
754                                                                      tcon->tid);
755                         }
756                         SMB2_ioctl_free(&rqst[num_rqst++]);
757                         break;
758                 case SMB2_OP_GET_REPARSE:
759                         if (!rc) {
760                                 iov = &rsp_iov[i + 1];
761                                 idata = in_iov[i].iov_base;
762                                 idata->reparse.io.iov = *iov;
763                                 idata->reparse.io.buftype = resp_buftype[i + 1];
764                                 rbuf = reparse_buf_ptr(iov);
765                                 if (IS_ERR(rbuf)) {
766                                         rc = PTR_ERR(rbuf);
767                                         trace_smb3_set_reparse_compound_err(xid,  ses->Suid,
768                                                                             tcon->tid, rc);
769                                 } else {
770                                         idata->reparse.tag = le32_to_cpu(rbuf->ReparseTag);
771                                         trace_smb3_set_reparse_compound_done(xid, ses->Suid,
772                                                                              tcon->tid);
773                                 }
774                                 memset(iov, 0, sizeof(*iov));
775                                 resp_buftype[i + 1] = CIFS_NO_BUFFER;
776                         } else {
777                                 trace_smb3_set_reparse_compound_err(xid, ses->Suid,
778                                                                     tcon->tid, rc);
779                         }
780                         SMB2_ioctl_free(&rqst[num_rqst++]);
781                         break;
782                 case SMB2_OP_QUERY_WSL_EA:
783                         if (!rc) {
784                                 idata = in_iov[i].iov_base;
785                                 qi_rsp = rsp_iov[i + 1].iov_base;
786                                 data[0] = (u8 *)qi_rsp + le16_to_cpu(qi_rsp->OutputBufferOffset);
787                                 size[0] = le32_to_cpu(qi_rsp->OutputBufferLength);
788                                 rc = check_wsl_eas(&rsp_iov[i + 1]);
789                                 if (!rc) {
790                                         memcpy(idata->wsl.eas, data[0], size[0]);
791                                         idata->wsl.eas_len = size[0];
792                                 }
793                         }
794                         if (!rc) {
795                                 trace_smb3_query_wsl_ea_compound_done(xid, ses->Suid,
796                                                                       tcon->tid);
797                         } else {
798                                 trace_smb3_query_wsl_ea_compound_err(xid, ses->Suid,
799                                                                      tcon->tid, rc);
800                         }
801                         SMB2_query_info_free(&rqst[num_rqst++]);
802                         break;
803                 }
804         }
805         SMB2_close_free(&rqst[num_rqst]);
806 
807         num_cmds += 2;
808         if (out_iov && out_buftype) {
809                 memcpy(out_iov, rsp_iov, num_cmds * sizeof(*out_iov));
810                 memcpy(out_buftype, resp_buftype,
811                        num_cmds * sizeof(*out_buftype));
812         } else {
813                 for (i = 0; i < num_cmds; i++)
814                         free_rsp_buf(resp_buftype[i], rsp_iov[i].iov_base);
815         }
816         num_cmds -= 2; /* correct num_cmds as there could be a retry */
817         kfree(vars);
818 
819         if (is_replayable_error(rc) &&
820             smb2_should_replay(tcon, &retries, &cur_sleep))
821                 goto replay_again;
822 
823         if (cfile)
824                 cifsFileInfo_put(cfile);
825 
826         return rc;
827 }
828 
829 static int parse_create_response(struct cifs_open_info_data *data,
830                                  struct cifs_sb_info *cifs_sb,
831                                  const struct kvec *iov)
832 {
833         struct smb2_create_rsp *rsp = iov->iov_base;
834         bool reparse_point = false;
835         u32 tag = 0;
836         int rc = 0;
837 
838         switch (rsp->hdr.Status) {
839         case STATUS_IO_REPARSE_TAG_NOT_HANDLED:
840                 reparse_point = true;
841                 break;
842         case STATUS_STOPPED_ON_SYMLINK:
843                 rc = smb2_parse_symlink_response(cifs_sb, iov,
844                                                  &data->symlink_target);
845                 if (rc)
846                         return rc;
847                 tag = IO_REPARSE_TAG_SYMLINK;
848                 reparse_point = true;
849                 break;
850         case STATUS_SUCCESS:
851                 reparse_point = !!(rsp->Flags & SMB2_CREATE_FLAG_REPARSEPOINT);
852                 break;
853         }
854         data->reparse_point = reparse_point;
855         data->reparse.tag = tag;
856         return rc;
857 }
858 
859 int smb2_query_path_info(const unsigned int xid,
860                          struct cifs_tcon *tcon,
861                          struct cifs_sb_info *cifs_sb,
862                          const char *full_path,
863                          struct cifs_open_info_data *data)
864 {
865         struct cifs_open_parms oparms;
866         __u32 create_options = 0;
867         struct cifsFileInfo *cfile;
868         struct cached_fid *cfid = NULL;
869         struct smb2_hdr *hdr;
870         struct kvec in_iov[3], out_iov[3] = {};
871         int out_buftype[3] = {};
872         int cmds[3];
873         bool islink;
874         int i, num_cmds = 0;
875         int rc, rc2;
876 
877         data->adjust_tz = false;
878         data->reparse_point = false;
879 
880         /*
881          * BB TODO: Add support for using cached root handle in SMB3.1.1 POSIX.
882          * Create SMB2_query_posix_info worker function to do non-compounded
883          * query when we already have an open file handle for this. For now this
884          * is fast enough (always using the compounded version).
885          */
886         if (!tcon->posix_extensions) {
887                 if (*full_path) {
888                         rc = -ENOENT;
889                 } else {
890                         rc = open_cached_dir(xid, tcon, full_path,
891                                              cifs_sb, false, &cfid);
892                 }
893                 /* If it is a root and its handle is cached then use it */
894                 if (!rc) {
895                         if (cfid->file_all_info_is_valid) {
896                                 memcpy(&data->fi, &cfid->file_all_info,
897                                        sizeof(data->fi));
898                         } else {
899                                 rc = SMB2_query_info(xid, tcon,
900                                                      cfid->fid.persistent_fid,
901                                                      cfid->fid.volatile_fid,
902                                                      &data->fi);
903                         }
904                         close_cached_dir(cfid);
905                         return rc;
906                 }
907                 cmds[num_cmds++] = SMB2_OP_QUERY_INFO;
908         } else {
909                 cmds[num_cmds++] = SMB2_OP_POSIX_QUERY_INFO;
910         }
911 
912         in_iov[0].iov_base = data;
913         in_iov[0].iov_len = sizeof(*data);
914         in_iov[1] = in_iov[0];
915         in_iov[2] = in_iov[0];
916 
917         cifs_get_readable_path(tcon, full_path, &cfile);
918         oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, FILE_READ_ATTRIBUTES,
919                              FILE_OPEN, create_options, ACL_NO_MODE);
920         rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
921                               &oparms, in_iov, cmds, num_cmds,
922                               cfile, out_iov, out_buftype, NULL);
923         hdr = out_iov[0].iov_base;
924         /*
925          * If first iov is unset, then SMB session was dropped or we've got a
926          * cached open file (@cfile).
927          */
928         if (!hdr || out_buftype[0] == CIFS_NO_BUFFER)
929                 goto out;
930 
931         switch (rc) {
932         case 0:
933                 rc = parse_create_response(data, cifs_sb, &out_iov[0]);
934                 break;
935         case -EOPNOTSUPP:
936                 /*
937                  * BB TODO: When support for special files added to Samba
938                  * re-verify this path.
939                  */
940                 rc = parse_create_response(data, cifs_sb, &out_iov[0]);
941                 if (rc || !data->reparse_point)
942                         goto out;
943 
944                 cmds[num_cmds++] = SMB2_OP_QUERY_WSL_EA;
945                 /*
946                  * Skip SMB2_OP_GET_REPARSE if symlink already parsed in create
947                  * response.
948                  */
949                 if (data->reparse.tag != IO_REPARSE_TAG_SYMLINK)
950                         cmds[num_cmds++] = SMB2_OP_GET_REPARSE;
951 
952                 oparms = CIFS_OPARMS(cifs_sb, tcon, full_path,
953                                      FILE_READ_ATTRIBUTES |
954                                      FILE_READ_EA | SYNCHRONIZE,
955                                      FILE_OPEN, create_options |
956                                      OPEN_REPARSE_POINT, ACL_NO_MODE);
957                 cifs_get_readable_path(tcon, full_path, &cfile);
958                 rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
959                                       &oparms, in_iov, cmds, num_cmds,
960                                       cfile, NULL, NULL, NULL);
961                 break;
962         case -EREMOTE:
963                 break;
964         default:
965                 if (hdr->Status != STATUS_OBJECT_NAME_INVALID)
966                         break;
967                 rc2 = cifs_inval_name_dfs_link_error(xid, tcon, cifs_sb,
968                                                      full_path, &islink);
969                 if (rc2) {
970                         rc = rc2;
971                         goto out;
972                 }
973                 if (islink)
974                         rc = -EREMOTE;
975         }
976 
977 out:
978         for (i = 0; i < ARRAY_SIZE(out_buftype); i++)
979                 free_rsp_buf(out_buftype[i], out_iov[i].iov_base);
980         return rc;
981 }
982 
983 int
984 smb2_mkdir(const unsigned int xid, struct inode *parent_inode, umode_t mode,
985            struct cifs_tcon *tcon, const char *name,
986            struct cifs_sb_info *cifs_sb)
987 {
988         struct cifs_open_parms oparms;
989 
990         oparms = CIFS_OPARMS(cifs_sb, tcon, name, FILE_WRITE_ATTRIBUTES,
991                              FILE_CREATE, CREATE_NOT_FILE, mode);
992         return smb2_compound_op(xid, tcon, cifs_sb,
993                                 name, &oparms, NULL,
994                                 &(int){SMB2_OP_MKDIR}, 1,
995                                 NULL, NULL, NULL, NULL);
996 }
997 
998 void
999 smb2_mkdir_setinfo(struct inode *inode, const char *name,
1000                    struct cifs_sb_info *cifs_sb, struct cifs_tcon *tcon,
1001                    const unsigned int xid)
1002 {
1003         struct cifs_open_parms oparms;
1004         FILE_BASIC_INFO data = {};
1005         struct cifsInodeInfo *cifs_i;
1006         struct cifsFileInfo *cfile;
1007         struct kvec in_iov;
1008         u32 dosattrs;
1009         int tmprc;
1010 
1011         in_iov.iov_base = &data;
1012         in_iov.iov_len = sizeof(data);
1013         cifs_i = CIFS_I(inode);
1014         dosattrs = cifs_i->cifsAttrs | ATTR_READONLY;
1015         data.Attributes = cpu_to_le32(dosattrs);
1016         cifs_get_writable_path(tcon, name, FIND_WR_ANY, &cfile);
1017         oparms = CIFS_OPARMS(cifs_sb, tcon, name, FILE_WRITE_ATTRIBUTES,
1018                              FILE_CREATE, CREATE_NOT_FILE, ACL_NO_MODE);
1019         tmprc = smb2_compound_op(xid, tcon, cifs_sb, name,
1020                                  &oparms, &in_iov,
1021                                  &(int){SMB2_OP_SET_INFO}, 1,
1022                                  cfile, NULL, NULL, NULL);
1023         if (tmprc == 0)
1024                 cifs_i->cifsAttrs = dosattrs;
1025 }
1026 
1027 int
1028 smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
1029            struct cifs_sb_info *cifs_sb)
1030 {
1031         struct cifs_open_parms oparms;
1032 
1033         drop_cached_dir_by_name(xid, tcon, name, cifs_sb);
1034         oparms = CIFS_OPARMS(cifs_sb, tcon, name, DELETE,
1035                              FILE_OPEN, CREATE_NOT_FILE, ACL_NO_MODE);
1036         return smb2_compound_op(xid, tcon, cifs_sb,
1037                                 name, &oparms, NULL,
1038                                 &(int){SMB2_OP_RMDIR}, 1,
1039                                 NULL, NULL, NULL, NULL);
1040 }
1041 
1042 int
1043 smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
1044             struct cifs_sb_info *cifs_sb, struct dentry *dentry)
1045 {
1046         struct cifs_open_parms oparms;
1047 
1048         oparms = CIFS_OPARMS(cifs_sb, tcon, name,
1049                              DELETE, FILE_OPEN,
1050                              CREATE_DELETE_ON_CLOSE | OPEN_REPARSE_POINT,
1051                              ACL_NO_MODE);
1052         int rc = smb2_compound_op(xid, tcon, cifs_sb, name, &oparms,
1053                                   NULL, &(int){SMB2_OP_DELETE}, 1,
1054                                   NULL, NULL, NULL, dentry);
1055         if (rc == -EINVAL) {
1056                 cifs_dbg(FYI, "invalid lease key, resending request without lease");
1057                 rc = smb2_compound_op(xid, tcon, cifs_sb, name, &oparms,
1058                                       NULL, &(int){SMB2_OP_DELETE}, 1,
1059                                       NULL, NULL, NULL, NULL);
1060         }
1061         return rc;
1062 }
1063 
1064 static int smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon,
1065                               const char *from_name, const char *to_name,
1066                               struct cifs_sb_info *cifs_sb,
1067                               __u32 create_options, __u32 access,
1068                               int command, struct cifsFileInfo *cfile,
1069                                   struct dentry *dentry)
1070 {
1071         struct cifs_open_parms oparms;
1072         struct kvec in_iov;
1073         __le16 *smb2_to_name = NULL;
1074         int rc;
1075 
1076         smb2_to_name = cifs_convert_path_to_utf16(to_name, cifs_sb);
1077         if (smb2_to_name == NULL) {
1078                 rc = -ENOMEM;
1079                 goto smb2_rename_path;
1080         }
1081         in_iov.iov_base = smb2_to_name;
1082         in_iov.iov_len = 2 * UniStrnlen((wchar_t *)smb2_to_name, PATH_MAX);
1083         oparms = CIFS_OPARMS(cifs_sb, tcon, from_name, access, FILE_OPEN,
1084                              create_options, ACL_NO_MODE);
1085         rc = smb2_compound_op(xid, tcon, cifs_sb, from_name,
1086                               &oparms, &in_iov, &command, 1,
1087                               cfile, NULL, NULL, dentry);
1088 smb2_rename_path:
1089         kfree(smb2_to_name);
1090         return rc;
1091 }
1092 
1093 int smb2_rename_path(const unsigned int xid,
1094                      struct cifs_tcon *tcon,
1095                      struct dentry *source_dentry,
1096                      const char *from_name, const char *to_name,
1097                      struct cifs_sb_info *cifs_sb)
1098 {
1099         struct cifsFileInfo *cfile;
1100         __u32 co = file_create_options(source_dentry);
1101 
1102         drop_cached_dir_by_name(xid, tcon, from_name, cifs_sb);
1103         cifs_get_writable_path(tcon, from_name, FIND_WR_WITH_DELETE, &cfile);
1104 
1105         int rc = smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
1106                                   co, DELETE, SMB2_OP_RENAME, cfile, source_dentry);
1107         if (rc == -EINVAL) {
1108                 cifs_dbg(FYI, "invalid lease key, resending request without lease");
1109                 cifs_get_writable_path(tcon, from_name,
1110                                        FIND_WR_WITH_DELETE, &cfile);
1111                 rc = smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
1112                                   co, DELETE, SMB2_OP_RENAME, cfile, NULL);
1113         }
1114         return rc;
1115 }
1116 
1117 int smb2_create_hardlink(const unsigned int xid,
1118                          struct cifs_tcon *tcon,
1119                          struct dentry *source_dentry,
1120                          const char *from_name, const char *to_name,
1121                          struct cifs_sb_info *cifs_sb)
1122 {
1123         __u32 co = file_create_options(source_dentry);
1124 
1125         return smb2_set_path_attr(xid, tcon, from_name, to_name,
1126                                   cifs_sb, co, FILE_READ_ATTRIBUTES,
1127                                   SMB2_OP_HARDLINK, NULL, NULL);
1128 }
1129 
1130 int
1131 smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
1132                    const char *full_path, __u64 size,
1133                    struct cifs_sb_info *cifs_sb, bool set_alloc,
1134                    struct dentry *dentry)
1135 {
1136         struct cifs_open_parms oparms;
1137         struct cifsFileInfo *cfile;
1138         struct kvec in_iov;
1139         __le64 eof = cpu_to_le64(size);
1140         int rc;
1141 
1142         in_iov.iov_base = &eof;
1143         in_iov.iov_len = sizeof(eof);
1144         cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
1145 
1146         oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, FILE_WRITE_DATA,
1147                              FILE_OPEN, 0, ACL_NO_MODE);
1148         rc = smb2_compound_op(xid, tcon, cifs_sb,
1149                               full_path, &oparms, &in_iov,
1150                               &(int){SMB2_OP_SET_EOF}, 1,
1151                               cfile, NULL, NULL, dentry);
1152         if (rc == -EINVAL) {
1153                 cifs_dbg(FYI, "invalid lease key, resending request without lease");
1154                 cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
1155                 rc = smb2_compound_op(xid, tcon, cifs_sb,
1156                                       full_path, &oparms, &in_iov,
1157                                       &(int){SMB2_OP_SET_EOF}, 1,
1158                                       cfile, NULL, NULL, NULL);
1159         }
1160         return rc;
1161 }
1162 
1163 int
1164 smb2_set_file_info(struct inode *inode, const char *full_path,
1165                    FILE_BASIC_INFO *buf, const unsigned int xid)
1166 {
1167         struct cifs_open_parms oparms;
1168         struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
1169         struct tcon_link *tlink;
1170         struct cifs_tcon *tcon;
1171         struct cifsFileInfo *cfile;
1172         struct kvec in_iov = { .iov_base = buf, .iov_len = sizeof(*buf), };
1173         int rc;
1174 
1175         if ((buf->CreationTime == 0) && (buf->LastAccessTime == 0) &&
1176             (buf->LastWriteTime == 0) && (buf->ChangeTime == 0) &&
1177             (buf->Attributes == 0))
1178                 return 0; /* would be a no op, no sense sending this */
1179 
1180         tlink = cifs_sb_tlink(cifs_sb);
1181         if (IS_ERR(tlink))
1182                 return PTR_ERR(tlink);
1183         tcon = tlink_tcon(tlink);
1184 
1185         cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
1186         oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, FILE_WRITE_ATTRIBUTES,
1187                              FILE_OPEN, 0, ACL_NO_MODE);
1188         rc = smb2_compound_op(xid, tcon, cifs_sb,
1189                               full_path, &oparms, &in_iov,
1190                               &(int){SMB2_OP_SET_INFO}, 1,
1191                               cfile, NULL, NULL, NULL);
1192         cifs_put_tlink(tlink);
1193         return rc;
1194 }
1195 
1196 struct inode *smb2_get_reparse_inode(struct cifs_open_info_data *data,
1197                                      struct super_block *sb,
1198                                      const unsigned int xid,
1199                                      struct cifs_tcon *tcon,
1200                                      const char *full_path,
1201                                      struct kvec *reparse_iov,
1202                                      struct kvec *xattr_iov)
1203 {
1204         struct cifs_open_parms oparms;
1205         struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
1206         struct cifsFileInfo *cfile;
1207         struct inode *new = NULL;
1208         int out_buftype[4] = {};
1209         struct kvec out_iov[4] = {};
1210         struct kvec in_iov[2];
1211         int cmds[2];
1212         int rc;
1213         int i;
1214 
1215         oparms = CIFS_OPARMS(cifs_sb, tcon, full_path,
1216                              SYNCHRONIZE | DELETE |
1217                              FILE_READ_ATTRIBUTES |
1218                              FILE_WRITE_ATTRIBUTES,
1219                              FILE_CREATE,
1220                              CREATE_NOT_DIR | OPEN_REPARSE_POINT,
1221                              ACL_NO_MODE);
1222         if (xattr_iov)
1223                 oparms.ea_cctx = xattr_iov;
1224 
1225         cmds[0] = SMB2_OP_SET_REPARSE;
1226         in_iov[0] = *reparse_iov;
1227         in_iov[1].iov_base = data;
1228         in_iov[1].iov_len = sizeof(*data);
1229 
1230         if (tcon->posix_extensions) {
1231                 cmds[1] = SMB2_OP_POSIX_QUERY_INFO;
1232                 cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
1233                 rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, &oparms,
1234                                       in_iov, cmds, 2, cfile, out_iov, out_buftype, NULL);
1235                 if (!rc) {
1236                         rc = smb311_posix_get_inode_info(&new, full_path,
1237                                                          data, sb, xid);
1238                 }
1239         } else {
1240                 cmds[1] = SMB2_OP_QUERY_INFO;
1241                 cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
1242                 rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, &oparms,
1243                                       in_iov, cmds, 2, cfile, out_iov, out_buftype, NULL);
1244                 if (!rc) {
1245                         rc = cifs_get_inode_info(&new, full_path,
1246                                                  data, sb, xid, NULL);
1247                 }
1248         }
1249 
1250 
1251         /*
1252          * If CREATE was successful but SMB2_OP_SET_REPARSE failed then
1253          * remove the intermediate object created by CREATE. Otherwise
1254          * empty object stay on the server when reparse call failed.
1255          */
1256         if (rc &&
1257             out_iov[0].iov_base != NULL && out_buftype[0] != CIFS_NO_BUFFER &&
1258             ((struct smb2_hdr *)out_iov[0].iov_base)->Status == STATUS_SUCCESS &&
1259             (out_iov[1].iov_base == NULL || out_buftype[1] == CIFS_NO_BUFFER ||
1260              ((struct smb2_hdr *)out_iov[1].iov_base)->Status != STATUS_SUCCESS))
1261                 smb2_unlink(xid, tcon, full_path, cifs_sb, NULL);
1262 
1263         for (i = 0; i < ARRAY_SIZE(out_buftype); i++)
1264                 free_rsp_buf(out_buftype[i], out_iov[i].iov_base);
1265 
1266         return rc ? ERR_PTR(rc) : new;
1267 }
1268 
1269 int smb2_query_reparse_point(const unsigned int xid,
1270                              struct cifs_tcon *tcon,
1271                              struct cifs_sb_info *cifs_sb,
1272                              const char *full_path,
1273                              u32 *tag, struct kvec *rsp,
1274                              int *rsp_buftype)
1275 {
1276         struct cifs_open_parms oparms;
1277         struct cifs_open_info_data data = {};
1278         struct cifsFileInfo *cfile;
1279         struct kvec in_iov = { .iov_base = &data, .iov_len = sizeof(data), };
1280         int rc;
1281 
1282         cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path);
1283 
1284         cifs_get_readable_path(tcon, full_path, &cfile);
1285         oparms = CIFS_OPARMS(cifs_sb, tcon, full_path,
1286                              FILE_READ_ATTRIBUTES | FILE_READ_EA | SYNCHRONIZE,
1287                              FILE_OPEN, OPEN_REPARSE_POINT, ACL_NO_MODE);
1288         rc = smb2_compound_op(xid, tcon, cifs_sb,
1289                               full_path, &oparms, &in_iov,
1290                               &(int){SMB2_OP_GET_REPARSE}, 1,
1291                               cfile, NULL, NULL, NULL);
1292         if (rc)
1293                 goto out;
1294 
1295         *tag = data.reparse.tag;
1296         *rsp = data.reparse.io.iov;
1297         *rsp_buftype = data.reparse.io.buftype;
1298         memset(&data.reparse.io.iov, 0, sizeof(data.reparse.io.iov));
1299         data.reparse.io.buftype = CIFS_NO_BUFFER;
1300 out:
1301         cifs_free_open_info(&data);
1302         return rc;
1303 }
1304 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php