]> Git Repo - J-linux.git/blob - fs/smb/client/smb2inode.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / fs / smb / client / smb2inode.c
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 ([email protected]),
7  *              Steve French ([email protected])
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 "../common/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 smb_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 smb_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 char *full_path,
832                                  const struct kvec *iov)
833 {
834         struct smb2_create_rsp *rsp = iov->iov_base;
835         bool reparse_point = false;
836         u32 tag = 0;
837         int rc = 0;
838
839         switch (rsp->hdr.Status) {
840         case STATUS_IO_REPARSE_TAG_NOT_HANDLED:
841                 reparse_point = true;
842                 break;
843         case STATUS_STOPPED_ON_SYMLINK:
844                 rc = smb2_parse_symlink_response(cifs_sb, iov,
845                                                  full_path,
846                                                  &data->symlink_target);
847                 if (rc)
848                         return rc;
849                 tag = IO_REPARSE_TAG_SYMLINK;
850                 reparse_point = true;
851                 break;
852         case STATUS_SUCCESS:
853                 reparse_point = !!(rsp->Flags & SMB2_CREATE_FLAG_REPARSEPOINT);
854                 break;
855         }
856         data->reparse_point = reparse_point;
857         data->reparse.tag = tag;
858         return rc;
859 }
860
861 int smb2_query_path_info(const unsigned int xid,
862                          struct cifs_tcon *tcon,
863                          struct cifs_sb_info *cifs_sb,
864                          const char *full_path,
865                          struct cifs_open_info_data *data)
866 {
867         struct cifs_open_parms oparms;
868         __u32 create_options = 0;
869         struct cifsFileInfo *cfile;
870         struct cached_fid *cfid = NULL;
871         struct smb2_hdr *hdr;
872         struct kvec in_iov[3], out_iov[3] = {};
873         int out_buftype[3] = {};
874         int cmds[3];
875         bool islink;
876         int i, num_cmds = 0;
877         int rc, rc2;
878
879         data->adjust_tz = false;
880         data->reparse_point = false;
881
882         /*
883          * BB TODO: Add support for using cached root handle in SMB3.1.1 POSIX.
884          * Create SMB2_query_posix_info worker function to do non-compounded
885          * query when we already have an open file handle for this. For now this
886          * is fast enough (always using the compounded version).
887          */
888         if (!tcon->posix_extensions) {
889                 if (*full_path) {
890                         rc = -ENOENT;
891                 } else {
892                         rc = open_cached_dir(xid, tcon, full_path,
893                                              cifs_sb, false, &cfid);
894                 }
895                 /* If it is a root and its handle is cached then use it */
896                 if (!rc) {
897                         if (cfid->file_all_info_is_valid) {
898                                 memcpy(&data->fi, &cfid->file_all_info,
899                                        sizeof(data->fi));
900                         } else {
901                                 rc = SMB2_query_info(xid, tcon,
902                                                      cfid->fid.persistent_fid,
903                                                      cfid->fid.volatile_fid,
904                                                      &data->fi);
905                         }
906                         close_cached_dir(cfid);
907                         return rc;
908                 }
909                 cmds[num_cmds++] = SMB2_OP_QUERY_INFO;
910         } else {
911                 cmds[num_cmds++] = SMB2_OP_POSIX_QUERY_INFO;
912         }
913
914         in_iov[0].iov_base = data;
915         in_iov[0].iov_len = sizeof(*data);
916         in_iov[1] = in_iov[0];
917         in_iov[2] = in_iov[0];
918
919         cifs_get_readable_path(tcon, full_path, &cfile);
920         oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, FILE_READ_ATTRIBUTES,
921                              FILE_OPEN, create_options, ACL_NO_MODE);
922         rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
923                               &oparms, in_iov, cmds, num_cmds,
924                               cfile, out_iov, out_buftype, NULL);
925         hdr = out_iov[0].iov_base;
926         /*
927          * If first iov is unset, then SMB session was dropped or we've got a
928          * cached open file (@cfile).
929          */
930         if (!hdr || out_buftype[0] == CIFS_NO_BUFFER)
931                 goto out;
932
933         switch (rc) {
934         case 0:
935                 rc = parse_create_response(data, cifs_sb, full_path, &out_iov[0]);
936                 break;
937         case -EOPNOTSUPP:
938                 /*
939                  * BB TODO: When support for special files added to Samba
940                  * re-verify this path.
941                  */
942                 rc = parse_create_response(data, cifs_sb, full_path, &out_iov[0]);
943                 if (rc || !data->reparse_point)
944                         goto out;
945
946                 if (!tcon->posix_extensions)
947                         cmds[num_cmds++] = SMB2_OP_QUERY_WSL_EA;
948                 /*
949                  * Skip SMB2_OP_GET_REPARSE if symlink already parsed in create
950                  * response.
951                  */
952                 if (data->reparse.tag != IO_REPARSE_TAG_SYMLINK)
953                         cmds[num_cmds++] = SMB2_OP_GET_REPARSE;
954
955                 oparms = CIFS_OPARMS(cifs_sb, tcon, full_path,
956                                      FILE_READ_ATTRIBUTES |
957                                      FILE_READ_EA | SYNCHRONIZE,
958                                      FILE_OPEN, create_options |
959                                      OPEN_REPARSE_POINT, ACL_NO_MODE);
960                 cifs_get_readable_path(tcon, full_path, &cfile);
961                 rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
962                                       &oparms, in_iov, cmds, num_cmds,
963                                       cfile, NULL, NULL, NULL);
964                 break;
965         case -EREMOTE:
966                 break;
967         default:
968                 if (hdr->Status != STATUS_OBJECT_NAME_INVALID)
969                         break;
970                 rc2 = cifs_inval_name_dfs_link_error(xid, tcon, cifs_sb,
971                                                      full_path, &islink);
972                 if (rc2) {
973                         rc = rc2;
974                         goto out;
975                 }
976                 if (islink)
977                         rc = -EREMOTE;
978         }
979
980 out:
981         for (i = 0; i < ARRAY_SIZE(out_buftype); i++)
982                 free_rsp_buf(out_buftype[i], out_iov[i].iov_base);
983         return rc;
984 }
985
986 int
987 smb2_mkdir(const unsigned int xid, struct inode *parent_inode, umode_t mode,
988            struct cifs_tcon *tcon, const char *name,
989            struct cifs_sb_info *cifs_sb)
990 {
991         struct cifs_open_parms oparms;
992
993         oparms = CIFS_OPARMS(cifs_sb, tcon, name, FILE_WRITE_ATTRIBUTES,
994                              FILE_CREATE, CREATE_NOT_FILE, mode);
995         return smb2_compound_op(xid, tcon, cifs_sb,
996                                 name, &oparms, NULL,
997                                 &(int){SMB2_OP_MKDIR}, 1,
998                                 NULL, NULL, NULL, NULL);
999 }
1000
1001 void
1002 smb2_mkdir_setinfo(struct inode *inode, const char *name,
1003                    struct cifs_sb_info *cifs_sb, struct cifs_tcon *tcon,
1004                    const unsigned int xid)
1005 {
1006         struct cifs_open_parms oparms;
1007         FILE_BASIC_INFO data = {};
1008         struct cifsInodeInfo *cifs_i;
1009         struct cifsFileInfo *cfile;
1010         struct kvec in_iov;
1011         u32 dosattrs;
1012         int tmprc;
1013
1014         in_iov.iov_base = &data;
1015         in_iov.iov_len = sizeof(data);
1016         cifs_i = CIFS_I(inode);
1017         dosattrs = cifs_i->cifsAttrs | ATTR_READONLY;
1018         data.Attributes = cpu_to_le32(dosattrs);
1019         cifs_get_writable_path(tcon, name, FIND_WR_ANY, &cfile);
1020         oparms = CIFS_OPARMS(cifs_sb, tcon, name, FILE_WRITE_ATTRIBUTES,
1021                              FILE_CREATE, CREATE_NOT_FILE, ACL_NO_MODE);
1022         tmprc = smb2_compound_op(xid, tcon, cifs_sb, name,
1023                                  &oparms, &in_iov,
1024                                  &(int){SMB2_OP_SET_INFO}, 1,
1025                                  cfile, NULL, NULL, NULL);
1026         if (tmprc == 0)
1027                 cifs_i->cifsAttrs = dosattrs;
1028 }
1029
1030 int
1031 smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
1032            struct cifs_sb_info *cifs_sb)
1033 {
1034         struct cifs_open_parms oparms;
1035
1036         drop_cached_dir_by_name(xid, tcon, name, cifs_sb);
1037         oparms = CIFS_OPARMS(cifs_sb, tcon, name, DELETE,
1038                              FILE_OPEN, CREATE_NOT_FILE, ACL_NO_MODE);
1039         return smb2_compound_op(xid, tcon, cifs_sb,
1040                                 name, &oparms, NULL,
1041                                 &(int){SMB2_OP_RMDIR}, 1,
1042                                 NULL, NULL, NULL, NULL);
1043 }
1044
1045 int
1046 smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
1047             struct cifs_sb_info *cifs_sb, struct dentry *dentry)
1048 {
1049         struct cifs_open_parms oparms;
1050
1051         oparms = CIFS_OPARMS(cifs_sb, tcon, name,
1052                              DELETE, FILE_OPEN,
1053                              CREATE_DELETE_ON_CLOSE | OPEN_REPARSE_POINT,
1054                              ACL_NO_MODE);
1055         int rc = smb2_compound_op(xid, tcon, cifs_sb, name, &oparms,
1056                                   NULL, &(int){SMB2_OP_DELETE}, 1,
1057                                   NULL, NULL, NULL, dentry);
1058         if (rc == -EINVAL) {
1059                 cifs_dbg(FYI, "invalid lease key, resending request without lease");
1060                 rc = smb2_compound_op(xid, tcon, cifs_sb, name, &oparms,
1061                                       NULL, &(int){SMB2_OP_DELETE}, 1,
1062                                       NULL, NULL, NULL, NULL);
1063         }
1064         return rc;
1065 }
1066
1067 static int smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon,
1068                               const char *from_name, const char *to_name,
1069                               struct cifs_sb_info *cifs_sb,
1070                               __u32 create_options, __u32 access,
1071                               int command, struct cifsFileInfo *cfile,
1072                                   struct dentry *dentry)
1073 {
1074         struct cifs_open_parms oparms;
1075         struct kvec in_iov;
1076         __le16 *smb2_to_name = NULL;
1077         int rc;
1078
1079         smb2_to_name = cifs_convert_path_to_utf16(to_name, cifs_sb);
1080         if (smb2_to_name == NULL) {
1081                 rc = -ENOMEM;
1082                 goto smb2_rename_path;
1083         }
1084         in_iov.iov_base = smb2_to_name;
1085         in_iov.iov_len = 2 * UniStrnlen((wchar_t *)smb2_to_name, PATH_MAX);
1086         oparms = CIFS_OPARMS(cifs_sb, tcon, from_name, access, FILE_OPEN,
1087                              create_options, ACL_NO_MODE);
1088         rc = smb2_compound_op(xid, tcon, cifs_sb, from_name,
1089                               &oparms, &in_iov, &command, 1,
1090                               cfile, NULL, NULL, dentry);
1091 smb2_rename_path:
1092         kfree(smb2_to_name);
1093         return rc;
1094 }
1095
1096 int smb2_rename_path(const unsigned int xid,
1097                      struct cifs_tcon *tcon,
1098                      struct dentry *source_dentry,
1099                      const char *from_name, const char *to_name,
1100                      struct cifs_sb_info *cifs_sb)
1101 {
1102         struct cifsFileInfo *cfile;
1103         __u32 co = file_create_options(source_dentry);
1104
1105         drop_cached_dir_by_name(xid, tcon, from_name, cifs_sb);
1106         cifs_get_writable_path(tcon, from_name, FIND_WR_WITH_DELETE, &cfile);
1107
1108         int rc = smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
1109                                   co, DELETE, SMB2_OP_RENAME, cfile, source_dentry);
1110         if (rc == -EINVAL) {
1111                 cifs_dbg(FYI, "invalid lease key, resending request without lease");
1112                 cifs_get_writable_path(tcon, from_name,
1113                                        FIND_WR_WITH_DELETE, &cfile);
1114                 rc = smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
1115                                   co, DELETE, SMB2_OP_RENAME, cfile, NULL);
1116         }
1117         return rc;
1118 }
1119
1120 int smb2_create_hardlink(const unsigned int xid,
1121                          struct cifs_tcon *tcon,
1122                          struct dentry *source_dentry,
1123                          const char *from_name, const char *to_name,
1124                          struct cifs_sb_info *cifs_sb)
1125 {
1126         __u32 co = file_create_options(source_dentry);
1127
1128         return smb2_set_path_attr(xid, tcon, from_name, to_name,
1129                                   cifs_sb, co, FILE_READ_ATTRIBUTES,
1130                                   SMB2_OP_HARDLINK, NULL, NULL);
1131 }
1132
1133 int
1134 smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
1135                    const char *full_path, __u64 size,
1136                    struct cifs_sb_info *cifs_sb, bool set_alloc,
1137                    struct dentry *dentry)
1138 {
1139         struct cifs_open_parms oparms;
1140         struct cifsFileInfo *cfile;
1141         struct kvec in_iov;
1142         __le64 eof = cpu_to_le64(size);
1143         int rc;
1144
1145         in_iov.iov_base = &eof;
1146         in_iov.iov_len = sizeof(eof);
1147         cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
1148
1149         oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, FILE_WRITE_DATA,
1150                              FILE_OPEN, 0, ACL_NO_MODE);
1151         rc = smb2_compound_op(xid, tcon, cifs_sb,
1152                               full_path, &oparms, &in_iov,
1153                               &(int){SMB2_OP_SET_EOF}, 1,
1154                               cfile, NULL, NULL, dentry);
1155         if (rc == -EINVAL) {
1156                 cifs_dbg(FYI, "invalid lease key, resending request without lease");
1157                 cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
1158                 rc = smb2_compound_op(xid, tcon, cifs_sb,
1159                                       full_path, &oparms, &in_iov,
1160                                       &(int){SMB2_OP_SET_EOF}, 1,
1161                                       cfile, NULL, NULL, NULL);
1162         }
1163         return rc;
1164 }
1165
1166 int
1167 smb2_set_file_info(struct inode *inode, const char *full_path,
1168                    FILE_BASIC_INFO *buf, const unsigned int xid)
1169 {
1170         struct cifs_open_parms oparms;
1171         struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
1172         struct tcon_link *tlink;
1173         struct cifs_tcon *tcon;
1174         struct cifsFileInfo *cfile;
1175         struct kvec in_iov = { .iov_base = buf, .iov_len = sizeof(*buf), };
1176         int rc;
1177
1178         if ((buf->CreationTime == 0) && (buf->LastAccessTime == 0) &&
1179             (buf->LastWriteTime == 0) && (buf->ChangeTime == 0) &&
1180             (buf->Attributes == 0))
1181                 return 0; /* would be a no op, no sense sending this */
1182
1183         tlink = cifs_sb_tlink(cifs_sb);
1184         if (IS_ERR(tlink))
1185                 return PTR_ERR(tlink);
1186         tcon = tlink_tcon(tlink);
1187
1188         cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
1189         oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, FILE_WRITE_ATTRIBUTES,
1190                              FILE_OPEN, 0, ACL_NO_MODE);
1191         rc = smb2_compound_op(xid, tcon, cifs_sb,
1192                               full_path, &oparms, &in_iov,
1193                               &(int){SMB2_OP_SET_INFO}, 1,
1194                               cfile, NULL, NULL, NULL);
1195         cifs_put_tlink(tlink);
1196         return rc;
1197 }
1198
1199 struct inode *smb2_get_reparse_inode(struct cifs_open_info_data *data,
1200                                      struct super_block *sb,
1201                                      const unsigned int xid,
1202                                      struct cifs_tcon *tcon,
1203                                      const char *full_path,
1204                                      bool directory,
1205                                      struct kvec *reparse_iov,
1206                                      struct kvec *xattr_iov)
1207 {
1208         struct cifs_open_parms oparms;
1209         struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
1210         struct cifsFileInfo *cfile;
1211         struct inode *new = NULL;
1212         int out_buftype[4] = {};
1213         struct kvec out_iov[4] = {};
1214         struct kvec in_iov[2];
1215         int cmds[2];
1216         int rc;
1217         int i;
1218
1219         oparms = CIFS_OPARMS(cifs_sb, tcon, full_path,
1220                              SYNCHRONIZE | DELETE |
1221                              FILE_READ_ATTRIBUTES |
1222                              FILE_WRITE_ATTRIBUTES,
1223                              FILE_CREATE,
1224                              (directory ? CREATE_NOT_FILE : CREATE_NOT_DIR) | OPEN_REPARSE_POINT,
1225                              ACL_NO_MODE);
1226         if (xattr_iov)
1227                 oparms.ea_cctx = xattr_iov;
1228
1229         cmds[0] = SMB2_OP_SET_REPARSE;
1230         in_iov[0] = *reparse_iov;
1231         in_iov[1].iov_base = data;
1232         in_iov[1].iov_len = sizeof(*data);
1233
1234         if (tcon->posix_extensions) {
1235                 cmds[1] = SMB2_OP_POSIX_QUERY_INFO;
1236                 cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
1237                 rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, &oparms,
1238                                       in_iov, cmds, 2, cfile, out_iov, out_buftype, NULL);
1239                 if (!rc) {
1240                         rc = smb311_posix_get_inode_info(&new, full_path,
1241                                                          data, sb, xid);
1242                 }
1243         } else {
1244                 cmds[1] = SMB2_OP_QUERY_INFO;
1245                 cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
1246                 rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, &oparms,
1247                                       in_iov, cmds, 2, cfile, out_iov, out_buftype, NULL);
1248                 if (!rc) {
1249                         rc = cifs_get_inode_info(&new, full_path,
1250                                                  data, sb, xid, NULL);
1251                 }
1252         }
1253
1254
1255         /*
1256          * If CREATE was successful but SMB2_OP_SET_REPARSE failed then
1257          * remove the intermediate object created by CREATE. Otherwise
1258          * empty object stay on the server when reparse call failed.
1259          */
1260         if (rc &&
1261             out_iov[0].iov_base != NULL && out_buftype[0] != CIFS_NO_BUFFER &&
1262             ((struct smb2_hdr *)out_iov[0].iov_base)->Status == STATUS_SUCCESS &&
1263             (out_iov[1].iov_base == NULL || out_buftype[1] == CIFS_NO_BUFFER ||
1264              ((struct smb2_hdr *)out_iov[1].iov_base)->Status != STATUS_SUCCESS))
1265                 smb2_unlink(xid, tcon, full_path, cifs_sb, NULL);
1266
1267         for (i = 0; i < ARRAY_SIZE(out_buftype); i++)
1268                 free_rsp_buf(out_buftype[i], out_iov[i].iov_base);
1269
1270         return rc ? ERR_PTR(rc) : new;
1271 }
1272
1273 int smb2_query_reparse_point(const unsigned int xid,
1274                              struct cifs_tcon *tcon,
1275                              struct cifs_sb_info *cifs_sb,
1276                              const char *full_path,
1277                              u32 *tag, struct kvec *rsp,
1278                              int *rsp_buftype)
1279 {
1280         struct cifs_open_parms oparms;
1281         struct cifs_open_info_data data = {};
1282         struct cifsFileInfo *cfile;
1283         struct kvec in_iov = { .iov_base = &data, .iov_len = sizeof(data), };
1284         int rc;
1285
1286         cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path);
1287
1288         cifs_get_readable_path(tcon, full_path, &cfile);
1289         oparms = CIFS_OPARMS(cifs_sb, tcon, full_path,
1290                              FILE_READ_ATTRIBUTES | FILE_READ_EA | SYNCHRONIZE,
1291                              FILE_OPEN, OPEN_REPARSE_POINT, ACL_NO_MODE);
1292         rc = smb2_compound_op(xid, tcon, cifs_sb,
1293                               full_path, &oparms, &in_iov,
1294                               &(int){SMB2_OP_GET_REPARSE}, 1,
1295                               cfile, NULL, NULL, NULL);
1296         if (rc)
1297                 goto out;
1298
1299         *tag = data.reparse.tag;
1300         *rsp = data.reparse.io.iov;
1301         *rsp_buftype = data.reparse.io.buftype;
1302         memset(&data.reparse.io.iov, 0, sizeof(data.reparse.io.iov));
1303         data.reparse.io.buftype = CIFS_NO_BUFFER;
1304 out:
1305         cifs_free_open_info(&data);
1306         return rc;
1307 }
This page took 0.103856 seconds and 4 git commands to generate.