1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * fs/cifs/smb2inode.c
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Copyright (C) International Business Machines Corp., 2002, 2011
5*4882a593Smuzhiyun * Etersoft, 2012
6*4882a593Smuzhiyun * Author(s): Pavel Shilovsky (pshilovsky@samba.org),
7*4882a593Smuzhiyun * Steve French (sfrench@us.ibm.com)
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * This library is free software; you can redistribute it and/or modify
10*4882a593Smuzhiyun * it under the terms of the GNU Lesser General Public License as published
11*4882a593Smuzhiyun * by the Free Software Foundation; either version 2.1 of the License, or
12*4882a593Smuzhiyun * (at your option) any later version.
13*4882a593Smuzhiyun *
14*4882a593Smuzhiyun * This library is distributed in the hope that it will be useful,
15*4882a593Smuzhiyun * but WITHOUT ANY WARRANTY; without even the implied warranty of
16*4882a593Smuzhiyun * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17*4882a593Smuzhiyun * the GNU Lesser General Public License for more details.
18*4882a593Smuzhiyun *
19*4882a593Smuzhiyun * You should have received a copy of the GNU Lesser General Public License
20*4882a593Smuzhiyun * along with this library; if not, write to the Free Software
21*4882a593Smuzhiyun * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22*4882a593Smuzhiyun */
23*4882a593Smuzhiyun #include <linux/fs.h>
24*4882a593Smuzhiyun #include <linux/stat.h>
25*4882a593Smuzhiyun #include <linux/slab.h>
26*4882a593Smuzhiyun #include <linux/pagemap.h>
27*4882a593Smuzhiyun #include <asm/div64.h>
28*4882a593Smuzhiyun #include "cifsfs.h"
29*4882a593Smuzhiyun #include "cifspdu.h"
30*4882a593Smuzhiyun #include "cifsglob.h"
31*4882a593Smuzhiyun #include "cifsproto.h"
32*4882a593Smuzhiyun #include "cifs_debug.h"
33*4882a593Smuzhiyun #include "cifs_fs_sb.h"
34*4882a593Smuzhiyun #include "cifs_unicode.h"
35*4882a593Smuzhiyun #include "fscache.h"
36*4882a593Smuzhiyun #include "smb2glob.h"
37*4882a593Smuzhiyun #include "smb2pdu.h"
38*4882a593Smuzhiyun #include "smb2proto.h"
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun static void
free_set_inf_compound(struct smb_rqst * rqst)41*4882a593Smuzhiyun free_set_inf_compound(struct smb_rqst *rqst)
42*4882a593Smuzhiyun {
43*4882a593Smuzhiyun if (rqst[1].rq_iov)
44*4882a593Smuzhiyun SMB2_set_info_free(&rqst[1]);
45*4882a593Smuzhiyun if (rqst[2].rq_iov)
46*4882a593Smuzhiyun SMB2_close_free(&rqst[2]);
47*4882a593Smuzhiyun }
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun struct cop_vars {
51*4882a593Smuzhiyun struct cifs_open_parms oparms;
52*4882a593Smuzhiyun struct kvec rsp_iov[3];
53*4882a593Smuzhiyun struct smb_rqst rqst[3];
54*4882a593Smuzhiyun struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
55*4882a593Smuzhiyun struct kvec qi_iov[1];
56*4882a593Smuzhiyun struct kvec si_iov[SMB2_SET_INFO_IOV_SIZE];
57*4882a593Smuzhiyun struct kvec close_iov[1];
58*4882a593Smuzhiyun struct smb2_file_rename_info rename_info;
59*4882a593Smuzhiyun struct smb2_file_link_info link_info;
60*4882a593Smuzhiyun };
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun static int
smb2_compound_op(const unsigned int xid,struct cifs_tcon * tcon,struct cifs_sb_info * cifs_sb,const char * full_path,__u32 desired_access,__u32 create_disposition,__u32 create_options,umode_t mode,void * ptr,int command,struct cifsFileInfo * cfile)63*4882a593Smuzhiyun smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
64*4882a593Smuzhiyun struct cifs_sb_info *cifs_sb, const char *full_path,
65*4882a593Smuzhiyun __u32 desired_access, __u32 create_disposition,
66*4882a593Smuzhiyun __u32 create_options, umode_t mode, void *ptr, int command,
67*4882a593Smuzhiyun struct cifsFileInfo *cfile)
68*4882a593Smuzhiyun {
69*4882a593Smuzhiyun struct cop_vars *vars = NULL;
70*4882a593Smuzhiyun struct kvec *rsp_iov;
71*4882a593Smuzhiyun struct smb_rqst *rqst;
72*4882a593Smuzhiyun int rc;
73*4882a593Smuzhiyun __le16 *utf16_path = NULL;
74*4882a593Smuzhiyun __u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
75*4882a593Smuzhiyun struct cifs_fid fid;
76*4882a593Smuzhiyun struct cifs_ses *ses = tcon->ses;
77*4882a593Smuzhiyun struct TCP_Server_Info *server;
78*4882a593Smuzhiyun int num_rqst = 0;
79*4882a593Smuzhiyun int resp_buftype[3];
80*4882a593Smuzhiyun struct smb2_query_info_rsp *qi_rsp = NULL;
81*4882a593Smuzhiyun int flags = 0;
82*4882a593Smuzhiyun __u8 delete_pending[8] = {1, 0, 0, 0, 0, 0, 0, 0};
83*4882a593Smuzhiyun unsigned int size[2];
84*4882a593Smuzhiyun void *data[2];
85*4882a593Smuzhiyun int len;
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun vars = kzalloc(sizeof(*vars), GFP_ATOMIC);
88*4882a593Smuzhiyun if (vars == NULL)
89*4882a593Smuzhiyun return -ENOMEM;
90*4882a593Smuzhiyun rqst = &vars->rqst[0];
91*4882a593Smuzhiyun rsp_iov = &vars->rsp_iov[0];
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun server = cifs_pick_channel(ses);
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun if (smb3_encryption_required(tcon))
96*4882a593Smuzhiyun flags |= CIFS_TRANSFORM_REQ;
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun /* We already have a handle so we can skip the open */
101*4882a593Smuzhiyun if (cfile)
102*4882a593Smuzhiyun goto after_open;
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun /* Open */
105*4882a593Smuzhiyun utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
106*4882a593Smuzhiyun if (!utf16_path) {
107*4882a593Smuzhiyun rc = -ENOMEM;
108*4882a593Smuzhiyun goto finished;
109*4882a593Smuzhiyun }
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun vars->oparms.tcon = tcon;
112*4882a593Smuzhiyun vars->oparms.desired_access = desired_access;
113*4882a593Smuzhiyun vars->oparms.disposition = create_disposition;
114*4882a593Smuzhiyun vars->oparms.create_options = cifs_create_options(cifs_sb, create_options);
115*4882a593Smuzhiyun vars->oparms.fid = &fid;
116*4882a593Smuzhiyun vars->oparms.reconnect = false;
117*4882a593Smuzhiyun vars->oparms.mode = mode;
118*4882a593Smuzhiyun vars->oparms.cifs_sb = cifs_sb;
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun rqst[num_rqst].rq_iov = &vars->open_iov[0];
121*4882a593Smuzhiyun rqst[num_rqst].rq_nvec = SMB2_CREATE_IOV_SIZE;
122*4882a593Smuzhiyun rc = SMB2_open_init(tcon, server,
123*4882a593Smuzhiyun &rqst[num_rqst], &oplock, &vars->oparms,
124*4882a593Smuzhiyun utf16_path);
125*4882a593Smuzhiyun kfree(utf16_path);
126*4882a593Smuzhiyun if (rc)
127*4882a593Smuzhiyun goto finished;
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun smb2_set_next_command(tcon, &rqst[num_rqst]);
130*4882a593Smuzhiyun after_open:
131*4882a593Smuzhiyun num_rqst++;
132*4882a593Smuzhiyun rc = 0;
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun /* Operation */
135*4882a593Smuzhiyun switch (command) {
136*4882a593Smuzhiyun case SMB2_OP_QUERY_INFO:
137*4882a593Smuzhiyun rqst[num_rqst].rq_iov = &vars->qi_iov[0];
138*4882a593Smuzhiyun rqst[num_rqst].rq_nvec = 1;
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun if (cfile)
141*4882a593Smuzhiyun rc = SMB2_query_info_init(tcon, server,
142*4882a593Smuzhiyun &rqst[num_rqst],
143*4882a593Smuzhiyun cfile->fid.persistent_fid,
144*4882a593Smuzhiyun cfile->fid.volatile_fid,
145*4882a593Smuzhiyun FILE_ALL_INFORMATION,
146*4882a593Smuzhiyun SMB2_O_INFO_FILE, 0,
147*4882a593Smuzhiyun sizeof(struct smb2_file_all_info) +
148*4882a593Smuzhiyun PATH_MAX * 2, 0, NULL);
149*4882a593Smuzhiyun else {
150*4882a593Smuzhiyun rc = SMB2_query_info_init(tcon, server,
151*4882a593Smuzhiyun &rqst[num_rqst],
152*4882a593Smuzhiyun COMPOUND_FID,
153*4882a593Smuzhiyun COMPOUND_FID,
154*4882a593Smuzhiyun FILE_ALL_INFORMATION,
155*4882a593Smuzhiyun SMB2_O_INFO_FILE, 0,
156*4882a593Smuzhiyun sizeof(struct smb2_file_all_info) +
157*4882a593Smuzhiyun PATH_MAX * 2, 0, NULL);
158*4882a593Smuzhiyun if (!rc) {
159*4882a593Smuzhiyun smb2_set_next_command(tcon, &rqst[num_rqst]);
160*4882a593Smuzhiyun smb2_set_related(&rqst[num_rqst]);
161*4882a593Smuzhiyun }
162*4882a593Smuzhiyun }
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun if (rc)
165*4882a593Smuzhiyun goto finished;
166*4882a593Smuzhiyun num_rqst++;
167*4882a593Smuzhiyun trace_smb3_query_info_compound_enter(xid, ses->Suid, tcon->tid,
168*4882a593Smuzhiyun full_path);
169*4882a593Smuzhiyun break;
170*4882a593Smuzhiyun case SMB2_OP_POSIX_QUERY_INFO:
171*4882a593Smuzhiyun rqst[num_rqst].rq_iov = &vars->qi_iov[0];
172*4882a593Smuzhiyun rqst[num_rqst].rq_nvec = 1;
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun if (cfile)
175*4882a593Smuzhiyun rc = SMB2_query_info_init(tcon, server,
176*4882a593Smuzhiyun &rqst[num_rqst],
177*4882a593Smuzhiyun cfile->fid.persistent_fid,
178*4882a593Smuzhiyun cfile->fid.volatile_fid,
179*4882a593Smuzhiyun SMB_FIND_FILE_POSIX_INFO,
180*4882a593Smuzhiyun SMB2_O_INFO_FILE, 0,
181*4882a593Smuzhiyun /* TBD: fix following to allow for longer SIDs */
182*4882a593Smuzhiyun sizeof(struct smb311_posix_qinfo *) + (PATH_MAX * 2) +
183*4882a593Smuzhiyun (sizeof(struct cifs_sid) * 2), 0, NULL);
184*4882a593Smuzhiyun else {
185*4882a593Smuzhiyun rc = SMB2_query_info_init(tcon, server,
186*4882a593Smuzhiyun &rqst[num_rqst],
187*4882a593Smuzhiyun COMPOUND_FID,
188*4882a593Smuzhiyun COMPOUND_FID,
189*4882a593Smuzhiyun SMB_FIND_FILE_POSIX_INFO,
190*4882a593Smuzhiyun SMB2_O_INFO_FILE, 0,
191*4882a593Smuzhiyun sizeof(struct smb311_posix_qinfo *) + (PATH_MAX * 2) +
192*4882a593Smuzhiyun (sizeof(struct cifs_sid) * 2), 0, NULL);
193*4882a593Smuzhiyun if (!rc) {
194*4882a593Smuzhiyun smb2_set_next_command(tcon, &rqst[num_rqst]);
195*4882a593Smuzhiyun smb2_set_related(&rqst[num_rqst]);
196*4882a593Smuzhiyun }
197*4882a593Smuzhiyun }
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun if (rc)
200*4882a593Smuzhiyun goto finished;
201*4882a593Smuzhiyun num_rqst++;
202*4882a593Smuzhiyun trace_smb3_posix_query_info_compound_enter(xid, ses->Suid, tcon->tid, full_path);
203*4882a593Smuzhiyun break;
204*4882a593Smuzhiyun case SMB2_OP_DELETE:
205*4882a593Smuzhiyun trace_smb3_delete_enter(xid, ses->Suid, tcon->tid, full_path);
206*4882a593Smuzhiyun break;
207*4882a593Smuzhiyun case SMB2_OP_MKDIR:
208*4882a593Smuzhiyun /*
209*4882a593Smuzhiyun * Directories are created through parameters in the
210*4882a593Smuzhiyun * SMB2_open() call.
211*4882a593Smuzhiyun */
212*4882a593Smuzhiyun trace_smb3_mkdir_enter(xid, ses->Suid, tcon->tid, full_path);
213*4882a593Smuzhiyun break;
214*4882a593Smuzhiyun case SMB2_OP_RMDIR:
215*4882a593Smuzhiyun rqst[num_rqst].rq_iov = &vars->si_iov[0];
216*4882a593Smuzhiyun rqst[num_rqst].rq_nvec = 1;
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun size[0] = 1; /* sizeof __u8 See MS-FSCC section 2.4.11 */
219*4882a593Smuzhiyun data[0] = &delete_pending[0];
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun rc = SMB2_set_info_init(tcon, server,
222*4882a593Smuzhiyun &rqst[num_rqst], COMPOUND_FID,
223*4882a593Smuzhiyun COMPOUND_FID, current->tgid,
224*4882a593Smuzhiyun FILE_DISPOSITION_INFORMATION,
225*4882a593Smuzhiyun SMB2_O_INFO_FILE, 0, data, size);
226*4882a593Smuzhiyun if (rc)
227*4882a593Smuzhiyun goto finished;
228*4882a593Smuzhiyun smb2_set_next_command(tcon, &rqst[num_rqst]);
229*4882a593Smuzhiyun smb2_set_related(&rqst[num_rqst++]);
230*4882a593Smuzhiyun trace_smb3_rmdir_enter(xid, ses->Suid, tcon->tid, full_path);
231*4882a593Smuzhiyun break;
232*4882a593Smuzhiyun case SMB2_OP_SET_EOF:
233*4882a593Smuzhiyun rqst[num_rqst].rq_iov = &vars->si_iov[0];
234*4882a593Smuzhiyun rqst[num_rqst].rq_nvec = 1;
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun size[0] = 8; /* sizeof __le64 */
237*4882a593Smuzhiyun data[0] = ptr;
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun rc = SMB2_set_info_init(tcon, server,
240*4882a593Smuzhiyun &rqst[num_rqst], COMPOUND_FID,
241*4882a593Smuzhiyun COMPOUND_FID, current->tgid,
242*4882a593Smuzhiyun FILE_END_OF_FILE_INFORMATION,
243*4882a593Smuzhiyun SMB2_O_INFO_FILE, 0, data, size);
244*4882a593Smuzhiyun if (rc)
245*4882a593Smuzhiyun goto finished;
246*4882a593Smuzhiyun smb2_set_next_command(tcon, &rqst[num_rqst]);
247*4882a593Smuzhiyun smb2_set_related(&rqst[num_rqst++]);
248*4882a593Smuzhiyun trace_smb3_set_eof_enter(xid, ses->Suid, tcon->tid, full_path);
249*4882a593Smuzhiyun break;
250*4882a593Smuzhiyun case SMB2_OP_SET_INFO:
251*4882a593Smuzhiyun rqst[num_rqst].rq_iov = &vars->si_iov[0];
252*4882a593Smuzhiyun rqst[num_rqst].rq_nvec = 1;
253*4882a593Smuzhiyun
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun size[0] = sizeof(FILE_BASIC_INFO);
256*4882a593Smuzhiyun data[0] = ptr;
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun if (cfile)
259*4882a593Smuzhiyun rc = SMB2_set_info_init(tcon, server,
260*4882a593Smuzhiyun &rqst[num_rqst],
261*4882a593Smuzhiyun cfile->fid.persistent_fid,
262*4882a593Smuzhiyun cfile->fid.volatile_fid, current->tgid,
263*4882a593Smuzhiyun FILE_BASIC_INFORMATION,
264*4882a593Smuzhiyun SMB2_O_INFO_FILE, 0, data, size);
265*4882a593Smuzhiyun else {
266*4882a593Smuzhiyun rc = SMB2_set_info_init(tcon, server,
267*4882a593Smuzhiyun &rqst[num_rqst],
268*4882a593Smuzhiyun COMPOUND_FID,
269*4882a593Smuzhiyun COMPOUND_FID, current->tgid,
270*4882a593Smuzhiyun FILE_BASIC_INFORMATION,
271*4882a593Smuzhiyun SMB2_O_INFO_FILE, 0, data, size);
272*4882a593Smuzhiyun if (!rc) {
273*4882a593Smuzhiyun smb2_set_next_command(tcon, &rqst[num_rqst]);
274*4882a593Smuzhiyun smb2_set_related(&rqst[num_rqst]);
275*4882a593Smuzhiyun }
276*4882a593Smuzhiyun }
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun if (rc)
279*4882a593Smuzhiyun goto finished;
280*4882a593Smuzhiyun num_rqst++;
281*4882a593Smuzhiyun trace_smb3_set_info_compound_enter(xid, ses->Suid, tcon->tid,
282*4882a593Smuzhiyun full_path);
283*4882a593Smuzhiyun break;
284*4882a593Smuzhiyun case SMB2_OP_RENAME:
285*4882a593Smuzhiyun rqst[num_rqst].rq_iov = &vars->si_iov[0];
286*4882a593Smuzhiyun rqst[num_rqst].rq_nvec = 2;
287*4882a593Smuzhiyun
288*4882a593Smuzhiyun len = (2 * UniStrnlen((wchar_t *)ptr, PATH_MAX));
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun vars->rename_info.ReplaceIfExists = 1;
291*4882a593Smuzhiyun vars->rename_info.RootDirectory = 0;
292*4882a593Smuzhiyun vars->rename_info.FileNameLength = cpu_to_le32(len);
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun size[0] = sizeof(struct smb2_file_rename_info);
295*4882a593Smuzhiyun data[0] = &vars->rename_info;
296*4882a593Smuzhiyun
297*4882a593Smuzhiyun size[1] = len + 2 /* null */;
298*4882a593Smuzhiyun data[1] = (__le16 *)ptr;
299*4882a593Smuzhiyun
300*4882a593Smuzhiyun if (cfile)
301*4882a593Smuzhiyun rc = SMB2_set_info_init(tcon, server,
302*4882a593Smuzhiyun &rqst[num_rqst],
303*4882a593Smuzhiyun cfile->fid.persistent_fid,
304*4882a593Smuzhiyun cfile->fid.volatile_fid,
305*4882a593Smuzhiyun current->tgid, FILE_RENAME_INFORMATION,
306*4882a593Smuzhiyun SMB2_O_INFO_FILE, 0, data, size);
307*4882a593Smuzhiyun else {
308*4882a593Smuzhiyun rc = SMB2_set_info_init(tcon, server,
309*4882a593Smuzhiyun &rqst[num_rqst],
310*4882a593Smuzhiyun COMPOUND_FID, COMPOUND_FID,
311*4882a593Smuzhiyun current->tgid, FILE_RENAME_INFORMATION,
312*4882a593Smuzhiyun SMB2_O_INFO_FILE, 0, data, size);
313*4882a593Smuzhiyun if (!rc) {
314*4882a593Smuzhiyun smb2_set_next_command(tcon, &rqst[num_rqst]);
315*4882a593Smuzhiyun smb2_set_related(&rqst[num_rqst]);
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun }
318*4882a593Smuzhiyun if (rc)
319*4882a593Smuzhiyun goto finished;
320*4882a593Smuzhiyun num_rqst++;
321*4882a593Smuzhiyun trace_smb3_rename_enter(xid, ses->Suid, tcon->tid, full_path);
322*4882a593Smuzhiyun break;
323*4882a593Smuzhiyun case SMB2_OP_HARDLINK:
324*4882a593Smuzhiyun rqst[num_rqst].rq_iov = &vars->si_iov[0];
325*4882a593Smuzhiyun rqst[num_rqst].rq_nvec = 2;
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun len = (2 * UniStrnlen((wchar_t *)ptr, PATH_MAX));
328*4882a593Smuzhiyun
329*4882a593Smuzhiyun vars->link_info.ReplaceIfExists = 0;
330*4882a593Smuzhiyun vars->link_info.RootDirectory = 0;
331*4882a593Smuzhiyun vars->link_info.FileNameLength = cpu_to_le32(len);
332*4882a593Smuzhiyun
333*4882a593Smuzhiyun size[0] = sizeof(struct smb2_file_link_info);
334*4882a593Smuzhiyun data[0] = &vars->link_info;
335*4882a593Smuzhiyun
336*4882a593Smuzhiyun size[1] = len + 2 /* null */;
337*4882a593Smuzhiyun data[1] = (__le16 *)ptr;
338*4882a593Smuzhiyun
339*4882a593Smuzhiyun rc = SMB2_set_info_init(tcon, server,
340*4882a593Smuzhiyun &rqst[num_rqst], COMPOUND_FID,
341*4882a593Smuzhiyun COMPOUND_FID, current->tgid,
342*4882a593Smuzhiyun FILE_LINK_INFORMATION,
343*4882a593Smuzhiyun SMB2_O_INFO_FILE, 0, data, size);
344*4882a593Smuzhiyun if (rc)
345*4882a593Smuzhiyun goto finished;
346*4882a593Smuzhiyun smb2_set_next_command(tcon, &rqst[num_rqst]);
347*4882a593Smuzhiyun smb2_set_related(&rqst[num_rqst++]);
348*4882a593Smuzhiyun trace_smb3_hardlink_enter(xid, ses->Suid, tcon->tid, full_path);
349*4882a593Smuzhiyun break;
350*4882a593Smuzhiyun default:
351*4882a593Smuzhiyun cifs_dbg(VFS, "Invalid command\n");
352*4882a593Smuzhiyun rc = -EINVAL;
353*4882a593Smuzhiyun }
354*4882a593Smuzhiyun if (rc)
355*4882a593Smuzhiyun goto finished;
356*4882a593Smuzhiyun
357*4882a593Smuzhiyun /* We already have a handle so we can skip the close */
358*4882a593Smuzhiyun if (cfile)
359*4882a593Smuzhiyun goto after_close;
360*4882a593Smuzhiyun /* Close */
361*4882a593Smuzhiyun flags |= CIFS_CP_CREATE_CLOSE_OP;
362*4882a593Smuzhiyun rqst[num_rqst].rq_iov = &vars->close_iov[0];
363*4882a593Smuzhiyun rqst[num_rqst].rq_nvec = 1;
364*4882a593Smuzhiyun rc = SMB2_close_init(tcon, server,
365*4882a593Smuzhiyun &rqst[num_rqst], COMPOUND_FID,
366*4882a593Smuzhiyun COMPOUND_FID, false);
367*4882a593Smuzhiyun smb2_set_related(&rqst[num_rqst]);
368*4882a593Smuzhiyun if (rc)
369*4882a593Smuzhiyun goto finished;
370*4882a593Smuzhiyun after_close:
371*4882a593Smuzhiyun num_rqst++;
372*4882a593Smuzhiyun
373*4882a593Smuzhiyun if (cfile) {
374*4882a593Smuzhiyun rc = compound_send_recv(xid, ses, server,
375*4882a593Smuzhiyun flags, num_rqst - 2,
376*4882a593Smuzhiyun &rqst[1], &resp_buftype[1],
377*4882a593Smuzhiyun &rsp_iov[1]);
378*4882a593Smuzhiyun } else
379*4882a593Smuzhiyun rc = compound_send_recv(xid, ses, server,
380*4882a593Smuzhiyun flags, num_rqst,
381*4882a593Smuzhiyun rqst, resp_buftype,
382*4882a593Smuzhiyun rsp_iov);
383*4882a593Smuzhiyun
384*4882a593Smuzhiyun finished:
385*4882a593Smuzhiyun if (cfile)
386*4882a593Smuzhiyun cifsFileInfo_put(cfile);
387*4882a593Smuzhiyun
388*4882a593Smuzhiyun SMB2_open_free(&rqst[0]);
389*4882a593Smuzhiyun if (rc == -EREMCHG) {
390*4882a593Smuzhiyun pr_warn_once("server share %s deleted\n", tcon->treeName);
391*4882a593Smuzhiyun tcon->need_reconnect = true;
392*4882a593Smuzhiyun }
393*4882a593Smuzhiyun
394*4882a593Smuzhiyun switch (command) {
395*4882a593Smuzhiyun case SMB2_OP_QUERY_INFO:
396*4882a593Smuzhiyun if (rc == 0) {
397*4882a593Smuzhiyun qi_rsp = (struct smb2_query_info_rsp *)
398*4882a593Smuzhiyun rsp_iov[1].iov_base;
399*4882a593Smuzhiyun rc = smb2_validate_and_copy_iov(
400*4882a593Smuzhiyun le16_to_cpu(qi_rsp->OutputBufferOffset),
401*4882a593Smuzhiyun le32_to_cpu(qi_rsp->OutputBufferLength),
402*4882a593Smuzhiyun &rsp_iov[1], sizeof(struct smb2_file_all_info),
403*4882a593Smuzhiyun ptr);
404*4882a593Smuzhiyun }
405*4882a593Smuzhiyun if (rqst[1].rq_iov)
406*4882a593Smuzhiyun SMB2_query_info_free(&rqst[1]);
407*4882a593Smuzhiyun if (rqst[2].rq_iov)
408*4882a593Smuzhiyun SMB2_close_free(&rqst[2]);
409*4882a593Smuzhiyun if (rc)
410*4882a593Smuzhiyun trace_smb3_query_info_compound_err(xid, ses->Suid,
411*4882a593Smuzhiyun tcon->tid, rc);
412*4882a593Smuzhiyun else
413*4882a593Smuzhiyun trace_smb3_query_info_compound_done(xid, ses->Suid,
414*4882a593Smuzhiyun tcon->tid);
415*4882a593Smuzhiyun break;
416*4882a593Smuzhiyun case SMB2_OP_POSIX_QUERY_INFO:
417*4882a593Smuzhiyun if (rc == 0) {
418*4882a593Smuzhiyun qi_rsp = (struct smb2_query_info_rsp *)
419*4882a593Smuzhiyun rsp_iov[1].iov_base;
420*4882a593Smuzhiyun rc = smb2_validate_and_copy_iov(
421*4882a593Smuzhiyun le16_to_cpu(qi_rsp->OutputBufferOffset),
422*4882a593Smuzhiyun le32_to_cpu(qi_rsp->OutputBufferLength),
423*4882a593Smuzhiyun &rsp_iov[1], sizeof(struct smb311_posix_qinfo) /* add SIDs */, ptr);
424*4882a593Smuzhiyun }
425*4882a593Smuzhiyun if (rqst[1].rq_iov)
426*4882a593Smuzhiyun SMB2_query_info_free(&rqst[1]);
427*4882a593Smuzhiyun if (rqst[2].rq_iov)
428*4882a593Smuzhiyun SMB2_close_free(&rqst[2]);
429*4882a593Smuzhiyun if (rc)
430*4882a593Smuzhiyun trace_smb3_posix_query_info_compound_err(xid, ses->Suid, tcon->tid, rc);
431*4882a593Smuzhiyun else
432*4882a593Smuzhiyun trace_smb3_posix_query_info_compound_done(xid, ses->Suid, tcon->tid);
433*4882a593Smuzhiyun break;
434*4882a593Smuzhiyun case SMB2_OP_DELETE:
435*4882a593Smuzhiyun if (rc)
436*4882a593Smuzhiyun trace_smb3_delete_err(xid, ses->Suid, tcon->tid, rc);
437*4882a593Smuzhiyun else
438*4882a593Smuzhiyun trace_smb3_delete_done(xid, ses->Suid, tcon->tid);
439*4882a593Smuzhiyun if (rqst[1].rq_iov)
440*4882a593Smuzhiyun SMB2_close_free(&rqst[1]);
441*4882a593Smuzhiyun break;
442*4882a593Smuzhiyun case SMB2_OP_MKDIR:
443*4882a593Smuzhiyun if (rc)
444*4882a593Smuzhiyun trace_smb3_mkdir_err(xid, ses->Suid, tcon->tid, rc);
445*4882a593Smuzhiyun else
446*4882a593Smuzhiyun trace_smb3_mkdir_done(xid, ses->Suid, tcon->tid);
447*4882a593Smuzhiyun if (rqst[1].rq_iov)
448*4882a593Smuzhiyun SMB2_close_free(&rqst[1]);
449*4882a593Smuzhiyun break;
450*4882a593Smuzhiyun case SMB2_OP_HARDLINK:
451*4882a593Smuzhiyun if (rc)
452*4882a593Smuzhiyun trace_smb3_hardlink_err(xid, ses->Suid, tcon->tid, rc);
453*4882a593Smuzhiyun else
454*4882a593Smuzhiyun trace_smb3_hardlink_done(xid, ses->Suid, tcon->tid);
455*4882a593Smuzhiyun free_set_inf_compound(rqst);
456*4882a593Smuzhiyun break;
457*4882a593Smuzhiyun case SMB2_OP_RENAME:
458*4882a593Smuzhiyun if (rc)
459*4882a593Smuzhiyun trace_smb3_rename_err(xid, ses->Suid, tcon->tid, rc);
460*4882a593Smuzhiyun else
461*4882a593Smuzhiyun trace_smb3_rename_done(xid, ses->Suid, tcon->tid);
462*4882a593Smuzhiyun free_set_inf_compound(rqst);
463*4882a593Smuzhiyun break;
464*4882a593Smuzhiyun case SMB2_OP_RMDIR:
465*4882a593Smuzhiyun if (rc)
466*4882a593Smuzhiyun trace_smb3_rmdir_err(xid, ses->Suid, tcon->tid, rc);
467*4882a593Smuzhiyun else
468*4882a593Smuzhiyun trace_smb3_rmdir_done(xid, ses->Suid, tcon->tid);
469*4882a593Smuzhiyun free_set_inf_compound(rqst);
470*4882a593Smuzhiyun break;
471*4882a593Smuzhiyun case SMB2_OP_SET_EOF:
472*4882a593Smuzhiyun if (rc)
473*4882a593Smuzhiyun trace_smb3_set_eof_err(xid, ses->Suid, tcon->tid, rc);
474*4882a593Smuzhiyun else
475*4882a593Smuzhiyun trace_smb3_set_eof_done(xid, ses->Suid, tcon->tid);
476*4882a593Smuzhiyun free_set_inf_compound(rqst);
477*4882a593Smuzhiyun break;
478*4882a593Smuzhiyun case SMB2_OP_SET_INFO:
479*4882a593Smuzhiyun if (rc)
480*4882a593Smuzhiyun trace_smb3_set_info_compound_err(xid, ses->Suid,
481*4882a593Smuzhiyun tcon->tid, rc);
482*4882a593Smuzhiyun else
483*4882a593Smuzhiyun trace_smb3_set_info_compound_done(xid, ses->Suid,
484*4882a593Smuzhiyun tcon->tid);
485*4882a593Smuzhiyun free_set_inf_compound(rqst);
486*4882a593Smuzhiyun break;
487*4882a593Smuzhiyun }
488*4882a593Smuzhiyun free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
489*4882a593Smuzhiyun free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
490*4882a593Smuzhiyun free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base);
491*4882a593Smuzhiyun kfree(vars);
492*4882a593Smuzhiyun return rc;
493*4882a593Smuzhiyun }
494*4882a593Smuzhiyun
495*4882a593Smuzhiyun void
move_smb2_info_to_cifs(FILE_ALL_INFO * dst,struct smb2_file_all_info * src)496*4882a593Smuzhiyun move_smb2_info_to_cifs(FILE_ALL_INFO *dst, struct smb2_file_all_info *src)
497*4882a593Smuzhiyun {
498*4882a593Smuzhiyun memcpy(dst, src, (size_t)(&src->CurrentByteOffset) - (size_t)src);
499*4882a593Smuzhiyun dst->CurrentByteOffset = src->CurrentByteOffset;
500*4882a593Smuzhiyun dst->Mode = src->Mode;
501*4882a593Smuzhiyun dst->AlignmentRequirement = src->AlignmentRequirement;
502*4882a593Smuzhiyun dst->IndexNumber1 = 0; /* we don't use it */
503*4882a593Smuzhiyun }
504*4882a593Smuzhiyun
505*4882a593Smuzhiyun int
smb2_query_path_info(const unsigned int xid,struct cifs_tcon * tcon,struct cifs_sb_info * cifs_sb,const char * full_path,FILE_ALL_INFO * data,bool * adjust_tz,bool * reparse)506*4882a593Smuzhiyun smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
507*4882a593Smuzhiyun struct cifs_sb_info *cifs_sb, const char *full_path,
508*4882a593Smuzhiyun FILE_ALL_INFO *data, bool *adjust_tz, bool *reparse)
509*4882a593Smuzhiyun {
510*4882a593Smuzhiyun int rc;
511*4882a593Smuzhiyun struct smb2_file_all_info *smb2_data;
512*4882a593Smuzhiyun __u32 create_options = 0;
513*4882a593Smuzhiyun bool no_cached_open = tcon->nohandlecache;
514*4882a593Smuzhiyun struct cifsFileInfo *cfile;
515*4882a593Smuzhiyun struct cached_fid *cfid = NULL;
516*4882a593Smuzhiyun
517*4882a593Smuzhiyun *adjust_tz = false;
518*4882a593Smuzhiyun *reparse = false;
519*4882a593Smuzhiyun
520*4882a593Smuzhiyun smb2_data = kzalloc(sizeof(struct smb2_file_all_info) + PATH_MAX * 2,
521*4882a593Smuzhiyun GFP_KERNEL);
522*4882a593Smuzhiyun if (smb2_data == NULL)
523*4882a593Smuzhiyun return -ENOMEM;
524*4882a593Smuzhiyun
525*4882a593Smuzhiyun /* If it is a root and its handle is cached then use it */
526*4882a593Smuzhiyun if (!strlen(full_path) && !no_cached_open) {
527*4882a593Smuzhiyun rc = open_shroot(xid, tcon, cifs_sb, &cfid);
528*4882a593Smuzhiyun if (rc)
529*4882a593Smuzhiyun goto out;
530*4882a593Smuzhiyun
531*4882a593Smuzhiyun if (tcon->crfid.file_all_info_is_valid) {
532*4882a593Smuzhiyun move_smb2_info_to_cifs(data,
533*4882a593Smuzhiyun &tcon->crfid.file_all_info);
534*4882a593Smuzhiyun } else {
535*4882a593Smuzhiyun rc = SMB2_query_info(xid, tcon,
536*4882a593Smuzhiyun cfid->fid->persistent_fid,
537*4882a593Smuzhiyun cfid->fid->volatile_fid, smb2_data);
538*4882a593Smuzhiyun if (!rc)
539*4882a593Smuzhiyun move_smb2_info_to_cifs(data, smb2_data);
540*4882a593Smuzhiyun }
541*4882a593Smuzhiyun close_shroot(cfid);
542*4882a593Smuzhiyun goto out;
543*4882a593Smuzhiyun }
544*4882a593Smuzhiyun
545*4882a593Smuzhiyun cifs_get_readable_path(tcon, full_path, &cfile);
546*4882a593Smuzhiyun rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
547*4882a593Smuzhiyun FILE_READ_ATTRIBUTES, FILE_OPEN, create_options,
548*4882a593Smuzhiyun ACL_NO_MODE, smb2_data, SMB2_OP_QUERY_INFO, cfile);
549*4882a593Smuzhiyun if (rc == -EOPNOTSUPP) {
550*4882a593Smuzhiyun *reparse = true;
551*4882a593Smuzhiyun create_options |= OPEN_REPARSE_POINT;
552*4882a593Smuzhiyun
553*4882a593Smuzhiyun /* Failed on a symbolic link - query a reparse point info */
554*4882a593Smuzhiyun rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
555*4882a593Smuzhiyun FILE_READ_ATTRIBUTES, FILE_OPEN,
556*4882a593Smuzhiyun create_options, ACL_NO_MODE,
557*4882a593Smuzhiyun smb2_data, SMB2_OP_QUERY_INFO, NULL);
558*4882a593Smuzhiyun }
559*4882a593Smuzhiyun if (rc)
560*4882a593Smuzhiyun goto out;
561*4882a593Smuzhiyun
562*4882a593Smuzhiyun move_smb2_info_to_cifs(data, smb2_data);
563*4882a593Smuzhiyun out:
564*4882a593Smuzhiyun kfree(smb2_data);
565*4882a593Smuzhiyun return rc;
566*4882a593Smuzhiyun }
567*4882a593Smuzhiyun
568*4882a593Smuzhiyun
569*4882a593Smuzhiyun int
smb311_posix_query_path_info(const unsigned int xid,struct cifs_tcon * tcon,struct cifs_sb_info * cifs_sb,const char * full_path,struct smb311_posix_qinfo * data,bool * adjust_tz,bool * reparse)570*4882a593Smuzhiyun smb311_posix_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
571*4882a593Smuzhiyun struct cifs_sb_info *cifs_sb, const char *full_path,
572*4882a593Smuzhiyun struct smb311_posix_qinfo *data, bool *adjust_tz, bool *reparse)
573*4882a593Smuzhiyun {
574*4882a593Smuzhiyun int rc;
575*4882a593Smuzhiyun __u32 create_options = 0;
576*4882a593Smuzhiyun struct cifsFileInfo *cfile;
577*4882a593Smuzhiyun struct smb311_posix_qinfo *smb2_data;
578*4882a593Smuzhiyun
579*4882a593Smuzhiyun *adjust_tz = false;
580*4882a593Smuzhiyun *reparse = false;
581*4882a593Smuzhiyun
582*4882a593Smuzhiyun /* BB TODO: Make struct larger when add support for parsing owner SIDs */
583*4882a593Smuzhiyun smb2_data = kzalloc(sizeof(struct smb311_posix_qinfo),
584*4882a593Smuzhiyun GFP_KERNEL);
585*4882a593Smuzhiyun if (smb2_data == NULL)
586*4882a593Smuzhiyun return -ENOMEM;
587*4882a593Smuzhiyun
588*4882a593Smuzhiyun /*
589*4882a593Smuzhiyun * BB TODO: Add support for using the cached root handle.
590*4882a593Smuzhiyun * Create SMB2_query_posix_info worker function to do non-compounded query
591*4882a593Smuzhiyun * when we already have an open file handle for this. For now this is fast enough
592*4882a593Smuzhiyun * (always using the compounded version).
593*4882a593Smuzhiyun */
594*4882a593Smuzhiyun
595*4882a593Smuzhiyun cifs_get_readable_path(tcon, full_path, &cfile);
596*4882a593Smuzhiyun rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
597*4882a593Smuzhiyun FILE_READ_ATTRIBUTES, FILE_OPEN, create_options,
598*4882a593Smuzhiyun ACL_NO_MODE, smb2_data, SMB2_OP_POSIX_QUERY_INFO, cfile);
599*4882a593Smuzhiyun if (rc == -EOPNOTSUPP) {
600*4882a593Smuzhiyun /* BB TODO: When support for special files added to Samba re-verify this path */
601*4882a593Smuzhiyun *reparse = true;
602*4882a593Smuzhiyun create_options |= OPEN_REPARSE_POINT;
603*4882a593Smuzhiyun
604*4882a593Smuzhiyun /* Failed on a symbolic link - query a reparse point info */
605*4882a593Smuzhiyun rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
606*4882a593Smuzhiyun FILE_READ_ATTRIBUTES, FILE_OPEN,
607*4882a593Smuzhiyun create_options, ACL_NO_MODE,
608*4882a593Smuzhiyun smb2_data, SMB2_OP_POSIX_QUERY_INFO, NULL);
609*4882a593Smuzhiyun }
610*4882a593Smuzhiyun if (rc)
611*4882a593Smuzhiyun goto out;
612*4882a593Smuzhiyun
613*4882a593Smuzhiyun /* TODO: will need to allow for the 2 SIDs when add support for getting owner UID/GID */
614*4882a593Smuzhiyun memcpy(data, smb2_data, sizeof(struct smb311_posix_qinfo));
615*4882a593Smuzhiyun
616*4882a593Smuzhiyun out:
617*4882a593Smuzhiyun kfree(smb2_data);
618*4882a593Smuzhiyun return rc;
619*4882a593Smuzhiyun }
620*4882a593Smuzhiyun
621*4882a593Smuzhiyun int
smb2_mkdir(const unsigned int xid,struct inode * parent_inode,umode_t mode,struct cifs_tcon * tcon,const char * name,struct cifs_sb_info * cifs_sb)622*4882a593Smuzhiyun smb2_mkdir(const unsigned int xid, struct inode *parent_inode, umode_t mode,
623*4882a593Smuzhiyun struct cifs_tcon *tcon, const char *name,
624*4882a593Smuzhiyun struct cifs_sb_info *cifs_sb)
625*4882a593Smuzhiyun {
626*4882a593Smuzhiyun return smb2_compound_op(xid, tcon, cifs_sb, name,
627*4882a593Smuzhiyun FILE_WRITE_ATTRIBUTES, FILE_CREATE,
628*4882a593Smuzhiyun CREATE_NOT_FILE, mode, NULL, SMB2_OP_MKDIR,
629*4882a593Smuzhiyun NULL);
630*4882a593Smuzhiyun }
631*4882a593Smuzhiyun
632*4882a593Smuzhiyun void
smb2_mkdir_setinfo(struct inode * inode,const char * name,struct cifs_sb_info * cifs_sb,struct cifs_tcon * tcon,const unsigned int xid)633*4882a593Smuzhiyun smb2_mkdir_setinfo(struct inode *inode, const char *name,
634*4882a593Smuzhiyun struct cifs_sb_info *cifs_sb, struct cifs_tcon *tcon,
635*4882a593Smuzhiyun const unsigned int xid)
636*4882a593Smuzhiyun {
637*4882a593Smuzhiyun FILE_BASIC_INFO data;
638*4882a593Smuzhiyun struct cifsInodeInfo *cifs_i;
639*4882a593Smuzhiyun struct cifsFileInfo *cfile;
640*4882a593Smuzhiyun u32 dosattrs;
641*4882a593Smuzhiyun int tmprc;
642*4882a593Smuzhiyun
643*4882a593Smuzhiyun memset(&data, 0, sizeof(data));
644*4882a593Smuzhiyun cifs_i = CIFS_I(inode);
645*4882a593Smuzhiyun dosattrs = cifs_i->cifsAttrs | ATTR_READONLY;
646*4882a593Smuzhiyun data.Attributes = cpu_to_le32(dosattrs);
647*4882a593Smuzhiyun cifs_get_writable_path(tcon, name, FIND_WR_ANY, &cfile);
648*4882a593Smuzhiyun tmprc = smb2_compound_op(xid, tcon, cifs_sb, name,
649*4882a593Smuzhiyun FILE_WRITE_ATTRIBUTES, FILE_CREATE,
650*4882a593Smuzhiyun CREATE_NOT_FILE, ACL_NO_MODE,
651*4882a593Smuzhiyun &data, SMB2_OP_SET_INFO, cfile);
652*4882a593Smuzhiyun if (tmprc == 0)
653*4882a593Smuzhiyun cifs_i->cifsAttrs = dosattrs;
654*4882a593Smuzhiyun }
655*4882a593Smuzhiyun
656*4882a593Smuzhiyun int
smb2_rmdir(const unsigned int xid,struct cifs_tcon * tcon,const char * name,struct cifs_sb_info * cifs_sb)657*4882a593Smuzhiyun smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
658*4882a593Smuzhiyun struct cifs_sb_info *cifs_sb)
659*4882a593Smuzhiyun {
660*4882a593Smuzhiyun return smb2_compound_op(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN,
661*4882a593Smuzhiyun CREATE_NOT_FILE, ACL_NO_MODE,
662*4882a593Smuzhiyun NULL, SMB2_OP_RMDIR, NULL);
663*4882a593Smuzhiyun }
664*4882a593Smuzhiyun
665*4882a593Smuzhiyun int
smb2_unlink(const unsigned int xid,struct cifs_tcon * tcon,const char * name,struct cifs_sb_info * cifs_sb)666*4882a593Smuzhiyun smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
667*4882a593Smuzhiyun struct cifs_sb_info *cifs_sb)
668*4882a593Smuzhiyun {
669*4882a593Smuzhiyun return smb2_compound_op(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN,
670*4882a593Smuzhiyun CREATE_DELETE_ON_CLOSE | OPEN_REPARSE_POINT,
671*4882a593Smuzhiyun ACL_NO_MODE, NULL, SMB2_OP_DELETE, NULL);
672*4882a593Smuzhiyun }
673*4882a593Smuzhiyun
674*4882a593Smuzhiyun static int
smb2_set_path_attr(const unsigned int xid,struct cifs_tcon * tcon,const char * from_name,const char * to_name,struct cifs_sb_info * cifs_sb,__u32 access,int command,struct cifsFileInfo * cfile)675*4882a593Smuzhiyun smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon,
676*4882a593Smuzhiyun const char *from_name, const char *to_name,
677*4882a593Smuzhiyun struct cifs_sb_info *cifs_sb, __u32 access, int command,
678*4882a593Smuzhiyun struct cifsFileInfo *cfile)
679*4882a593Smuzhiyun {
680*4882a593Smuzhiyun __le16 *smb2_to_name = NULL;
681*4882a593Smuzhiyun int rc;
682*4882a593Smuzhiyun
683*4882a593Smuzhiyun smb2_to_name = cifs_convert_path_to_utf16(to_name, cifs_sb);
684*4882a593Smuzhiyun if (smb2_to_name == NULL) {
685*4882a593Smuzhiyun rc = -ENOMEM;
686*4882a593Smuzhiyun goto smb2_rename_path;
687*4882a593Smuzhiyun }
688*4882a593Smuzhiyun rc = smb2_compound_op(xid, tcon, cifs_sb, from_name, access,
689*4882a593Smuzhiyun FILE_OPEN, 0, ACL_NO_MODE, smb2_to_name,
690*4882a593Smuzhiyun command, cfile);
691*4882a593Smuzhiyun smb2_rename_path:
692*4882a593Smuzhiyun kfree(smb2_to_name);
693*4882a593Smuzhiyun return rc;
694*4882a593Smuzhiyun }
695*4882a593Smuzhiyun
696*4882a593Smuzhiyun int
smb2_rename_path(const unsigned int xid,struct cifs_tcon * tcon,const char * from_name,const char * to_name,struct cifs_sb_info * cifs_sb)697*4882a593Smuzhiyun smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon,
698*4882a593Smuzhiyun const char *from_name, const char *to_name,
699*4882a593Smuzhiyun struct cifs_sb_info *cifs_sb)
700*4882a593Smuzhiyun {
701*4882a593Smuzhiyun struct cifsFileInfo *cfile;
702*4882a593Smuzhiyun
703*4882a593Smuzhiyun cifs_get_writable_path(tcon, from_name, FIND_WR_WITH_DELETE, &cfile);
704*4882a593Smuzhiyun
705*4882a593Smuzhiyun return smb2_set_path_attr(xid, tcon, from_name, to_name,
706*4882a593Smuzhiyun cifs_sb, DELETE, SMB2_OP_RENAME, cfile);
707*4882a593Smuzhiyun }
708*4882a593Smuzhiyun
709*4882a593Smuzhiyun int
smb2_create_hardlink(const unsigned int xid,struct cifs_tcon * tcon,const char * from_name,const char * to_name,struct cifs_sb_info * cifs_sb)710*4882a593Smuzhiyun smb2_create_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
711*4882a593Smuzhiyun const char *from_name, const char *to_name,
712*4882a593Smuzhiyun struct cifs_sb_info *cifs_sb)
713*4882a593Smuzhiyun {
714*4882a593Smuzhiyun return smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
715*4882a593Smuzhiyun FILE_READ_ATTRIBUTES, SMB2_OP_HARDLINK,
716*4882a593Smuzhiyun NULL);
717*4882a593Smuzhiyun }
718*4882a593Smuzhiyun
719*4882a593Smuzhiyun int
smb2_set_path_size(const unsigned int xid,struct cifs_tcon * tcon,const char * full_path,__u64 size,struct cifs_sb_info * cifs_sb,bool set_alloc)720*4882a593Smuzhiyun smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
721*4882a593Smuzhiyun const char *full_path, __u64 size,
722*4882a593Smuzhiyun struct cifs_sb_info *cifs_sb, bool set_alloc)
723*4882a593Smuzhiyun {
724*4882a593Smuzhiyun __le64 eof = cpu_to_le64(size);
725*4882a593Smuzhiyun
726*4882a593Smuzhiyun return smb2_compound_op(xid, tcon, cifs_sb, full_path,
727*4882a593Smuzhiyun FILE_WRITE_DATA, FILE_OPEN, 0, ACL_NO_MODE,
728*4882a593Smuzhiyun &eof, SMB2_OP_SET_EOF, NULL);
729*4882a593Smuzhiyun }
730*4882a593Smuzhiyun
731*4882a593Smuzhiyun int
smb2_set_file_info(struct inode * inode,const char * full_path,FILE_BASIC_INFO * buf,const unsigned int xid)732*4882a593Smuzhiyun smb2_set_file_info(struct inode *inode, const char *full_path,
733*4882a593Smuzhiyun FILE_BASIC_INFO *buf, const unsigned int xid)
734*4882a593Smuzhiyun {
735*4882a593Smuzhiyun struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
736*4882a593Smuzhiyun struct tcon_link *tlink;
737*4882a593Smuzhiyun int rc;
738*4882a593Smuzhiyun
739*4882a593Smuzhiyun if ((buf->CreationTime == 0) && (buf->LastAccessTime == 0) &&
740*4882a593Smuzhiyun (buf->LastWriteTime == 0) && (buf->ChangeTime == 0) &&
741*4882a593Smuzhiyun (buf->Attributes == 0))
742*4882a593Smuzhiyun return 0; /* would be a no op, no sense sending this */
743*4882a593Smuzhiyun
744*4882a593Smuzhiyun tlink = cifs_sb_tlink(cifs_sb);
745*4882a593Smuzhiyun if (IS_ERR(tlink))
746*4882a593Smuzhiyun return PTR_ERR(tlink);
747*4882a593Smuzhiyun
748*4882a593Smuzhiyun rc = smb2_compound_op(xid, tlink_tcon(tlink), cifs_sb, full_path,
749*4882a593Smuzhiyun FILE_WRITE_ATTRIBUTES, FILE_OPEN,
750*4882a593Smuzhiyun 0, ACL_NO_MODE, buf, SMB2_OP_SET_INFO, NULL);
751*4882a593Smuzhiyun cifs_put_tlink(tlink);
752*4882a593Smuzhiyun return rc;
753*4882a593Smuzhiyun }
754