Merge branch 'v4-0-test' of ssh://git.samba.org/data/git/samba into 4-0-abartlet
[metze/samba/wip.git] / source4 / ntvfs / ntvfs_generic.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    NTVFS generic level mapping code
5
6    Copyright (C) Andrew Tridgell 2003-2004
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21 /*
22   this implements mappings between info levels for NTVFS backend calls
23
24   the idea is that each of these functions implements one of the NTVFS
25   backend calls in terms of the 'generic' call. All backends that use
26   these functions must supply the generic call, but can if it wants to
27   also implement other levels if the need arises
28
29   this allows backend writers to only implement one variant of each
30   call unless they need fine grained control of the calls.
31 */
32
33 #include "includes.h"
34 #include "ntvfs/ntvfs.h"
35 #include "libcli/smb2/smb2.h"
36 #include "libcli/smb2/smb2_calls.h"
37
38 /* a second stage function converts from the out parameters of the generic
39    call onto the out parameters of the specific call made */
40 typedef NTSTATUS (*second_stage_t)(struct ntvfs_module_context *,
41                                    struct ntvfs_request *,
42                                    void *, void *, NTSTATUS);
43
44 /* 
45    this structure holds the async state for pending mapped async calls
46 */
47 struct ntvfs_map_async {
48         struct ntvfs_module_context *ntvfs;
49         void *io, *io2;
50         second_stage_t fn;
51 };
52
53 /*
54   this is a async wrapper, called from the backend when it has completed
55   a function that it has decided to reply to in an async fashion
56 */
57 static void ntvfs_map_async_send(struct ntvfs_request *req)
58 {
59         struct ntvfs_map_async *m = req->async_states->private_data;
60
61         ntvfs_async_state_pop(req);
62
63         /* call the _finish function setup in ntvfs_map_async_setup() */
64         req->async_states->status = m->fn(m->ntvfs, req, m->io, m->io2, req->async_states->status);
65
66         /* call the send function from the next module up */
67         req->async_states->send_fn(req);
68 }
69
70 /*
71   prepare for calling a ntvfs backend with async support
72   io is the original call structure
73   io2 is the new call structure for the mapped call
74   fn is a second stage function for processing the out arguments
75 */
76 static NTSTATUS ntvfs_map_async_setup(struct ntvfs_module_context *ntvfs,
77                                       struct ntvfs_request *req,
78                                       void *io, void *io2,
79                                       second_stage_t fn)
80 {
81         struct ntvfs_map_async *m;
82         m = talloc(req, struct ntvfs_map_async);
83         if (m == NULL) {
84                 return NT_STATUS_NO_MEMORY;
85         }
86         m->ntvfs = ntvfs;
87         m->io = io;
88         m->io2 = io2;
89         m->fn = fn;
90         return ntvfs_async_state_push(ntvfs, req, m, ntvfs_map_async_send);
91 }
92
93 /*
94   called when first stage processing is complete. 
95 */      
96 static NTSTATUS ntvfs_map_async_finish(struct ntvfs_request *req, NTSTATUS status)
97 {
98         struct ntvfs_map_async *m;
99
100         /* if the backend has decided to reply in an async fashion then
101            we don't need to do any work here */
102         if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
103                 return status;
104         }
105
106         /* the backend is replying immediately. call the 2nd stage function after popping our local
107            async state */
108         m = req->async_states->private_data;
109
110         ntvfs_async_state_pop(req);
111
112         return m->fn(m->ntvfs, req, m->io, m->io2, status);
113 }
114
115 /*
116   see if a filename ends in EXE COM DLL or SYM. This is needed for the
117   DENY_DOS mapping for OpenX
118 */
119 bool is_exe_filename(const char *fname)
120 {
121         char *p;
122         p = strrchr(fname, '.');
123         if (!p) {
124                 return false;
125         }
126         p++;
127         if (strcasecmp(p, "EXE") == 0 ||
128             strcasecmp(p, "COM") == 0 ||
129             strcasecmp(p, "DLL") == 0 ||
130             strcasecmp(p, "SYM") == 0) {
131                 return true;
132         }
133         return false;
134 }
135
136
137 /* 
138    NTVFS openx to ntcreatex mapper
139 */
140 static NTSTATUS ntvfs_map_open_finish(struct ntvfs_module_context *ntvfs,
141                                       struct ntvfs_request *req, 
142                                       union smb_open *io, 
143                                       union smb_open *io2, 
144                                       NTSTATUS status)
145 {
146         time_t write_time = 0;
147         uint32_t set_size = 0;
148         union smb_setfileinfo *sf;
149         uint_t state;
150
151         if (!NT_STATUS_IS_OK(status)) {
152                 return status;
153         }
154
155         switch (io->generic.level) {
156         case RAW_OPEN_OPEN:
157                 io->openold.out.file.ntvfs = io2->generic.out.file.ntvfs;
158                 io->openold.out.attrib     = io2->generic.out.attrib;
159                 io->openold.out.write_time = nt_time_to_unix(io2->generic.out.write_time);
160                 io->openold.out.size       = io2->generic.out.size;
161                 io->openold.out.rmode      = io->openold.in.open_mode;
162                 break;
163
164         case RAW_OPEN_OPENX:
165                 io->openx.out.file.ntvfs  = io2->generic.out.file.ntvfs;
166                 io->openx.out.attrib      = io2->generic.out.attrib;
167                 io->openx.out.write_time  = nt_time_to_unix(io2->generic.out.write_time);
168                 io->openx.out.size        = io2->generic.out.size;
169                 io->openx.out.access      = (io->openx.in.open_mode & OPENX_MODE_ACCESS_MASK);
170                 io->openx.out.ftype       = 0;
171                 io->openx.out.devstate    = 0;
172                 io->openx.out.action      = io2->generic.out.create_action;
173                 io->openx.out.unique_fid  = 0;
174                 io->openx.out.access_mask = SEC_STD_ALL;
175                 io->openx.out.unknown     = 0;
176                 
177                 /* we need to extend the file to the requested size if
178                    it was newly created */
179                 if (io2->generic.out.create_action == NTCREATEX_ACTION_CREATED) {
180                         set_size = io->openx.in.size;
181                 }
182                 break;
183
184         case RAW_OPEN_T2OPEN:
185                 io->t2open.out.file.ntvfs  = io2->generic.out.file.ntvfs;
186                 io->t2open.out.attrib      = io2->generic.out.attrib;
187                 io->t2open.out.write_time  = nt_time_to_unix(io2->generic.out.write_time);
188                 io->t2open.out.size        = io2->generic.out.size;
189                 io->t2open.out.access      = io->t2open.in.open_mode;
190                 io->t2open.out.ftype       = 0;
191                 io->t2open.out.devstate    = 0;
192                 io->t2open.out.action      = io2->generic.out.create_action;
193                 io->t2open.out.file_id      = 0;
194                 break;
195
196         case RAW_OPEN_MKNEW:
197         case RAW_OPEN_CREATE:
198                 io->mknew.out.file.ntvfs= io2->generic.out.file.ntvfs;
199                 write_time              = io->mknew.in.write_time;
200                 break;
201
202         case RAW_OPEN_CTEMP:
203                 io->ctemp.out.file.ntvfs= io2->generic.out.file.ntvfs;
204                 io->ctemp.out.name      = talloc_strdup(req, io2->generic.in.fname + 
205                                                         strlen(io->ctemp.in.directory) + 1);
206                 NT_STATUS_HAVE_NO_MEMORY(io->ctemp.out.name);
207                 break;
208
209         case RAW_OPEN_SMB2:
210                 ZERO_STRUCT(io->smb2.out);
211                 io->smb2.out.file.ntvfs         = io2->generic.out.file.ntvfs;
212                 switch (io2->generic.out.oplock_level) {
213                 case BATCH_OPLOCK_RETURN:
214                         io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
215                         break;
216                 case EXCLUSIVE_OPLOCK_RETURN:
217                         io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
218                         break;
219                 case LEVEL_II_OPLOCK_RETURN:
220                         io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_II;
221                         break;
222                 default:
223                         io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_NONE;
224                         break;
225                 }
226                 io->smb2.out.reserved           = 0;
227                 io->smb2.out.create_action      = io2->generic.out.create_action;
228                 io->smb2.out.create_time        = io2->generic.out.create_time;
229                 io->smb2.out.access_time        = io2->generic.out.access_time;
230                 io->smb2.out.write_time         = io2->generic.out.write_time;
231                 io->smb2.out.change_time        = io2->generic.out.change_time;
232                 io->smb2.out.alloc_size         = io2->generic.out.alloc_size;
233                 io->smb2.out.size               = io2->generic.out.size;
234                 io->smb2.out.file_attr          = io2->generic.out.attrib;
235                 io->smb2.out.reserved2          = 0;
236                 io->smb2.out.maximal_access     = io2->generic.out.maximal_access;
237                 break;
238
239         default:
240                 return NT_STATUS_INVALID_LEVEL;
241         }
242
243         /* doing a secondary request async is more trouble than its
244            worth */
245         state = req->async_states->state;
246         req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
247
248         if (write_time != 0) {
249                 sf = talloc(req, union smb_setfileinfo);
250                 NT_STATUS_HAVE_NO_MEMORY(sf);
251                 sf->generic.level           = RAW_SFILEINFO_STANDARD;
252                 sf->generic.in.file.ntvfs   = io2->generic.out.file.ntvfs;
253                 sf->standard.in.create_time = 0;
254                 sf->standard.in.write_time  = write_time;
255                 sf->standard.in.access_time = 0;
256                 status = ntvfs->ops->setfileinfo(ntvfs, req, sf);
257         }
258
259         if (set_size != 0) {
260                 sf = talloc(req, union smb_setfileinfo);                        
261                 NT_STATUS_HAVE_NO_MEMORY(sf);
262                 sf->generic.level            = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
263                 sf->generic.in.file.ntvfs    = io2->generic.out.file.ntvfs;
264                 sf->end_of_file_info.in.size = set_size;
265                 status = ntvfs->ops->setfileinfo(ntvfs, req, sf);
266                 if (NT_STATUS_IS_OK(status)) {
267                         io->openx.out.size = io->openx.in.size;
268                 }
269         }
270
271         req->async_states->state = state;
272
273         return NT_STATUS_OK;
274 }
275
276 /*
277   the core of the mapping between openx style parameters and ntcreatex 
278   parameters
279 */
280 static NTSTATUS map_openx_open(uint16_t flags, uint16_t open_mode, 
281                                uint16_t open_func, const char *fname,
282                                union smb_open *io2)
283 {
284         if (flags & OPENX_FLAGS_REQUEST_OPLOCK) {
285                 io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_OPLOCK;
286         }
287         if (flags & OPENX_FLAGS_REQUEST_BATCH_OPLOCK) {
288                 io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
289         }
290
291         switch (open_mode & OPENX_MODE_ACCESS_MASK) {
292         case OPENX_MODE_ACCESS_READ:
293         case OPENX_MODE_ACCESS_EXEC:
294                 io2->generic.in.access_mask = SEC_RIGHTS_FILE_READ;
295                 break;
296         case OPENX_MODE_ACCESS_WRITE:
297                 io2->generic.in.access_mask = SEC_RIGHTS_FILE_WRITE;
298                 break;
299         case OPENX_MODE_ACCESS_RDWR:
300         case OPENX_MODE_ACCESS_FCB:
301                 io2->generic.in.access_mask = 
302                         SEC_RIGHTS_FILE_READ | 
303                         SEC_RIGHTS_FILE_WRITE;
304                 break;
305         default:
306                 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
307         }
308
309         switch (open_mode & OPENX_MODE_DENY_MASK) {
310         case OPENX_MODE_DENY_READ:
311                 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_WRITE;
312                 break;
313         case OPENX_MODE_DENY_WRITE:
314                 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
315                 break;
316         case OPENX_MODE_DENY_ALL:
317                 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
318                 break;
319         case OPENX_MODE_DENY_NONE:
320                 io2->generic.in.share_access = 
321                         NTCREATEX_SHARE_ACCESS_READ | 
322                         NTCREATEX_SHARE_ACCESS_WRITE;
323                 break;
324         case OPENX_MODE_DENY_DOS:
325                 /* DENY_DOS is quite strange - it depends on the filename! */
326                 io2->generic.in.create_options |= 
327                         NTCREATEX_OPTIONS_PRIVATE_DENY_DOS;
328                 if (is_exe_filename(fname)) {
329                         io2->generic.in.share_access = 
330                                 NTCREATEX_SHARE_ACCESS_READ | 
331                                 NTCREATEX_SHARE_ACCESS_WRITE;
332                 } else {
333                         if ((open_mode & OPENX_MODE_ACCESS_MASK) == OPENX_MODE_ACCESS_READ) {
334                                 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
335                         } else {
336                                 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
337                         }
338                 }
339                 break;
340         case OPENX_MODE_DENY_FCB:
341                 io2->generic.in.create_options |= NTCREATEX_OPTIONS_PRIVATE_DENY_FCB;
342                 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
343                 break;
344         default:
345                 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
346         }
347
348         switch (open_func) {
349         case (OPENX_OPEN_FUNC_OPEN):
350                 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN;
351                 break;
352         case (OPENX_OPEN_FUNC_TRUNC):
353                 io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
354                 break;
355         case (OPENX_OPEN_FUNC_FAIL | OPENX_OPEN_FUNC_CREATE):
356                 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
357                 break;
358         case (OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE):
359                 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
360                 break;
361         case (OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE):
362                 io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
363                 break;                  
364         default:
365                 /* this one is very strange */
366                 if ((open_mode & OPENX_MODE_ACCESS_MASK) == OPENX_MODE_ACCESS_EXEC) {
367                         io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
368                         break;
369                 }
370                 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
371         }
372
373         return NT_STATUS_OK;
374 }
375
376 /* 
377    NTVFS open generic to any mapper
378 */
379 NTSTATUS ntvfs_map_open(struct ntvfs_module_context *ntvfs,
380                                  struct ntvfs_request *req,
381                                  union smb_open *io)
382 {
383         NTSTATUS status;
384         union smb_open *io2;
385
386         io2 = talloc_zero(req, union smb_open);
387         if (io2 == NULL) {
388                 return NT_STATUS_NO_MEMORY;
389         }
390
391         status = ntvfs_map_async_setup(ntvfs, req,
392                                        io, io2, 
393                                        (second_stage_t)ntvfs_map_open_finish);
394         if (!NT_STATUS_IS_OK(status)) {
395                 return status;
396         }
397
398         io2->generic.level = RAW_OPEN_GENERIC;
399                 
400         switch (io->generic.level) {
401         case RAW_OPEN_OPENX:
402                 status = map_openx_open(io->openx.in.flags,
403                                         io->openx.in.open_mode, 
404                                         io->openx.in.open_func, 
405                                         io->openx.in.fname,
406                                         io2);
407                 if (!NT_STATUS_IS_OK(status)) {
408                         goto done;
409                 }
410                 
411                 io2->generic.in.file_attr = io->openx.in.file_attrs;
412                 io2->generic.in.fname = io->openx.in.fname;
413                 
414                 status = ntvfs->ops->open(ntvfs, req, io2);
415                 break;
416                 
417                 
418         case RAW_OPEN_OPEN:
419                 status = map_openx_open(0,
420                                         io->openold.in.open_mode, 
421                                         OPENX_OPEN_FUNC_OPEN, 
422                                         io->openold.in.fname,
423                                         io2);
424                 if (!NT_STATUS_IS_OK(status)) {
425                         goto done;
426                 }
427
428                 io2->generic.in.file_attr = io->openold.in.search_attrs;
429                 io2->generic.in.fname = io->openold.in.fname;
430
431                 status = ntvfs->ops->open(ntvfs, req, io2);
432                 break;
433
434         case RAW_OPEN_T2OPEN:
435                 io2->generic.level         = RAW_OPEN_NTTRANS_CREATE;
436
437                 if (io->t2open.in.open_func == 0) {
438                         status = NT_STATUS_OBJECT_NAME_COLLISION;
439                         goto done;
440                 }
441
442                 status = map_openx_open(io->t2open.in.flags,
443                                         io->t2open.in.open_mode, 
444                                         io->t2open.in.open_func, 
445                                         io->t2open.in.fname,
446                                         io2);
447                 if (!NT_STATUS_IS_OK(status)) {
448                         goto done;
449                 }
450
451                 io2->generic.in.file_attr        = io->t2open.in.file_attrs;
452                 io2->generic.in.fname            = io->t2open.in.fname;
453                 io2->generic.in.ea_list          = talloc(io2, struct smb_ea_list);
454                 io2->generic.in.ea_list->num_eas = io->t2open.in.num_eas;
455                 io2->generic.in.ea_list->eas     = io->t2open.in.eas;
456
457                 status = ntvfs->ops->open(ntvfs, req, io2);
458                 break;
459
460         case RAW_OPEN_MKNEW:
461                 io2->generic.in.file_attr = io->mknew.in.attrib;
462                 io2->generic.in.fname = io->mknew.in.fname;
463                 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
464                 io2->generic.in.access_mask = 
465                         SEC_RIGHTS_FILE_READ |
466                         SEC_RIGHTS_FILE_WRITE;
467                 io2->generic.in.share_access = 
468                         NTCREATEX_SHARE_ACCESS_READ | 
469                         NTCREATEX_SHARE_ACCESS_WRITE;
470                 status = ntvfs->ops->open(ntvfs, req, io2);
471                 break;
472
473         case RAW_OPEN_CREATE:
474                 io2->generic.in.file_attr = io->mknew.in.attrib;
475                 io2->generic.in.fname = io->mknew.in.fname;
476                 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
477                 io2->generic.in.access_mask = 
478                         SEC_RIGHTS_FILE_READ |
479                         SEC_RIGHTS_FILE_WRITE;
480                 io2->generic.in.share_access = 
481                         NTCREATEX_SHARE_ACCESS_READ | 
482                         NTCREATEX_SHARE_ACCESS_WRITE;
483                 status = ntvfs->ops->open(ntvfs, req, io2);
484                 break;
485
486         case RAW_OPEN_CTEMP:
487                 io2->generic.in.file_attr = io->ctemp.in.attrib;
488                 io2->generic.in.fname = 
489                         talloc_asprintf(io2, "%s\\SRV%s", 
490                                         io->ctemp.in.directory,
491                                         generate_random_str_list(io2, 5, "0123456789"));
492                 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
493                 io2->generic.in.access_mask = 
494                         SEC_RIGHTS_FILE_READ |
495                         SEC_RIGHTS_FILE_WRITE;
496                 io2->generic.in.share_access = 
497                         NTCREATEX_SHARE_ACCESS_READ | 
498                         NTCREATEX_SHARE_ACCESS_WRITE;
499                 status = ntvfs->ops->open(ntvfs, req, io2);
500                 break;
501         case RAW_OPEN_SMB2:
502                 switch (io->smb2.in.oplock_level) {
503                 case SMB2_OPLOCK_LEVEL_BATCH:
504                         io2->generic.in.flags = NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK |
505                                                 NTCREATEX_FLAGS_REQUEST_OPLOCK;
506                         break;
507                 case SMB2_OPLOCK_LEVEL_EXCLUSIVE:
508                         io2->generic.in.flags = NTCREATEX_FLAGS_REQUEST_OPLOCK;
509                         break;
510                 default:
511                         io2->generic.in.flags = 0;
512                         break;
513                 }
514                 io2->generic.in.root_fid        = 0;
515                 io2->generic.in.access_mask     = io->smb2.in.desired_access;
516                 io2->generic.in.alloc_size      = io->smb2.in.alloc_size;
517                 io2->generic.in.file_attr       = io->smb2.in.file_attributes;
518                 io2->generic.in.share_access    = io->smb2.in.share_access;
519                 io2->generic.in.open_disposition= io->smb2.in.create_disposition;
520                 io2->generic.in.create_options  = io->smb2.in.create_options;
521                 io2->generic.in.impersonation   = io->smb2.in.impersonation_level;
522                 io2->generic.in.security_flags  = 0;
523                 io2->generic.in.fname           = io->smb2.in.fname;
524                 io2->generic.in.sec_desc        = io->smb2.in.sec_desc;
525                 io2->generic.in.ea_list         = &io->smb2.in.eas;
526                 io2->generic.in.query_maximal_access = io->smb2.in.query_maximal_access; 
527
528                 /* we don't support timewarp yet */
529                 if (io->smb2.in.timewarp != 0) {
530                         status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
531                         break;
532                 }
533
534                 /* we need to check these bits before we check the private mask */
535                 if (io2->generic.in.create_options & SMB2_CREATE_OPTIONS_NOT_SUPPORTED_MASK) {
536                         status = NT_STATUS_NOT_SUPPORTED;
537                         break;
538                 }
539
540                 /* TODO: find out why only SMB2 ignores these */
541                 io2->generic.in.create_options &= ~NTCREATEX_OPTIONS_SYNC_ALERT;
542                 io2->generic.in.create_options &= ~NTCREATEX_OPTIONS_ASYNC_ALERT;
543
544                 status = ntvfs->ops->open(ntvfs, req, io2);             
545                 break;
546
547         default:
548                 status = NT_STATUS_INVALID_LEVEL;
549                 break;
550         }
551 done:
552         return ntvfs_map_async_finish(req, status);
553 }
554
555
556 /* 
557    NTVFS fsinfo generic to any mapper
558 */
559 NTSTATUS ntvfs_map_fsinfo(struct ntvfs_module_context *ntvfs,
560                                    struct ntvfs_request *req,
561                                    union smb_fsinfo *fs)
562 {
563         NTSTATUS status;
564         union smb_fsinfo *fs2;
565
566         fs2 = talloc(req, union smb_fsinfo);
567         if (fs2 == NULL) {
568                 return NT_STATUS_NO_MEMORY;
569         }
570
571         if (fs->generic.level == RAW_QFS_GENERIC) {
572                 return NT_STATUS_INVALID_LEVEL;
573         }
574         
575         /* only used by the simple backend, which doesn't do async */
576         req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
577
578         /* ask the backend for the generic info */
579         fs2->generic.level = RAW_QFS_GENERIC;
580
581         status = ntvfs->ops->fsinfo(ntvfs, req, fs2);
582         if (!NT_STATUS_IS_OK(status)) {
583                 return status;
584         }
585
586         /* and convert it to the required level */
587         switch (fs->generic.level) {
588         case RAW_QFS_GENERIC:
589                 return NT_STATUS_INVALID_LEVEL;
590
591         case RAW_QFS_DSKATTR: {
592                 /* map from generic to DSKATTR */
593                 uint_t bpunit = 64;
594
595                 /* we need to scale the sizes to fit */
596                 for (bpunit=64; bpunit<0x10000; bpunit *= 2) {
597                         if (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size < bpunit * 512 * 65535.0) {
598                                 break;
599                         }
600                 }
601
602                 fs->dskattr.out.blocks_per_unit = bpunit;
603                 fs->dskattr.out.block_size = 512;
604                 fs->dskattr.out.units_total = 
605                         (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size) / (bpunit * 512);
606                 fs->dskattr.out.units_free  = 
607                         (fs2->generic.out.blocks_free  * (double)fs2->generic.out.block_size) / (bpunit * 512);
608
609                 /* we must return a maximum of 2G to old DOS systems, or they get very confused */
610                 if (bpunit > 64 && req->ctx->protocol <= PROTOCOL_LANMAN2) {
611                         fs->dskattr.out.blocks_per_unit = 64;
612                         fs->dskattr.out.units_total = 0xFFFF;
613                         fs->dskattr.out.units_free = 0xFFFF;
614                 }
615                 return NT_STATUS_OK;
616         }
617
618         case RAW_QFS_ALLOCATION:
619                 fs->allocation.out.fs_id = fs2->generic.out.fs_id;
620                 fs->allocation.out.total_alloc_units = fs2->generic.out.blocks_total;
621                 fs->allocation.out.avail_alloc_units = fs2->generic.out.blocks_free;
622                 fs->allocation.out.sectors_per_unit = 1;
623                 fs->allocation.out.bytes_per_sector = fs2->generic.out.block_size;
624                 return NT_STATUS_OK;
625
626         case RAW_QFS_VOLUME:
627                 fs->volume.out.serial_number = fs2->generic.out.serial_number;
628                 fs->volume.out.volume_name.s = fs2->generic.out.volume_name;
629                 return NT_STATUS_OK;
630
631         case RAW_QFS_VOLUME_INFO:
632         case RAW_QFS_VOLUME_INFORMATION:
633                 fs->volume_info.out.create_time = fs2->generic.out.create_time;
634                 fs->volume_info.out.serial_number = fs2->generic.out.serial_number;
635                 fs->volume_info.out.volume_name.s = fs2->generic.out.volume_name;
636                 return NT_STATUS_OK;
637
638         case RAW_QFS_SIZE_INFO:
639         case RAW_QFS_SIZE_INFORMATION:
640                 fs->size_info.out.total_alloc_units = fs2->generic.out.blocks_total;
641                 fs->size_info.out.avail_alloc_units = fs2->generic.out.blocks_free;
642                 fs->size_info.out.sectors_per_unit = 1;
643                 fs->size_info.out.bytes_per_sector = fs2->generic.out.block_size;
644                 return NT_STATUS_OK;
645
646         case RAW_QFS_DEVICE_INFO:
647         case RAW_QFS_DEVICE_INFORMATION:
648                 fs->device_info.out.device_type = fs2->generic.out.device_type;
649                 fs->device_info.out.characteristics = fs2->generic.out.device_characteristics;
650                 return NT_STATUS_OK;
651
652         case RAW_QFS_ATTRIBUTE_INFO:
653         case RAW_QFS_ATTRIBUTE_INFORMATION:
654                 fs->attribute_info.out.fs_attr = fs2->generic.out.fs_attr;
655                 fs->attribute_info.out.max_file_component_length = fs2->generic.out.max_file_component_length;
656                 fs->attribute_info.out.fs_type.s = fs2->generic.out.fs_type;
657                 return NT_STATUS_OK;
658
659         case RAW_QFS_QUOTA_INFORMATION:
660                 ZERO_STRUCT(fs->quota_information.out.unknown);
661                 fs->quota_information.out.quota_soft = fs2->generic.out.quota_soft;
662                 fs->quota_information.out.quota_hard = fs2->generic.out.quota_hard;
663                 fs->quota_information.out.quota_flags = fs2->generic.out.quota_flags;
664                 return NT_STATUS_OK;
665
666         case RAW_QFS_FULL_SIZE_INFORMATION:
667                 fs->full_size_information.out.total_alloc_units = fs2->generic.out.blocks_total;
668                 fs->full_size_information.out.call_avail_alloc_units = fs2->generic.out.blocks_free;
669                 fs->full_size_information.out.actual_avail_alloc_units = fs2->generic.out.blocks_free;
670                 fs->full_size_information.out.sectors_per_unit = 1;
671                 fs->full_size_information.out.bytes_per_sector = fs2->generic.out.block_size;
672                 return NT_STATUS_OK;
673
674         case RAW_QFS_OBJECTID_INFORMATION:
675                 fs->objectid_information.out.guid = fs2->generic.out.guid;
676                 ZERO_STRUCT(fs->objectid_information.out.unknown);
677                 return NT_STATUS_OK;
678         }
679
680
681         return NT_STATUS_INVALID_LEVEL;
682 }
683
684
685 /* 
686    NTVFS fileinfo generic to any mapper
687 */
688 NTSTATUS ntvfs_map_fileinfo(TALLOC_CTX *mem_ctx,
689                                      union smb_fileinfo *info, 
690                                      union smb_fileinfo *info2)
691 {
692         int i;
693         /* and convert it to the required level using results in info2 */
694         switch (info->generic.level) {
695                 case RAW_FILEINFO_GENERIC:
696                 return NT_STATUS_INVALID_LEVEL;
697         case RAW_FILEINFO_GETATTR:
698                 info->getattr.out.attrib = info2->generic.out.attrib & 0xff;
699                 info->getattr.out.size = info2->generic.out.size;
700                 info->getattr.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
701                 return NT_STATUS_OK;
702                 
703         case RAW_FILEINFO_GETATTRE:
704                 info->getattre.out.attrib = info2->generic.out.attrib;
705                 info->getattre.out.size = info2->generic.out.size;
706                 info->getattre.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
707                 info->getattre.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
708                 info->getattre.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
709                 info->getattre.out.alloc_size = info2->generic.out.alloc_size;
710                 return NT_STATUS_OK;
711                 
712         case RAW_FILEINFO_NETWORK_OPEN_INFORMATION:
713                 info->network_open_information.out.create_time = info2->generic.out.create_time;
714                 info->network_open_information.out.access_time = info2->generic.out.access_time;
715                 info->network_open_information.out.write_time =  info2->generic.out.write_time;
716                 info->network_open_information.out.change_time = info2->generic.out.change_time;
717                 info->network_open_information.out.alloc_size = info2->generic.out.alloc_size;
718                 info->network_open_information.out.size = info2->generic.out.size;
719                 info->network_open_information.out.attrib = info2->generic.out.attrib;
720                 return NT_STATUS_OK;
721
722         case RAW_FILEINFO_ALL_INFO:
723         case RAW_FILEINFO_ALL_INFORMATION:
724                 info->all_info.out.create_time = info2->generic.out.create_time;
725                 info->all_info.out.access_time = info2->generic.out.access_time;
726                 info->all_info.out.write_time =  info2->generic.out.write_time;
727                 info->all_info.out.change_time = info2->generic.out.change_time;
728                 info->all_info.out.attrib = info2->generic.out.attrib;
729                 info->all_info.out.alloc_size = info2->generic.out.alloc_size;
730                 info->all_info.out.size = info2->generic.out.size;
731                 info->all_info.out.nlink = info2->generic.out.nlink;
732                 info->all_info.out.delete_pending = info2->generic.out.delete_pending;
733                 info->all_info.out.directory = info2->generic.out.directory;
734                 info->all_info.out.ea_size = info2->generic.out.ea_size;
735                 info->all_info.out.fname.s = info2->generic.out.fname.s;
736                 info->all_info.out.fname.private_length = info2->generic.out.fname.private_length;
737                 return NT_STATUS_OK;
738
739         case RAW_FILEINFO_BASIC_INFO:
740         case RAW_FILEINFO_BASIC_INFORMATION:
741                 info->basic_info.out.create_time = info2->generic.out.create_time;
742                 info->basic_info.out.access_time = info2->generic.out.access_time;
743                 info->basic_info.out.write_time = info2->generic.out.write_time;
744                 info->basic_info.out.change_time = info2->generic.out.change_time;
745                 info->basic_info.out.attrib = info2->generic.out.attrib;
746                 return NT_STATUS_OK;
747
748         case RAW_FILEINFO_STANDARD:
749                 info->standard.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
750                 info->standard.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
751                 info->standard.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
752                 info->standard.out.size = info2->generic.out.size;
753                 info->standard.out.alloc_size = info2->generic.out.alloc_size;
754                 info->standard.out.attrib = info2->generic.out.attrib;
755                 return NT_STATUS_OK;
756
757         case RAW_FILEINFO_EA_SIZE:
758                 info->ea_size.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
759                 info->ea_size.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
760                 info->ea_size.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
761                 info->ea_size.out.size = info2->generic.out.size;
762                 info->ea_size.out.alloc_size = info2->generic.out.alloc_size;
763                 info->ea_size.out.attrib = info2->generic.out.attrib;
764                 info->ea_size.out.ea_size = info2->generic.out.ea_size;
765                 return NT_STATUS_OK;
766
767         case RAW_FILEINFO_STANDARD_INFO:
768         case RAW_FILEINFO_STANDARD_INFORMATION:
769                 info->standard_info.out.alloc_size = info2->generic.out.alloc_size;
770                 info->standard_info.out.size = info2->generic.out.size;
771                 info->standard_info.out.nlink = info2->generic.out.nlink;
772                 info->standard_info.out.delete_pending = info2->generic.out.delete_pending;
773                 info->standard_info.out.directory = info2->generic.out.directory;
774                 return NT_STATUS_OK;
775
776         case RAW_FILEINFO_INTERNAL_INFORMATION:
777                 info->internal_information.out.file_id = info2->generic.out.file_id;
778                 return NT_STATUS_OK;
779
780         case RAW_FILEINFO_EA_INFO:
781         case RAW_FILEINFO_EA_INFORMATION:
782                 info->ea_info.out.ea_size = info2->generic.out.ea_size;
783                 return NT_STATUS_OK;
784
785         case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION:
786                 info->attribute_tag_information.out.attrib = info2->generic.out.attrib;
787                 info->attribute_tag_information.out.reparse_tag = info2->generic.out.reparse_tag;
788                 return NT_STATUS_OK;
789
790         case RAW_FILEINFO_STREAM_INFO:
791         case RAW_FILEINFO_STREAM_INFORMATION:
792                 info->stream_info.out.num_streams = info2->generic.out.num_streams;
793                 if (info->stream_info.out.num_streams > 0) {
794                         info->stream_info.out.streams = 
795                                 talloc_array(mem_ctx, 
796                                                struct stream_struct,
797                                                info->stream_info.out.num_streams);
798                         if (!info->stream_info.out.streams) {
799                                 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d streams\n",
800                                         info->stream_info.out.num_streams));
801                                 return NT_STATUS_NO_MEMORY;
802                         }
803                         for (i=0; i < info->stream_info.out.num_streams; i++) {
804                                 info->stream_info.out.streams[i] = info2->generic.out.streams[i];
805                                 info->stream_info.out.streams[i].stream_name.s = 
806                                         talloc_strdup(info->stream_info.out.streams,
807                                                       info2->generic.out.streams[i].stream_name.s);
808                                 if (!info->stream_info.out.streams[i].stream_name.s) {
809                                         DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
810                                         return NT_STATUS_NO_MEMORY;
811                                 }
812                         }
813                 }
814                 return NT_STATUS_OK;
815
816         case RAW_FILEINFO_NAME_INFO:
817         case RAW_FILEINFO_NAME_INFORMATION:
818                 info->name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.fname.s);
819                 NT_STATUS_HAVE_NO_MEMORY(info->name_info.out.fname.s);
820                 info->name_info.out.fname.private_length = info2->generic.out.fname.private_length;
821                 return NT_STATUS_OK;
822                 
823         case RAW_FILEINFO_ALT_NAME_INFO:
824         case RAW_FILEINFO_ALT_NAME_INFORMATION:
825                 info->alt_name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.alt_fname.s);
826                 NT_STATUS_HAVE_NO_MEMORY(info->alt_name_info.out.fname.s);
827                 info->alt_name_info.out.fname.private_length = info2->generic.out.alt_fname.private_length;
828                 return NT_STATUS_OK;
829         
830         case RAW_FILEINFO_POSITION_INFORMATION:
831                 info->position_information.out.position = info2->generic.out.position;
832                 return NT_STATUS_OK;
833         
834         case RAW_FILEINFO_ALL_EAS:
835                 info->all_eas.out.num_eas = info2->generic.out.num_eas;
836                 if (info->all_eas.out.num_eas > 0) {
837                         info->all_eas.out.eas = talloc_array(mem_ctx, 
838                                                                struct ea_struct,
839                                                                info->all_eas.out.num_eas);
840                         if (!info->all_eas.out.eas) {
841                                 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d eas\n",
842                                         info->all_eas.out.num_eas));
843                                 return NT_STATUS_NO_MEMORY;
844                         }
845                         for (i = 0; i < info->all_eas.out.num_eas; i++) {
846                                 info->all_eas.out.eas[i] = info2->generic.out.eas[i];
847                                 info->all_eas.out.eas[i].name.s = 
848                                         talloc_strdup(info->all_eas.out.eas,
849                                                       info2->generic.out.eas[i].name.s);
850                                 if (!info->all_eas.out.eas[i].name.s) {
851                                         DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
852                                         return NT_STATUS_NO_MEMORY;
853                                 }
854                                 info->all_eas.out.eas[i].value.data = 
855                                         talloc_memdup(info->all_eas.out.eas,
856                                                 info2->generic.out.eas[i].value.data,
857                                                 info2->generic.out.eas[i].value.length);
858                                 if (!info->all_eas.out.eas[i].value.data) {
859                                         DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
860                                         return NT_STATUS_NO_MEMORY;
861                                 }
862                         }
863                 }
864                 return NT_STATUS_OK;
865                 
866         case RAW_FILEINFO_IS_NAME_VALID:
867                 return NT_STATUS_OK;
868                 
869         case RAW_FILEINFO_COMPRESSION_INFO:
870         case RAW_FILEINFO_COMPRESSION_INFORMATION:
871                 info->compression_info.out.compressed_size = info2->generic.out.compressed_size;
872                 info->compression_info.out.format = info2->generic.out.format;
873                 info->compression_info.out.unit_shift = info2->generic.out.unit_shift;
874                 info->compression_info.out.chunk_shift = info2->generic.out.chunk_shift;
875                 info->compression_info.out.cluster_shift = info2->generic.out.cluster_shift;
876                 return NT_STATUS_OK;
877                 
878         case RAW_FILEINFO_ACCESS_INFORMATION:
879                 info->access_information.out.access_flags = info2->generic.out.access_flags;
880                 return NT_STATUS_OK;
881                 
882         case RAW_FILEINFO_MODE_INFORMATION:
883                 info->mode_information.out.mode = info2->generic.out.mode;
884                 return NT_STATUS_OK;
885                 
886         case RAW_FILEINFO_ALIGNMENT_INFORMATION:
887                 info->alignment_information.out.alignment_requirement =
888                         info2->generic.out.alignment_requirement;
889                 return NT_STATUS_OK;
890 #if 0   
891         case RAW_FILEINFO_UNIX_BASIC:
892                 info->unix_basic_info.out.end_of_file = info2->generic.out.end_of_file;
893                 info->unix_basic_info.out.num_bytes = info2->generic.out.size;
894                 info->unix_basic_info.out.status_change_time = info2->generic.out.change_time;
895                 info->unix_basic_info.out.access_time = info2->generic.out.access_time;
896                 info->unix_basic_info.out.change_time = info2->generic.out.change_time;
897                 info->unix_basic_info.out.uid = info2->generic.out.uid;
898                 info->unix_basic_info.out.gid = info2->generic.out.gid;
899                 info->unix_basic_info.out.file_type = info2->generic.out.file_type;
900                 info->unix_basic_info.out.dev_major = info2->generic.out.device;
901                 info->unix_basic_info.out.dev_minor = info2->generic.out.device;
902                 info->unix_basic_info.out.unique_id = info2->generic.out.inode;
903                 info->unix_basic_info.out.permissions = info2->generic.out.permissions;
904                 info->unix_basic_info.out.nlink = info2->generic.out.nlink;
905                 return NT_STATUS_OK;
906                 
907         case RAW_FILEINFO_UNIX_LINK:
908                 info->unix_link_info.out.link_dest = info2->generic.out.link_dest;
909                 return NT_STATUS_OK;
910 #endif
911         }
912
913         return NT_STATUS_INVALID_LEVEL;
914 }
915
916 /* 
917    NTVFS fileinfo generic to any mapper
918 */
919 NTSTATUS ntvfs_map_qfileinfo(struct ntvfs_module_context *ntvfs,
920                                       struct ntvfs_request *req,
921                                       union smb_fileinfo *info)
922 {
923         NTSTATUS status;
924         union smb_fileinfo *info2;
925
926         info2 = talloc(req, union smb_fileinfo);
927         if (info2 == NULL) {
928                 return NT_STATUS_NO_MEMORY;
929         }
930
931         if (info->generic.level == RAW_FILEINFO_GENERIC) {
932                 return NT_STATUS_INVALID_LEVEL;
933         }
934
935         /* ask the backend for the generic info */
936         info2->generic.level = RAW_FILEINFO_GENERIC;
937         info2->generic.in.file.ntvfs= info->generic.in.file.ntvfs;
938
939         /* only used by the simple backend, which doesn't do async */
940         req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
941
942         status = ntvfs->ops->qfileinfo(ntvfs, req, info2);
943         if (!NT_STATUS_IS_OK(status)) {
944                 return status;
945         }
946         return ntvfs_map_fileinfo(req, info, info2);
947 }
948
949 /* 
950    NTVFS pathinfo generic to any mapper
951 */
952 NTSTATUS ntvfs_map_qpathinfo(struct ntvfs_module_context *ntvfs,
953                                       struct ntvfs_request *req,
954                                       union smb_fileinfo *info)
955 {
956         NTSTATUS status;
957         union smb_fileinfo *info2;
958
959         info2 = talloc(req, union smb_fileinfo);
960         if (info2 == NULL) {
961                 return NT_STATUS_NO_MEMORY;
962         }
963
964         if (info->generic.level == RAW_FILEINFO_GENERIC) {
965                 return NT_STATUS_INVALID_LEVEL;
966         }
967
968         /* ask the backend for the generic info */
969         info2->generic.level            = RAW_FILEINFO_GENERIC;
970         info2->generic.in.file.path     = info->generic.in.file.path;
971
972         /* only used by the simple backend, which doesn't do async */
973         req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
974
975         status = ntvfs->ops->qpathinfo(ntvfs, req, info2);
976         if (!NT_STATUS_IS_OK(status)) {
977                 return status;
978         }
979         return ntvfs_map_fileinfo(req, info, info2);
980 }
981
982
983 /* 
984    NTVFS lock generic to any mapper
985 */
986 NTSTATUS ntvfs_map_lock(struct ntvfs_module_context *ntvfs,
987                         struct ntvfs_request *req,
988                         union smb_lock *lck)
989 {
990         union smb_lock *lck2;
991         struct smb_lock_entry *locks;
992
993         lck2 = talloc(req, union smb_lock);
994         if (lck2 == NULL) {
995                 return NT_STATUS_NO_MEMORY;
996         }
997
998         locks = talloc_array(lck2, struct smb_lock_entry, 1);
999         if (locks == NULL) {
1000                 return NT_STATUS_NO_MEMORY;
1001         }
1002
1003         switch (lck->generic.level) {
1004         case RAW_LOCK_LOCKX:
1005                 return NT_STATUS_INVALID_LEVEL;
1006
1007         case RAW_LOCK_LOCK:
1008                 lck2->generic.level = RAW_LOCK_GENERIC;
1009                 lck2->generic.in.file.ntvfs= lck->lock.in.file.ntvfs;
1010                 lck2->generic.in.mode = 0;
1011                 lck2->generic.in.timeout = 0;
1012                 lck2->generic.in.ulock_cnt = 0;
1013                 lck2->generic.in.lock_cnt = 1;
1014                 lck2->generic.in.locks = locks;
1015                 locks->pid = req->smbpid;
1016                 locks->offset = lck->lock.in.offset;
1017                 locks->count = lck->lock.in.count;
1018                 break;
1019
1020         case RAW_LOCK_UNLOCK:
1021                 lck2->generic.level = RAW_LOCK_GENERIC;
1022                 lck2->generic.in.file.ntvfs= lck->unlock.in.file.ntvfs;
1023                 lck2->generic.in.mode = 0;
1024                 lck2->generic.in.timeout = 0;
1025                 lck2->generic.in.ulock_cnt = 1;
1026                 lck2->generic.in.lock_cnt = 0;
1027                 lck2->generic.in.locks = locks;
1028                 locks->pid = req->smbpid;
1029                 locks->offset = lck->unlock.in.offset;
1030                 locks->count = lck->unlock.in.count;
1031                 break;
1032
1033         case RAW_LOCK_SMB2: {
1034                 /* this is only approximate! We need to change the
1035                    generic structure to fix this properly */
1036                 int i;
1037                 bool isunlock;
1038                 if (lck->smb2.in.lock_count < 1) {
1039                         return NT_STATUS_INVALID_PARAMETER;
1040                 }
1041
1042                 lck2->generic.level = RAW_LOCK_GENERIC;
1043                 lck2->generic.in.file.ntvfs= lck->smb2.in.file.ntvfs;
1044                 lck2->generic.in.timeout = UINT32_MAX;
1045                 lck2->generic.in.mode = 0;
1046                 lck2->generic.in.lock_cnt = 0;
1047                 lck2->generic.in.ulock_cnt = 0;
1048                 lck2->generic.in.locks = talloc_zero_array(lck2, struct smb_lock_entry, 
1049                                                            lck->smb2.in.lock_count);
1050                 if (lck2->generic.in.locks == NULL) {
1051                         return NT_STATUS_NO_MEMORY;
1052                 }
1053                 /* only the first lock gives the UNLOCK bit - see
1054                    MS-SMB2 3.3.5.14 */
1055                 if (lck->smb2.in.locks[0].flags & SMB2_LOCK_FLAG_UNLOCK) {
1056                         lck2->generic.in.ulock_cnt = lck->smb2.in.lock_count;
1057                         isunlock = true;
1058                 } else {
1059                         lck2->generic.in.lock_cnt = lck->smb2.in.lock_count;
1060                         isunlock = false;
1061                 }
1062                 for (i=0;i<lck->smb2.in.lock_count;i++) {
1063                         if (isunlock && 
1064                             (lck->smb2.in.locks[i].flags & 
1065                              (SMB2_LOCK_FLAG_SHARED|SMB2_LOCK_FLAG_EXCLUSIVE))) {
1066                                 return NT_STATUS_INVALID_PARAMETER;
1067                         }
1068                         if (!isunlock && 
1069                             (lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_UNLOCK)) {
1070                                 return NT_STATUS_INVALID_PARAMETER;
1071                         }
1072                         lck2->generic.in.locks[i].pid    = req->smbpid;
1073                         lck2->generic.in.locks[i].offset = lck->smb2.in.locks[i].offset;
1074                         lck2->generic.in.locks[i].count  = lck->smb2.in.locks[i].length;
1075                         if (!(lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_EXCLUSIVE)) {
1076                                 lck2->generic.in.mode = LOCKING_ANDX_SHARED_LOCK;
1077                         }
1078                         if (lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_FAIL_IMMEDIATELY) {
1079                                 lck2->generic.in.timeout = 0;
1080                         }
1081                 }
1082                 /* initialize output value */
1083                 lck->smb2.out.reserved = 0;
1084                 break;
1085         }
1086
1087         case RAW_LOCK_SMB2_BREAK:
1088                 lck2->generic.level             = RAW_LOCK_GENERIC;
1089                 lck2->generic.in.file.ntvfs     = lck->smb2_break.in.file.ntvfs;
1090                 lck2->generic.in.mode           = LOCKING_ANDX_OPLOCK_RELEASE |
1091                                                   ((lck->smb2_break.in.oplock_level << 8) & 0xFF00);
1092                 lck2->generic.in.timeout        = 0;
1093                 lck2->generic.in.ulock_cnt      = 0;
1094                 lck2->generic.in.lock_cnt       = 0;
1095                 lck2->generic.in.locks          = NULL;
1096
1097                 /* initialize output value */
1098                 lck->smb2_break.out.oplock_level= lck->smb2_break.in.oplock_level;
1099                 lck->smb2_break.out.reserved    = lck->smb2_break.in.reserved;
1100                 lck->smb2_break.out.reserved2   = lck->smb2_break.in.reserved2;
1101                 lck->smb2_break.out.file        = lck->smb2_break.in.file;
1102                 break;
1103         }
1104
1105         /* 
1106          * we don't need to call ntvfs_map_async_setup() here,
1107          * as lock() doesn't have any output fields
1108          */
1109
1110         return ntvfs->ops->lock(ntvfs, req, lck2);
1111 }
1112
1113
1114 /* 
1115    NTVFS write generic to any mapper
1116 */
1117 static NTSTATUS ntvfs_map_write_finish(struct ntvfs_module_context *ntvfs,
1118                                        struct ntvfs_request *req,
1119                                        union smb_write *wr, 
1120                                        union smb_write *wr2, 
1121                                        NTSTATUS status)
1122 {
1123         union smb_lock *lck;
1124         union smb_close *cl;
1125         uint_t state;
1126
1127         if (NT_STATUS_IS_ERR(status)) {
1128                 return status;
1129         }
1130
1131         switch (wr->generic.level) {
1132         case RAW_WRITE_WRITE:
1133                 wr->write.out.nwritten    = wr2->generic.out.nwritten;
1134                 break;
1135
1136         case RAW_WRITE_WRITEUNLOCK:
1137                 wr->writeunlock.out.nwritten = wr2->generic.out.nwritten;
1138
1139                 lck = talloc(wr2, union smb_lock);
1140                 if (lck == NULL) {
1141                         return NT_STATUS_NO_MEMORY;
1142                 }
1143
1144                 lck->unlock.level               = RAW_LOCK_UNLOCK;
1145                 lck->unlock.in.file.ntvfs       = wr->writeunlock.in.file.ntvfs;
1146                 lck->unlock.in.count            = wr->writeunlock.in.count;
1147                 lck->unlock.in.offset           = wr->writeunlock.in.offset;
1148
1149                 if (lck->unlock.in.count != 0) {
1150                         /* do the lock sync for now */
1151                         state = req->async_states->state;
1152                         req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1153                         status = ntvfs->ops->lock(ntvfs, req, lck);
1154                         req->async_states->state = state;
1155                 }
1156                 break;
1157
1158         case RAW_WRITE_WRITECLOSE:
1159                 wr->writeclose.out.nwritten    = wr2->generic.out.nwritten;
1160
1161                 cl = talloc(wr2, union smb_close);
1162                 if (cl == NULL) {
1163                         return NT_STATUS_NO_MEMORY;
1164                 }
1165
1166                 cl->close.level         = RAW_CLOSE_CLOSE;
1167                 cl->close.in.file.ntvfs = wr->writeclose.in.file.ntvfs;
1168                 cl->close.in.write_time = wr->writeclose.in.mtime;
1169
1170                 if (wr2->generic.in.count != 0) {
1171                         /* do the close sync for now */
1172                         state = req->async_states->state;
1173                         req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1174                         status = ntvfs->ops->close(ntvfs, req, cl);
1175                         req->async_states->state = state;
1176                 }
1177                 break;
1178
1179         case RAW_WRITE_SPLWRITE:
1180                 break;
1181
1182         case RAW_WRITE_SMB2:
1183                 wr->smb2.out._pad       = 0;
1184                 wr->smb2.out.nwritten   = wr2->generic.out.nwritten;
1185                 wr->smb2.out.unknown1   = 0;
1186                 break;
1187
1188         default:
1189                 return NT_STATUS_INVALID_LEVEL;
1190         }
1191
1192         return status;
1193 }
1194
1195
1196 /* 
1197    NTVFS write generic to any mapper
1198 */
1199 NTSTATUS ntvfs_map_write(struct ntvfs_module_context *ntvfs,
1200                                   struct ntvfs_request *req,
1201                                   union smb_write *wr)
1202 {
1203         union smb_write *wr2;
1204         NTSTATUS status;
1205
1206         wr2 = talloc(req, union smb_write);
1207         if (wr2 == NULL) {
1208                 return NT_STATUS_NO_MEMORY;
1209         }
1210
1211         status = ntvfs_map_async_setup(ntvfs, req, wr, wr2, 
1212                                        (second_stage_t)ntvfs_map_write_finish);
1213         if (!NT_STATUS_IS_OK(status)) {
1214                 return status;
1215         }
1216
1217         wr2->writex.level = RAW_WRITE_GENERIC;
1218
1219         switch (wr->generic.level) {
1220         case RAW_WRITE_WRITEX:
1221                 status = NT_STATUS_INVALID_LEVEL;
1222                 break;
1223
1224         case RAW_WRITE_WRITE:
1225                 wr2->writex.in.file.ntvfs= wr->write.in.file.ntvfs;
1226                 wr2->writex.in.offset    = wr->write.in.offset;
1227                 wr2->writex.in.wmode     = 0;
1228                 wr2->writex.in.remaining = wr->write.in.remaining;
1229                 wr2->writex.in.count     = wr->write.in.count;
1230                 wr2->writex.in.data      = wr->write.in.data;
1231                 status = ntvfs->ops->write(ntvfs, req, wr2);
1232                 break;
1233
1234         case RAW_WRITE_WRITEUNLOCK:
1235                 wr2->writex.in.file.ntvfs= wr->writeunlock.in.file.ntvfs;
1236                 wr2->writex.in.offset    = wr->writeunlock.in.offset;
1237                 wr2->writex.in.wmode     = 0;
1238                 wr2->writex.in.remaining = wr->writeunlock.in.remaining;
1239                 wr2->writex.in.count     = wr->writeunlock.in.count;
1240                 wr2->writex.in.data      = wr->writeunlock.in.data;
1241                 status = ntvfs->ops->write(ntvfs, req, wr2);
1242                 break;
1243
1244         case RAW_WRITE_WRITECLOSE:
1245                 wr2->writex.in.file.ntvfs= wr->writeclose.in.file.ntvfs;
1246                 wr2->writex.in.offset    = wr->writeclose.in.offset;
1247                 wr2->writex.in.wmode     = 0;
1248                 wr2->writex.in.remaining = 0;
1249                 wr2->writex.in.count     = wr->writeclose.in.count;
1250                 wr2->writex.in.data      = wr->writeclose.in.data;
1251                 status = ntvfs->ops->write(ntvfs, req, wr2);
1252                 break;
1253
1254         case RAW_WRITE_SPLWRITE:
1255                 wr2->writex.in.file.ntvfs= wr->splwrite.in.file.ntvfs;
1256                 wr2->writex.in.offset    = 0;
1257                 wr2->writex.in.wmode     = 0;
1258                 wr2->writex.in.remaining = 0;
1259                 wr2->writex.in.count     = wr->splwrite.in.count;
1260                 wr2->writex.in.data      = wr->splwrite.in.data;
1261                 status = ntvfs->ops->write(ntvfs, req, wr2);
1262                 break;
1263
1264         case RAW_WRITE_SMB2:
1265                 wr2->writex.in.file.ntvfs= wr->smb2.in.file.ntvfs;
1266                 wr2->writex.in.offset    = wr->smb2.in.offset;
1267                 wr2->writex.in.wmode     = 0;
1268                 wr2->writex.in.remaining = 0;
1269                 wr2->writex.in.count     = wr->smb2.in.data.length;
1270                 wr2->writex.in.data      = wr->smb2.in.data.data;
1271                 status = ntvfs->ops->write(ntvfs, req, wr2);
1272         }
1273
1274         return ntvfs_map_async_finish(req, status);
1275 }
1276
1277
1278 /* 
1279    NTVFS read generic to any mapper - finish the out mapping
1280 */
1281 static NTSTATUS ntvfs_map_read_finish(struct ntvfs_module_context *ntvfs,
1282                                       struct ntvfs_request *req, 
1283                                       union smb_read *rd, 
1284                                       union smb_read *rd2,
1285                                       NTSTATUS status)
1286 {
1287         switch (rd->generic.level) {
1288         case RAW_READ_READ:
1289                 rd->read.out.nread      = rd2->generic.out.nread;
1290                 break;
1291         case RAW_READ_READBRAW:
1292                 rd->readbraw.out.nread  = rd2->generic.out.nread;
1293                 break;
1294         case RAW_READ_LOCKREAD:
1295                 rd->lockread.out.nread  = rd2->generic.out.nread;
1296                 break;
1297         case RAW_READ_SMB2:
1298                 rd->smb2.out.data.length= rd2->generic.out.nread;
1299                 rd->smb2.out.remaining  = 0;
1300                 rd->smb2.out.reserved   = 0;
1301                 break;
1302         default:
1303                 return NT_STATUS_INVALID_LEVEL;
1304         }
1305
1306         return status;
1307 }
1308
1309 /* 
1310    NTVFS read* to readx mapper
1311 */
1312 NTSTATUS ntvfs_map_read(struct ntvfs_module_context *ntvfs,
1313                                  struct ntvfs_request *req,
1314                                  union smb_read *rd)
1315 {
1316         union smb_read *rd2;
1317         union smb_lock *lck;
1318         NTSTATUS status;
1319         uint_t state;
1320
1321         rd2 = talloc(req, union smb_read);
1322         if (rd2 == NULL) {
1323                 return NT_STATUS_NO_MEMORY;
1324         }
1325
1326         status = ntvfs_map_async_setup(ntvfs, req, rd, rd2, 
1327                                        (second_stage_t)ntvfs_map_read_finish);
1328         if (!NT_STATUS_IS_OK(status)) {
1329                 return status;
1330         }
1331
1332         rd2->readx.level = RAW_READ_READX;
1333         rd2->readx.in.read_for_execute = false;
1334
1335         switch (rd->generic.level) {
1336         case RAW_READ_READX:
1337                 status = NT_STATUS_INVALID_LEVEL;
1338                 break;
1339
1340         case RAW_READ_READ:
1341                 rd2->readx.in.file.ntvfs= rd->read.in.file.ntvfs;
1342                 rd2->readx.in.offset    = rd->read.in.offset;
1343                 rd2->readx.in.mincnt    = rd->read.in.count;
1344                 rd2->readx.in.maxcnt    = rd->read.in.count;
1345                 rd2->readx.in.remaining = rd->read.in.remaining;
1346                 rd2->readx.out.data     = rd->read.out.data;
1347                 status = ntvfs->ops->read(ntvfs, req, rd2);
1348                 break;
1349
1350         case RAW_READ_READBRAW:
1351                 rd2->readx.in.file.ntvfs= rd->readbraw.in.file.ntvfs;
1352                 rd2->readx.in.offset    = rd->readbraw.in.offset;
1353                 rd2->readx.in.mincnt    = rd->readbraw.in.mincnt;
1354                 rd2->readx.in.maxcnt    = rd->readbraw.in.maxcnt;
1355                 rd2->readx.in.remaining = 0;
1356                 rd2->readx.out.data     = rd->readbraw.out.data;
1357                 status = ntvfs->ops->read(ntvfs, req, rd2);
1358                 break;
1359
1360         case RAW_READ_LOCKREAD:
1361                 /* do the initial lock sync for now */
1362                 state = req->async_states->state;
1363                 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1364
1365                 lck = talloc(rd2, union smb_lock);
1366                 if (lck == NULL) {
1367                         status = NT_STATUS_NO_MEMORY;
1368                         goto done;
1369                 }
1370                 lck->lock.level         = RAW_LOCK_LOCK;
1371                 lck->lock.in.file.ntvfs = rd->lockread.in.file.ntvfs;
1372                 lck->lock.in.count      = rd->lockread.in.count;
1373                 lck->lock.in.offset     = rd->lockread.in.offset;
1374                 status = ntvfs->ops->lock(ntvfs, req, lck);
1375                 req->async_states->state = state;
1376
1377                 rd2->readx.in.file.ntvfs= rd->lockread.in.file.ntvfs;
1378                 rd2->readx.in.offset    = rd->lockread.in.offset;
1379                 rd2->readx.in.mincnt    = rd->lockread.in.count;
1380                 rd2->readx.in.maxcnt    = rd->lockread.in.count;
1381                 rd2->readx.in.remaining = rd->lockread.in.remaining;
1382                 rd2->readx.out.data     = rd->lockread.out.data;
1383
1384                 if (NT_STATUS_IS_OK(status)) {
1385                         status = ntvfs->ops->read(ntvfs, req, rd2);
1386                 }
1387                 break;
1388
1389         case RAW_READ_SMB2:
1390                 rd2->readx.in.file.ntvfs= rd->smb2.in.file.ntvfs;
1391                 rd2->readx.in.offset    = rd->smb2.in.offset;
1392                 rd2->readx.in.mincnt    = rd->smb2.in.min_count;
1393                 rd2->readx.in.maxcnt    = rd->smb2.in.length;
1394                 rd2->readx.in.remaining = 0;
1395                 rd2->readx.out.data     = rd->smb2.out.data.data;
1396                 status = ntvfs->ops->read(ntvfs, req, rd2);
1397                 break;
1398         }
1399
1400 done:
1401         return ntvfs_map_async_finish(req, status);
1402 }
1403
1404
1405 /* 
1406    NTVFS close generic to any mapper
1407 */
1408 static NTSTATUS ntvfs_map_close_finish(struct ntvfs_module_context *ntvfs,
1409                                         struct ntvfs_request *req,
1410                                         union smb_close *cl, 
1411                                         union smb_close *cl2, 
1412                                         NTSTATUS status)
1413 {
1414         NT_STATUS_NOT_OK_RETURN(status);
1415
1416         switch (cl->generic.level) {
1417         case RAW_CLOSE_SMB2:
1418                 cl->smb2.out.flags        = cl2->generic.out.flags;
1419                 cl->smb2.out._pad         = 0;
1420                 cl->smb2.out.create_time  = cl2->generic.out.create_time;
1421                 cl->smb2.out.access_time  = cl2->generic.out.access_time;
1422                 cl->smb2.out.write_time   = cl2->generic.out.write_time;
1423                 cl->smb2.out.change_time  = cl2->generic.out.change_time;
1424                 cl->smb2.out.alloc_size   = cl2->generic.out.alloc_size;
1425                 cl->smb2.out.size         = cl2->generic.out.size;
1426                 cl->smb2.out.file_attr    = cl2->generic.out.file_attr;
1427                 break;
1428         default:
1429                 break;
1430         }
1431
1432         return status;
1433 }
1434
1435 /* 
1436    NTVFS close generic to any mapper
1437 */
1438 NTSTATUS ntvfs_map_close(struct ntvfs_module_context *ntvfs,
1439                                   struct ntvfs_request *req,
1440                                   union smb_close *cl)
1441 {
1442         union smb_close *cl2;
1443         NTSTATUS status;
1444
1445         cl2 = talloc(req, union smb_close);
1446         if (cl2 == NULL) {
1447                 return NT_STATUS_NO_MEMORY;
1448         }
1449
1450         switch (cl->generic.level) {
1451         case RAW_CLOSE_GENERIC:
1452                 return NT_STATUS_INVALID_LEVEL;
1453
1454         case RAW_CLOSE_CLOSE:
1455                 cl2->generic.level              = RAW_CLOSE_GENERIC;
1456                 cl2->generic.in.file            = cl->close.in.file;
1457                 cl2->generic.in.write_time      = cl->close.in.write_time;
1458                 cl2->generic.in.flags           = 0;
1459                 break;
1460
1461         case RAW_CLOSE_SPLCLOSE:
1462                 cl2->generic.level              = RAW_CLOSE_GENERIC;
1463                 cl2->generic.in.file            = cl->splclose.in.file;
1464                 cl2->generic.in.write_time      = 0;
1465                 cl2->generic.in.flags           = 0;
1466                 break;
1467
1468         case RAW_CLOSE_SMB2:
1469                 cl2->generic.level              = RAW_CLOSE_GENERIC;
1470                 cl2->generic.in.file            = cl->smb2.in.file;
1471                 cl2->generic.in.write_time      = 0;
1472                 cl2->generic.in.flags           = cl->smb2.in.flags;
1473                 break;
1474         }
1475
1476         status = ntvfs_map_async_setup(ntvfs, req, cl, cl2, 
1477                                        (second_stage_t)ntvfs_map_close_finish);
1478         NT_STATUS_NOT_OK_RETURN(status);
1479
1480         status = ntvfs->ops->close(ntvfs, req, cl2);
1481
1482         return ntvfs_map_async_finish(req, status);
1483 }
1484
1485 /* 
1486    NTVFS notify generic to any mapper
1487 */
1488 static NTSTATUS ntvfs_map_notify_finish(struct ntvfs_module_context *ntvfs,
1489                                         struct ntvfs_request *req,
1490                                         union smb_notify *nt, 
1491                                         union smb_notify *nt2, 
1492                                         NTSTATUS status)
1493 {
1494         NT_STATUS_NOT_OK_RETURN(status);
1495
1496         switch (nt->nttrans.level) {
1497         case RAW_NOTIFY_SMB2:
1498                 if (nt2->nttrans.out.num_changes == 0) {
1499                         return STATUS_NOTIFY_ENUM_DIR;
1500                 }
1501                 nt->smb2.out.num_changes        = nt2->nttrans.out.num_changes;
1502                 nt->smb2.out.changes            = talloc_steal(req, nt2->nttrans.out.changes);
1503                 break;
1504
1505         default:
1506                 return NT_STATUS_INVALID_LEVEL;
1507         }
1508
1509         return status;
1510 }
1511
1512
1513 /* 
1514    NTVFS notify generic to any mapper
1515 */
1516 NTSTATUS ntvfs_map_notify(struct ntvfs_module_context *ntvfs,
1517                                    struct ntvfs_request *req,
1518                                    union smb_notify *nt)
1519 {
1520         union smb_notify *nt2;
1521         NTSTATUS status;
1522
1523         nt2 = talloc(req, union smb_notify);
1524         NT_STATUS_HAVE_NO_MEMORY(nt2);
1525
1526         status = ntvfs_map_async_setup(ntvfs, req, nt, nt2, 
1527                                        (second_stage_t)ntvfs_map_notify_finish);
1528         NT_STATUS_NOT_OK_RETURN(status);
1529
1530         nt2->nttrans.level = RAW_NOTIFY_NTTRANS;
1531
1532         switch (nt->nttrans.level) {
1533         case RAW_NOTIFY_NTTRANS:
1534                 status = NT_STATUS_INVALID_LEVEL;
1535                 break;
1536
1537         case RAW_NOTIFY_SMB2:
1538                 nt2->nttrans.in.file.ntvfs              = nt->smb2.in.file.ntvfs;
1539                 nt2->nttrans.in.buffer_size             = nt->smb2.in.buffer_size;
1540                 nt2->nttrans.in.completion_filter       = nt->smb2.in.completion_filter;
1541                 nt2->nttrans.in.recursive               = nt->smb2.in.recursive;
1542                 status = ntvfs->ops->notify(ntvfs, req, nt2);
1543                 break;
1544         }
1545
1546         return ntvfs_map_async_finish(req, status);
1547 }