Merge branch 'master' of ssh://git.samba.org/data/git/samba into selftest
[tprouty/samba.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                         DEBUG(2,(__location__ " create_options 0x%x not supported\n",
537                                  io2->generic.in.create_options));
538                         status = NT_STATUS_NOT_SUPPORTED;
539                         break;
540                 }
541
542                 /* TODO: find out why only SMB2 ignores these */
543                 io2->generic.in.create_options &= ~NTCREATEX_OPTIONS_SYNC_ALERT;
544                 io2->generic.in.create_options &= ~NTCREATEX_OPTIONS_ASYNC_ALERT;
545
546                 status = ntvfs->ops->open(ntvfs, req, io2);             
547                 break;
548
549         default:
550                 status = NT_STATUS_INVALID_LEVEL;
551                 break;
552         }
553 done:
554         return ntvfs_map_async_finish(req, status);
555 }
556
557
558 /* 
559    NTVFS fsinfo generic to any mapper
560 */
561 NTSTATUS ntvfs_map_fsinfo(struct ntvfs_module_context *ntvfs,
562                                    struct ntvfs_request *req,
563                                    union smb_fsinfo *fs)
564 {
565         NTSTATUS status;
566         union smb_fsinfo *fs2;
567
568         fs2 = talloc(req, union smb_fsinfo);
569         if (fs2 == NULL) {
570                 return NT_STATUS_NO_MEMORY;
571         }
572
573         if (fs->generic.level == RAW_QFS_GENERIC) {
574                 return NT_STATUS_INVALID_LEVEL;
575         }
576         
577         /* only used by the simple backend, which doesn't do async */
578         req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
579
580         /* ask the backend for the generic info */
581         fs2->generic.level = RAW_QFS_GENERIC;
582
583         status = ntvfs->ops->fsinfo(ntvfs, req, fs2);
584         if (!NT_STATUS_IS_OK(status)) {
585                 return status;
586         }
587
588         /* and convert it to the required level */
589         switch (fs->generic.level) {
590         case RAW_QFS_GENERIC:
591                 return NT_STATUS_INVALID_LEVEL;
592
593         case RAW_QFS_DSKATTR: {
594                 /* map from generic to DSKATTR */
595                 uint_t bpunit = 64;
596
597                 /* we need to scale the sizes to fit */
598                 for (bpunit=64; bpunit<0x10000; bpunit *= 2) {
599                         if (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size < bpunit * 512 * 65535.0) {
600                                 break;
601                         }
602                 }
603
604                 fs->dskattr.out.blocks_per_unit = bpunit;
605                 fs->dskattr.out.block_size = 512;
606                 fs->dskattr.out.units_total = 
607                         (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size) / (bpunit * 512);
608                 fs->dskattr.out.units_free  = 
609                         (fs2->generic.out.blocks_free  * (double)fs2->generic.out.block_size) / (bpunit * 512);
610
611                 /* we must return a maximum of 2G to old DOS systems, or they get very confused */
612                 if (bpunit > 64 && req->ctx->protocol <= PROTOCOL_LANMAN2) {
613                         fs->dskattr.out.blocks_per_unit = 64;
614                         fs->dskattr.out.units_total = 0xFFFF;
615                         fs->dskattr.out.units_free = 0xFFFF;
616                 }
617                 return NT_STATUS_OK;
618         }
619
620         case RAW_QFS_ALLOCATION:
621                 fs->allocation.out.fs_id = fs2->generic.out.fs_id;
622                 fs->allocation.out.total_alloc_units = fs2->generic.out.blocks_total;
623                 fs->allocation.out.avail_alloc_units = fs2->generic.out.blocks_free;
624                 fs->allocation.out.sectors_per_unit = 1;
625                 fs->allocation.out.bytes_per_sector = fs2->generic.out.block_size;
626                 return NT_STATUS_OK;
627
628         case RAW_QFS_VOLUME:
629                 fs->volume.out.serial_number = fs2->generic.out.serial_number;
630                 fs->volume.out.volume_name.s = fs2->generic.out.volume_name;
631                 return NT_STATUS_OK;
632
633         case RAW_QFS_VOLUME_INFO:
634         case RAW_QFS_VOLUME_INFORMATION:
635                 fs->volume_info.out.create_time = fs2->generic.out.create_time;
636                 fs->volume_info.out.serial_number = fs2->generic.out.serial_number;
637                 fs->volume_info.out.volume_name.s = fs2->generic.out.volume_name;
638                 return NT_STATUS_OK;
639
640         case RAW_QFS_SIZE_INFO:
641         case RAW_QFS_SIZE_INFORMATION:
642                 fs->size_info.out.total_alloc_units = fs2->generic.out.blocks_total;
643                 fs->size_info.out.avail_alloc_units = fs2->generic.out.blocks_free;
644                 fs->size_info.out.sectors_per_unit = 1;
645                 fs->size_info.out.bytes_per_sector = fs2->generic.out.block_size;
646                 return NT_STATUS_OK;
647
648         case RAW_QFS_DEVICE_INFO:
649         case RAW_QFS_DEVICE_INFORMATION:
650                 fs->device_info.out.device_type = fs2->generic.out.device_type;
651                 fs->device_info.out.characteristics = fs2->generic.out.device_characteristics;
652                 return NT_STATUS_OK;
653
654         case RAW_QFS_ATTRIBUTE_INFO:
655         case RAW_QFS_ATTRIBUTE_INFORMATION:
656                 fs->attribute_info.out.fs_attr = fs2->generic.out.fs_attr;
657                 fs->attribute_info.out.max_file_component_length = fs2->generic.out.max_file_component_length;
658                 fs->attribute_info.out.fs_type.s = fs2->generic.out.fs_type;
659                 return NT_STATUS_OK;
660
661         case RAW_QFS_QUOTA_INFORMATION:
662                 ZERO_STRUCT(fs->quota_information.out.unknown);
663                 fs->quota_information.out.quota_soft = fs2->generic.out.quota_soft;
664                 fs->quota_information.out.quota_hard = fs2->generic.out.quota_hard;
665                 fs->quota_information.out.quota_flags = fs2->generic.out.quota_flags;
666                 return NT_STATUS_OK;
667
668         case RAW_QFS_FULL_SIZE_INFORMATION:
669                 fs->full_size_information.out.total_alloc_units = fs2->generic.out.blocks_total;
670                 fs->full_size_information.out.call_avail_alloc_units = fs2->generic.out.blocks_free;
671                 fs->full_size_information.out.actual_avail_alloc_units = fs2->generic.out.blocks_free;
672                 fs->full_size_information.out.sectors_per_unit = 1;
673                 fs->full_size_information.out.bytes_per_sector = fs2->generic.out.block_size;
674                 return NT_STATUS_OK;
675
676         case RAW_QFS_OBJECTID_INFORMATION:
677                 fs->objectid_information.out.guid = fs2->generic.out.guid;
678                 ZERO_STRUCT(fs->objectid_information.out.unknown);
679                 return NT_STATUS_OK;
680         }
681
682
683         return NT_STATUS_INVALID_LEVEL;
684 }
685
686
687 /* 
688    NTVFS fileinfo generic to any mapper
689 */
690 NTSTATUS ntvfs_map_fileinfo(TALLOC_CTX *mem_ctx,
691                                      union smb_fileinfo *info, 
692                                      union smb_fileinfo *info2)
693 {
694         int i;
695         /* and convert it to the required level using results in info2 */
696         switch (info->generic.level) {
697                 case RAW_FILEINFO_GENERIC:
698                 return NT_STATUS_INVALID_LEVEL;
699         case RAW_FILEINFO_GETATTR:
700                 info->getattr.out.attrib = info2->generic.out.attrib & 0xff;
701                 info->getattr.out.size = info2->generic.out.size;
702                 info->getattr.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
703                 return NT_STATUS_OK;
704                 
705         case RAW_FILEINFO_GETATTRE:
706                 info->getattre.out.attrib = info2->generic.out.attrib;
707                 info->getattre.out.size = info2->generic.out.size;
708                 info->getattre.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
709                 info->getattre.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
710                 info->getattre.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
711                 info->getattre.out.alloc_size = info2->generic.out.alloc_size;
712                 return NT_STATUS_OK;
713                 
714         case RAW_FILEINFO_NETWORK_OPEN_INFORMATION:
715                 info->network_open_information.out.create_time = info2->generic.out.create_time;
716                 info->network_open_information.out.access_time = info2->generic.out.access_time;
717                 info->network_open_information.out.write_time =  info2->generic.out.write_time;
718                 info->network_open_information.out.change_time = info2->generic.out.change_time;
719                 info->network_open_information.out.alloc_size = info2->generic.out.alloc_size;
720                 info->network_open_information.out.size = info2->generic.out.size;
721                 info->network_open_information.out.attrib = info2->generic.out.attrib;
722                 return NT_STATUS_OK;
723
724         case RAW_FILEINFO_ALL_INFO:
725         case RAW_FILEINFO_ALL_INFORMATION:
726                 info->all_info.out.create_time = info2->generic.out.create_time;
727                 info->all_info.out.access_time = info2->generic.out.access_time;
728                 info->all_info.out.write_time =  info2->generic.out.write_time;
729                 info->all_info.out.change_time = info2->generic.out.change_time;
730                 info->all_info.out.attrib = info2->generic.out.attrib;
731                 info->all_info.out.alloc_size = info2->generic.out.alloc_size;
732                 info->all_info.out.size = info2->generic.out.size;
733                 info->all_info.out.nlink = info2->generic.out.nlink;
734                 info->all_info.out.delete_pending = info2->generic.out.delete_pending;
735                 info->all_info.out.directory = info2->generic.out.directory;
736                 info->all_info.out.ea_size = info2->generic.out.ea_size;
737                 info->all_info.out.fname.s = info2->generic.out.fname.s;
738                 info->all_info.out.fname.private_length = info2->generic.out.fname.private_length;
739                 return NT_STATUS_OK;
740
741         case RAW_FILEINFO_BASIC_INFO:
742         case RAW_FILEINFO_BASIC_INFORMATION:
743                 info->basic_info.out.create_time = info2->generic.out.create_time;
744                 info->basic_info.out.access_time = info2->generic.out.access_time;
745                 info->basic_info.out.write_time = info2->generic.out.write_time;
746                 info->basic_info.out.change_time = info2->generic.out.change_time;
747                 info->basic_info.out.attrib = info2->generic.out.attrib;
748                 return NT_STATUS_OK;
749
750         case RAW_FILEINFO_STANDARD:
751                 info->standard.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
752                 info->standard.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
753                 info->standard.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
754                 info->standard.out.size = info2->generic.out.size;
755                 info->standard.out.alloc_size = info2->generic.out.alloc_size;
756                 info->standard.out.attrib = info2->generic.out.attrib;
757                 return NT_STATUS_OK;
758
759         case RAW_FILEINFO_EA_SIZE:
760                 info->ea_size.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
761                 info->ea_size.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
762                 info->ea_size.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
763                 info->ea_size.out.size = info2->generic.out.size;
764                 info->ea_size.out.alloc_size = info2->generic.out.alloc_size;
765                 info->ea_size.out.attrib = info2->generic.out.attrib;
766                 info->ea_size.out.ea_size = info2->generic.out.ea_size;
767                 return NT_STATUS_OK;
768
769         case RAW_FILEINFO_STANDARD_INFO:
770         case RAW_FILEINFO_STANDARD_INFORMATION:
771                 info->standard_info.out.alloc_size = info2->generic.out.alloc_size;
772                 info->standard_info.out.size = info2->generic.out.size;
773                 info->standard_info.out.nlink = info2->generic.out.nlink;
774                 info->standard_info.out.delete_pending = info2->generic.out.delete_pending;
775                 info->standard_info.out.directory = info2->generic.out.directory;
776                 return NT_STATUS_OK;
777
778         case RAW_FILEINFO_INTERNAL_INFORMATION:
779                 info->internal_information.out.file_id = info2->generic.out.file_id;
780                 return NT_STATUS_OK;
781
782         case RAW_FILEINFO_EA_INFO:
783         case RAW_FILEINFO_EA_INFORMATION:
784                 info->ea_info.out.ea_size = info2->generic.out.ea_size;
785                 return NT_STATUS_OK;
786
787         case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION:
788                 info->attribute_tag_information.out.attrib = info2->generic.out.attrib;
789                 info->attribute_tag_information.out.reparse_tag = info2->generic.out.reparse_tag;
790                 return NT_STATUS_OK;
791
792         case RAW_FILEINFO_STREAM_INFO:
793         case RAW_FILEINFO_STREAM_INFORMATION:
794                 info->stream_info.out.num_streams = info2->generic.out.num_streams;
795                 if (info->stream_info.out.num_streams > 0) {
796                         info->stream_info.out.streams = 
797                                 talloc_array(mem_ctx, 
798                                                struct stream_struct,
799                                                info->stream_info.out.num_streams);
800                         if (!info->stream_info.out.streams) {
801                                 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d streams\n",
802                                         info->stream_info.out.num_streams));
803                                 return NT_STATUS_NO_MEMORY;
804                         }
805                         for (i=0; i < info->stream_info.out.num_streams; i++) {
806                                 info->stream_info.out.streams[i] = info2->generic.out.streams[i];
807                                 info->stream_info.out.streams[i].stream_name.s = 
808                                         talloc_strdup(info->stream_info.out.streams,
809                                                       info2->generic.out.streams[i].stream_name.s);
810                                 if (!info->stream_info.out.streams[i].stream_name.s) {
811                                         DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
812                                         return NT_STATUS_NO_MEMORY;
813                                 }
814                         }
815                 }
816                 return NT_STATUS_OK;
817
818         case RAW_FILEINFO_NAME_INFO:
819         case RAW_FILEINFO_NAME_INFORMATION:
820                 info->name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.fname.s);
821                 NT_STATUS_HAVE_NO_MEMORY(info->name_info.out.fname.s);
822                 info->name_info.out.fname.private_length = info2->generic.out.fname.private_length;
823                 return NT_STATUS_OK;
824                 
825         case RAW_FILEINFO_ALT_NAME_INFO:
826         case RAW_FILEINFO_ALT_NAME_INFORMATION:
827                 info->alt_name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.alt_fname.s);
828                 NT_STATUS_HAVE_NO_MEMORY(info->alt_name_info.out.fname.s);
829                 info->alt_name_info.out.fname.private_length = info2->generic.out.alt_fname.private_length;
830                 return NT_STATUS_OK;
831         
832         case RAW_FILEINFO_POSITION_INFORMATION:
833                 info->position_information.out.position = info2->generic.out.position;
834                 return NT_STATUS_OK;
835         
836         case RAW_FILEINFO_ALL_EAS:
837                 info->all_eas.out.num_eas = info2->generic.out.num_eas;
838                 if (info->all_eas.out.num_eas > 0) {
839                         info->all_eas.out.eas = talloc_array(mem_ctx, 
840                                                                struct ea_struct,
841                                                                info->all_eas.out.num_eas);
842                         if (!info->all_eas.out.eas) {
843                                 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d eas\n",
844                                         info->all_eas.out.num_eas));
845                                 return NT_STATUS_NO_MEMORY;
846                         }
847                         for (i = 0; i < info->all_eas.out.num_eas; i++) {
848                                 info->all_eas.out.eas[i] = info2->generic.out.eas[i];
849                                 info->all_eas.out.eas[i].name.s = 
850                                         talloc_strdup(info->all_eas.out.eas,
851                                                       info2->generic.out.eas[i].name.s);
852                                 if (!info->all_eas.out.eas[i].name.s) {
853                                         DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
854                                         return NT_STATUS_NO_MEMORY;
855                                 }
856                                 info->all_eas.out.eas[i].value.data = 
857                                         talloc_memdup(info->all_eas.out.eas,
858                                                 info2->generic.out.eas[i].value.data,
859                                                 info2->generic.out.eas[i].value.length);
860                                 if (!info->all_eas.out.eas[i].value.data) {
861                                         DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
862                                         return NT_STATUS_NO_MEMORY;
863                                 }
864                         }
865                 }
866                 return NT_STATUS_OK;
867                 
868         case RAW_FILEINFO_IS_NAME_VALID:
869                 return NT_STATUS_OK;
870                 
871         case RAW_FILEINFO_COMPRESSION_INFO:
872         case RAW_FILEINFO_COMPRESSION_INFORMATION:
873                 info->compression_info.out.compressed_size = info2->generic.out.compressed_size;
874                 info->compression_info.out.format = info2->generic.out.format;
875                 info->compression_info.out.unit_shift = info2->generic.out.unit_shift;
876                 info->compression_info.out.chunk_shift = info2->generic.out.chunk_shift;
877                 info->compression_info.out.cluster_shift = info2->generic.out.cluster_shift;
878                 return NT_STATUS_OK;
879                 
880         case RAW_FILEINFO_ACCESS_INFORMATION:
881                 info->access_information.out.access_flags = info2->generic.out.access_flags;
882                 return NT_STATUS_OK;
883                 
884         case RAW_FILEINFO_MODE_INFORMATION:
885                 info->mode_information.out.mode = info2->generic.out.mode;
886                 return NT_STATUS_OK;
887                 
888         case RAW_FILEINFO_ALIGNMENT_INFORMATION:
889                 info->alignment_information.out.alignment_requirement =
890                         info2->generic.out.alignment_requirement;
891                 return NT_STATUS_OK;
892 #if 0   
893         case RAW_FILEINFO_UNIX_BASIC:
894                 info->unix_basic_info.out.end_of_file = info2->generic.out.end_of_file;
895                 info->unix_basic_info.out.num_bytes = info2->generic.out.size;
896                 info->unix_basic_info.out.status_change_time = info2->generic.out.change_time;
897                 info->unix_basic_info.out.access_time = info2->generic.out.access_time;
898                 info->unix_basic_info.out.change_time = info2->generic.out.change_time;
899                 info->unix_basic_info.out.uid = info2->generic.out.uid;
900                 info->unix_basic_info.out.gid = info2->generic.out.gid;
901                 info->unix_basic_info.out.file_type = info2->generic.out.file_type;
902                 info->unix_basic_info.out.dev_major = info2->generic.out.device;
903                 info->unix_basic_info.out.dev_minor = info2->generic.out.device;
904                 info->unix_basic_info.out.unique_id = info2->generic.out.inode;
905                 info->unix_basic_info.out.permissions = info2->generic.out.permissions;
906                 info->unix_basic_info.out.nlink = info2->generic.out.nlink;
907                 return NT_STATUS_OK;
908                 
909         case RAW_FILEINFO_UNIX_LINK:
910                 info->unix_link_info.out.link_dest = info2->generic.out.link_dest;
911                 return NT_STATUS_OK;
912 #endif
913         }
914
915         return NT_STATUS_INVALID_LEVEL;
916 }
917
918 /* 
919    NTVFS fileinfo generic to any mapper
920 */
921 NTSTATUS ntvfs_map_qfileinfo(struct ntvfs_module_context *ntvfs,
922                                       struct ntvfs_request *req,
923                                       union smb_fileinfo *info)
924 {
925         NTSTATUS status;
926         union smb_fileinfo *info2;
927
928         info2 = talloc(req, union smb_fileinfo);
929         if (info2 == NULL) {
930                 return NT_STATUS_NO_MEMORY;
931         }
932
933         if (info->generic.level == RAW_FILEINFO_GENERIC) {
934                 return NT_STATUS_INVALID_LEVEL;
935         }
936
937         /* ask the backend for the generic info */
938         info2->generic.level = RAW_FILEINFO_GENERIC;
939         info2->generic.in.file.ntvfs= info->generic.in.file.ntvfs;
940
941         /* only used by the simple backend, which doesn't do async */
942         req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
943
944         status = ntvfs->ops->qfileinfo(ntvfs, req, info2);
945         if (!NT_STATUS_IS_OK(status)) {
946                 return status;
947         }
948         return ntvfs_map_fileinfo(req, info, info2);
949 }
950
951 /* 
952    NTVFS pathinfo generic to any mapper
953 */
954 NTSTATUS ntvfs_map_qpathinfo(struct ntvfs_module_context *ntvfs,
955                                       struct ntvfs_request *req,
956                                       union smb_fileinfo *info)
957 {
958         NTSTATUS status;
959         union smb_fileinfo *info2;
960
961         info2 = talloc(req, union smb_fileinfo);
962         if (info2 == NULL) {
963                 return NT_STATUS_NO_MEMORY;
964         }
965
966         if (info->generic.level == RAW_FILEINFO_GENERIC) {
967                 return NT_STATUS_INVALID_LEVEL;
968         }
969
970         /* ask the backend for the generic info */
971         info2->generic.level            = RAW_FILEINFO_GENERIC;
972         info2->generic.in.file.path     = info->generic.in.file.path;
973
974         /* only used by the simple backend, which doesn't do async */
975         req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
976
977         status = ntvfs->ops->qpathinfo(ntvfs, req, info2);
978         if (!NT_STATUS_IS_OK(status)) {
979                 return status;
980         }
981         return ntvfs_map_fileinfo(req, info, info2);
982 }
983
984
985 /* 
986    NTVFS lock generic to any mapper
987 */
988 NTSTATUS ntvfs_map_lock(struct ntvfs_module_context *ntvfs,
989                         struct ntvfs_request *req,
990                         union smb_lock *lck)
991 {
992         union smb_lock *lck2;
993         struct smb_lock_entry *locks;
994
995         lck2 = talloc(req, union smb_lock);
996         if (lck2 == NULL) {
997                 return NT_STATUS_NO_MEMORY;
998         }
999
1000         locks = talloc_array(lck2, struct smb_lock_entry, 1);
1001         if (locks == NULL) {
1002                 return NT_STATUS_NO_MEMORY;
1003         }
1004
1005         switch (lck->generic.level) {
1006         case RAW_LOCK_LOCKX:
1007                 return NT_STATUS_INVALID_LEVEL;
1008
1009         case RAW_LOCK_LOCK:
1010                 lck2->generic.level = RAW_LOCK_GENERIC;
1011                 lck2->generic.in.file.ntvfs= lck->lock.in.file.ntvfs;
1012                 lck2->generic.in.mode = 0;
1013                 lck2->generic.in.timeout = 0;
1014                 lck2->generic.in.ulock_cnt = 0;
1015                 lck2->generic.in.lock_cnt = 1;
1016                 lck2->generic.in.locks = locks;
1017                 locks->pid = req->smbpid;
1018                 locks->offset = lck->lock.in.offset;
1019                 locks->count = lck->lock.in.count;
1020                 break;
1021
1022         case RAW_LOCK_UNLOCK:
1023                 lck2->generic.level = RAW_LOCK_GENERIC;
1024                 lck2->generic.in.file.ntvfs= lck->unlock.in.file.ntvfs;
1025                 lck2->generic.in.mode = 0;
1026                 lck2->generic.in.timeout = 0;
1027                 lck2->generic.in.ulock_cnt = 1;
1028                 lck2->generic.in.lock_cnt = 0;
1029                 lck2->generic.in.locks = locks;
1030                 locks->pid = req->smbpid;
1031                 locks->offset = lck->unlock.in.offset;
1032                 locks->count = lck->unlock.in.count;
1033                 break;
1034
1035         case RAW_LOCK_SMB2: {
1036                 /* this is only approximate! We need to change the
1037                    generic structure to fix this properly */
1038                 int i;
1039                 bool isunlock;
1040                 if (lck->smb2.in.lock_count < 1) {
1041                         return NT_STATUS_INVALID_PARAMETER;
1042                 }
1043
1044                 lck2->generic.level = RAW_LOCK_GENERIC;
1045                 lck2->generic.in.file.ntvfs= lck->smb2.in.file.ntvfs;
1046                 lck2->generic.in.timeout = UINT32_MAX;
1047                 lck2->generic.in.mode = 0;
1048                 lck2->generic.in.lock_cnt = 0;
1049                 lck2->generic.in.ulock_cnt = 0;
1050                 lck2->generic.in.locks = talloc_zero_array(lck2, struct smb_lock_entry, 
1051                                                            lck->smb2.in.lock_count);
1052                 if (lck2->generic.in.locks == NULL) {
1053                         return NT_STATUS_NO_MEMORY;
1054                 }
1055                 /* only the first lock gives the UNLOCK bit - see
1056                    MS-SMB2 3.3.5.14 */
1057                 if (lck->smb2.in.locks[0].flags & SMB2_LOCK_FLAG_UNLOCK) {
1058                         lck2->generic.in.ulock_cnt = lck->smb2.in.lock_count;
1059                         isunlock = true;
1060                 } else {
1061                         lck2->generic.in.lock_cnt = lck->smb2.in.lock_count;
1062                         isunlock = false;
1063                 }
1064                 for (i=0;i<lck->smb2.in.lock_count;i++) {
1065                         if (isunlock && 
1066                             (lck->smb2.in.locks[i].flags & 
1067                              (SMB2_LOCK_FLAG_SHARED|SMB2_LOCK_FLAG_EXCLUSIVE))) {
1068                                 return NT_STATUS_INVALID_PARAMETER;
1069                         }
1070                         if (!isunlock && 
1071                             (lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_UNLOCK)) {
1072                                 return NT_STATUS_INVALID_PARAMETER;
1073                         }
1074                         lck2->generic.in.locks[i].pid    = req->smbpid;
1075                         lck2->generic.in.locks[i].offset = lck->smb2.in.locks[i].offset;
1076                         lck2->generic.in.locks[i].count  = lck->smb2.in.locks[i].length;
1077                         if (!(lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_EXCLUSIVE)) {
1078                                 lck2->generic.in.mode = LOCKING_ANDX_SHARED_LOCK;
1079                         }
1080                         if (lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_FAIL_IMMEDIATELY) {
1081                                 lck2->generic.in.timeout = 0;
1082                         }
1083                 }
1084                 /* initialize output value */
1085                 lck->smb2.out.reserved = 0;
1086                 break;
1087         }
1088
1089         case RAW_LOCK_SMB2_BREAK:
1090                 lck2->generic.level             = RAW_LOCK_GENERIC;
1091                 lck2->generic.in.file.ntvfs     = lck->smb2_break.in.file.ntvfs;
1092                 lck2->generic.in.mode           = LOCKING_ANDX_OPLOCK_RELEASE |
1093                                                   ((lck->smb2_break.in.oplock_level << 8) & 0xFF00);
1094                 lck2->generic.in.timeout        = 0;
1095                 lck2->generic.in.ulock_cnt      = 0;
1096                 lck2->generic.in.lock_cnt       = 0;
1097                 lck2->generic.in.locks          = NULL;
1098
1099                 /* initialize output value */
1100                 lck->smb2_break.out.oplock_level= lck->smb2_break.in.oplock_level;
1101                 lck->smb2_break.out.reserved    = lck->smb2_break.in.reserved;
1102                 lck->smb2_break.out.reserved2   = lck->smb2_break.in.reserved2;
1103                 lck->smb2_break.out.file        = lck->smb2_break.in.file;
1104                 break;
1105         }
1106
1107         /* 
1108          * we don't need to call ntvfs_map_async_setup() here,
1109          * as lock() doesn't have any output fields
1110          */
1111
1112         return ntvfs->ops->lock(ntvfs, req, lck2);
1113 }
1114
1115
1116 /* 
1117    NTVFS write generic to any mapper
1118 */
1119 static NTSTATUS ntvfs_map_write_finish(struct ntvfs_module_context *ntvfs,
1120                                        struct ntvfs_request *req,
1121                                        union smb_write *wr, 
1122                                        union smb_write *wr2, 
1123                                        NTSTATUS status)
1124 {
1125         union smb_lock *lck;
1126         union smb_close *cl;
1127         uint_t state;
1128
1129         if (NT_STATUS_IS_ERR(status)) {
1130                 return status;
1131         }
1132
1133         switch (wr->generic.level) {
1134         case RAW_WRITE_WRITE:
1135                 wr->write.out.nwritten    = wr2->generic.out.nwritten;
1136                 break;
1137
1138         case RAW_WRITE_WRITEUNLOCK:
1139                 wr->writeunlock.out.nwritten = wr2->generic.out.nwritten;
1140
1141                 lck = talloc(wr2, union smb_lock);
1142                 if (lck == NULL) {
1143                         return NT_STATUS_NO_MEMORY;
1144                 }
1145
1146                 lck->unlock.level               = RAW_LOCK_UNLOCK;
1147                 lck->unlock.in.file.ntvfs       = wr->writeunlock.in.file.ntvfs;
1148                 lck->unlock.in.count            = wr->writeunlock.in.count;
1149                 lck->unlock.in.offset           = wr->writeunlock.in.offset;
1150
1151                 if (lck->unlock.in.count != 0) {
1152                         /* do the lock sync for now */
1153                         state = req->async_states->state;
1154                         req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1155                         status = ntvfs->ops->lock(ntvfs, req, lck);
1156                         req->async_states->state = state;
1157                 }
1158                 break;
1159
1160         case RAW_WRITE_WRITECLOSE:
1161                 wr->writeclose.out.nwritten    = wr2->generic.out.nwritten;
1162
1163                 cl = talloc(wr2, union smb_close);
1164                 if (cl == NULL) {
1165                         return NT_STATUS_NO_MEMORY;
1166                 }
1167
1168                 cl->close.level         = RAW_CLOSE_CLOSE;
1169                 cl->close.in.file.ntvfs = wr->writeclose.in.file.ntvfs;
1170                 cl->close.in.write_time = wr->writeclose.in.mtime;
1171
1172                 if (wr2->generic.in.count != 0) {
1173                         /* do the close sync for now */
1174                         state = req->async_states->state;
1175                         req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1176                         status = ntvfs->ops->close(ntvfs, req, cl);
1177                         req->async_states->state = state;
1178                 }
1179                 break;
1180
1181         case RAW_WRITE_SPLWRITE:
1182                 break;
1183
1184         case RAW_WRITE_SMB2:
1185                 wr->smb2.out._pad       = 0;
1186                 wr->smb2.out.nwritten   = wr2->generic.out.nwritten;
1187                 wr->smb2.out.unknown1   = 0;
1188                 break;
1189
1190         default:
1191                 return NT_STATUS_INVALID_LEVEL;
1192         }
1193
1194         return status;
1195 }
1196
1197
1198 /* 
1199    NTVFS write generic to any mapper
1200 */
1201 NTSTATUS ntvfs_map_write(struct ntvfs_module_context *ntvfs,
1202                                   struct ntvfs_request *req,
1203                                   union smb_write *wr)
1204 {
1205         union smb_write *wr2;
1206         NTSTATUS status;
1207
1208         wr2 = talloc(req, union smb_write);
1209         if (wr2 == NULL) {
1210                 return NT_STATUS_NO_MEMORY;
1211         }
1212
1213         status = ntvfs_map_async_setup(ntvfs, req, wr, wr2, 
1214                                        (second_stage_t)ntvfs_map_write_finish);
1215         if (!NT_STATUS_IS_OK(status)) {
1216                 return status;
1217         }
1218
1219         wr2->writex.level = RAW_WRITE_GENERIC;
1220
1221         switch (wr->generic.level) {
1222         case RAW_WRITE_WRITEX:
1223                 status = NT_STATUS_INVALID_LEVEL;
1224                 break;
1225
1226         case RAW_WRITE_WRITE:
1227                 wr2->writex.in.file.ntvfs= wr->write.in.file.ntvfs;
1228                 wr2->writex.in.offset    = wr->write.in.offset;
1229                 wr2->writex.in.wmode     = 0;
1230                 wr2->writex.in.remaining = wr->write.in.remaining;
1231                 wr2->writex.in.count     = wr->write.in.count;
1232                 wr2->writex.in.data      = wr->write.in.data;
1233                 status = ntvfs->ops->write(ntvfs, req, wr2);
1234                 break;
1235
1236         case RAW_WRITE_WRITEUNLOCK:
1237                 wr2->writex.in.file.ntvfs= wr->writeunlock.in.file.ntvfs;
1238                 wr2->writex.in.offset    = wr->writeunlock.in.offset;
1239                 wr2->writex.in.wmode     = 0;
1240                 wr2->writex.in.remaining = wr->writeunlock.in.remaining;
1241                 wr2->writex.in.count     = wr->writeunlock.in.count;
1242                 wr2->writex.in.data      = wr->writeunlock.in.data;
1243                 status = ntvfs->ops->write(ntvfs, req, wr2);
1244                 break;
1245
1246         case RAW_WRITE_WRITECLOSE:
1247                 wr2->writex.in.file.ntvfs= wr->writeclose.in.file.ntvfs;
1248                 wr2->writex.in.offset    = wr->writeclose.in.offset;
1249                 wr2->writex.in.wmode     = 0;
1250                 wr2->writex.in.remaining = 0;
1251                 wr2->writex.in.count     = wr->writeclose.in.count;
1252                 wr2->writex.in.data      = wr->writeclose.in.data;
1253                 status = ntvfs->ops->write(ntvfs, req, wr2);
1254                 break;
1255
1256         case RAW_WRITE_SPLWRITE:
1257                 wr2->writex.in.file.ntvfs= wr->splwrite.in.file.ntvfs;
1258                 wr2->writex.in.offset    = 0;
1259                 wr2->writex.in.wmode     = 0;
1260                 wr2->writex.in.remaining = 0;
1261                 wr2->writex.in.count     = wr->splwrite.in.count;
1262                 wr2->writex.in.data      = wr->splwrite.in.data;
1263                 status = ntvfs->ops->write(ntvfs, req, wr2);
1264                 break;
1265
1266         case RAW_WRITE_SMB2:
1267                 wr2->writex.in.file.ntvfs= wr->smb2.in.file.ntvfs;
1268                 wr2->writex.in.offset    = wr->smb2.in.offset;
1269                 wr2->writex.in.wmode     = 0;
1270                 wr2->writex.in.remaining = 0;
1271                 wr2->writex.in.count     = wr->smb2.in.data.length;
1272                 wr2->writex.in.data      = wr->smb2.in.data.data;
1273                 status = ntvfs->ops->write(ntvfs, req, wr2);
1274         }
1275
1276         return ntvfs_map_async_finish(req, status);
1277 }
1278
1279
1280 /* 
1281    NTVFS read generic to any mapper - finish the out mapping
1282 */
1283 static NTSTATUS ntvfs_map_read_finish(struct ntvfs_module_context *ntvfs,
1284                                       struct ntvfs_request *req, 
1285                                       union smb_read *rd, 
1286                                       union smb_read *rd2,
1287                                       NTSTATUS status)
1288 {
1289         switch (rd->generic.level) {
1290         case RAW_READ_READ:
1291                 rd->read.out.nread      = rd2->generic.out.nread;
1292                 break;
1293         case RAW_READ_READBRAW:
1294                 rd->readbraw.out.nread  = rd2->generic.out.nread;
1295                 break;
1296         case RAW_READ_LOCKREAD:
1297                 rd->lockread.out.nread  = rd2->generic.out.nread;
1298                 break;
1299         case RAW_READ_SMB2:
1300                 rd->smb2.out.data.length= rd2->generic.out.nread;
1301                 rd->smb2.out.remaining  = 0;
1302                 rd->smb2.out.reserved   = 0;
1303                 break;
1304         default:
1305                 return NT_STATUS_INVALID_LEVEL;
1306         }
1307
1308         return status;
1309 }
1310
1311 /* 
1312    NTVFS read* to readx mapper
1313 */
1314 NTSTATUS ntvfs_map_read(struct ntvfs_module_context *ntvfs,
1315                                  struct ntvfs_request *req,
1316                                  union smb_read *rd)
1317 {
1318         union smb_read *rd2;
1319         union smb_lock *lck;
1320         NTSTATUS status;
1321         uint_t state;
1322
1323         rd2 = talloc(req, union smb_read);
1324         if (rd2 == NULL) {
1325                 return NT_STATUS_NO_MEMORY;
1326         }
1327
1328         status = ntvfs_map_async_setup(ntvfs, req, rd, rd2, 
1329                                        (second_stage_t)ntvfs_map_read_finish);
1330         if (!NT_STATUS_IS_OK(status)) {
1331                 return status;
1332         }
1333
1334         rd2->readx.level = RAW_READ_READX;
1335         rd2->readx.in.read_for_execute = false;
1336
1337         switch (rd->generic.level) {
1338         case RAW_READ_READX:
1339                 status = NT_STATUS_INVALID_LEVEL;
1340                 break;
1341
1342         case RAW_READ_READ:
1343                 rd2->readx.in.file.ntvfs= rd->read.in.file.ntvfs;
1344                 rd2->readx.in.offset    = rd->read.in.offset;
1345                 rd2->readx.in.mincnt    = rd->read.in.count;
1346                 rd2->readx.in.maxcnt    = rd->read.in.count;
1347                 rd2->readx.in.remaining = rd->read.in.remaining;
1348                 rd2->readx.out.data     = rd->read.out.data;
1349                 status = ntvfs->ops->read(ntvfs, req, rd2);
1350                 break;
1351
1352         case RAW_READ_READBRAW:
1353                 rd2->readx.in.file.ntvfs= rd->readbraw.in.file.ntvfs;
1354                 rd2->readx.in.offset    = rd->readbraw.in.offset;
1355                 rd2->readx.in.mincnt    = rd->readbraw.in.mincnt;
1356                 rd2->readx.in.maxcnt    = rd->readbraw.in.maxcnt;
1357                 rd2->readx.in.remaining = 0;
1358                 rd2->readx.out.data     = rd->readbraw.out.data;
1359                 status = ntvfs->ops->read(ntvfs, req, rd2);
1360                 break;
1361
1362         case RAW_READ_LOCKREAD:
1363                 /* do the initial lock sync for now */
1364                 state = req->async_states->state;
1365                 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1366
1367                 lck = talloc(rd2, union smb_lock);
1368                 if (lck == NULL) {
1369                         status = NT_STATUS_NO_MEMORY;
1370                         goto done;
1371                 }
1372                 lck->lock.level         = RAW_LOCK_LOCK;
1373                 lck->lock.in.file.ntvfs = rd->lockread.in.file.ntvfs;
1374                 lck->lock.in.count      = rd->lockread.in.count;
1375                 lck->lock.in.offset     = rd->lockread.in.offset;
1376                 status = ntvfs->ops->lock(ntvfs, req, lck);
1377                 req->async_states->state = state;
1378
1379                 rd2->readx.in.file.ntvfs= rd->lockread.in.file.ntvfs;
1380                 rd2->readx.in.offset    = rd->lockread.in.offset;
1381                 rd2->readx.in.mincnt    = rd->lockread.in.count;
1382                 rd2->readx.in.maxcnt    = rd->lockread.in.count;
1383                 rd2->readx.in.remaining = rd->lockread.in.remaining;
1384                 rd2->readx.out.data     = rd->lockread.out.data;
1385
1386                 if (NT_STATUS_IS_OK(status)) {
1387                         status = ntvfs->ops->read(ntvfs, req, rd2);
1388                 }
1389                 break;
1390
1391         case RAW_READ_SMB2:
1392                 rd2->readx.in.file.ntvfs= rd->smb2.in.file.ntvfs;
1393                 rd2->readx.in.offset    = rd->smb2.in.offset;
1394                 rd2->readx.in.mincnt    = rd->smb2.in.min_count;
1395                 rd2->readx.in.maxcnt    = rd->smb2.in.length;
1396                 rd2->readx.in.remaining = 0;
1397                 rd2->readx.out.data     = rd->smb2.out.data.data;
1398                 status = ntvfs->ops->read(ntvfs, req, rd2);
1399                 break;
1400         }
1401
1402 done:
1403         return ntvfs_map_async_finish(req, status);
1404 }
1405
1406
1407 /* 
1408    NTVFS close generic to any mapper
1409 */
1410 static NTSTATUS ntvfs_map_close_finish(struct ntvfs_module_context *ntvfs,
1411                                         struct ntvfs_request *req,
1412                                         union smb_close *cl, 
1413                                         union smb_close *cl2, 
1414                                         NTSTATUS status)
1415 {
1416         NT_STATUS_NOT_OK_RETURN(status);
1417
1418         switch (cl->generic.level) {
1419         case RAW_CLOSE_SMB2:
1420                 cl->smb2.out.flags        = cl2->generic.out.flags;
1421                 cl->smb2.out._pad         = 0;
1422                 cl->smb2.out.create_time  = cl2->generic.out.create_time;
1423                 cl->smb2.out.access_time  = cl2->generic.out.access_time;
1424                 cl->smb2.out.write_time   = cl2->generic.out.write_time;
1425                 cl->smb2.out.change_time  = cl2->generic.out.change_time;
1426                 cl->smb2.out.alloc_size   = cl2->generic.out.alloc_size;
1427                 cl->smb2.out.size         = cl2->generic.out.size;
1428                 cl->smb2.out.file_attr    = cl2->generic.out.file_attr;
1429                 break;
1430         default:
1431                 break;
1432         }
1433
1434         return status;
1435 }
1436
1437 /* 
1438    NTVFS close generic to any mapper
1439 */
1440 NTSTATUS ntvfs_map_close(struct ntvfs_module_context *ntvfs,
1441                                   struct ntvfs_request *req,
1442                                   union smb_close *cl)
1443 {
1444         union smb_close *cl2;
1445         NTSTATUS status;
1446
1447         cl2 = talloc(req, union smb_close);
1448         if (cl2 == NULL) {
1449                 return NT_STATUS_NO_MEMORY;
1450         }
1451
1452         switch (cl->generic.level) {
1453         case RAW_CLOSE_GENERIC:
1454                 return NT_STATUS_INVALID_LEVEL;
1455
1456         case RAW_CLOSE_CLOSE:
1457                 cl2->generic.level              = RAW_CLOSE_GENERIC;
1458                 cl2->generic.in.file            = cl->close.in.file;
1459                 cl2->generic.in.write_time      = cl->close.in.write_time;
1460                 cl2->generic.in.flags           = 0;
1461                 break;
1462
1463         case RAW_CLOSE_SPLCLOSE:
1464                 cl2->generic.level              = RAW_CLOSE_GENERIC;
1465                 cl2->generic.in.file            = cl->splclose.in.file;
1466                 cl2->generic.in.write_time      = 0;
1467                 cl2->generic.in.flags           = 0;
1468                 break;
1469
1470         case RAW_CLOSE_SMB2:
1471                 cl2->generic.level              = RAW_CLOSE_GENERIC;
1472                 cl2->generic.in.file            = cl->smb2.in.file;
1473                 cl2->generic.in.write_time      = 0;
1474                 cl2->generic.in.flags           = cl->smb2.in.flags;
1475                 break;
1476         }
1477
1478         status = ntvfs_map_async_setup(ntvfs, req, cl, cl2, 
1479                                        (second_stage_t)ntvfs_map_close_finish);
1480         NT_STATUS_NOT_OK_RETURN(status);
1481
1482         status = ntvfs->ops->close(ntvfs, req, cl2);
1483
1484         return ntvfs_map_async_finish(req, status);
1485 }
1486
1487 /* 
1488    NTVFS notify generic to any mapper
1489 */
1490 static NTSTATUS ntvfs_map_notify_finish(struct ntvfs_module_context *ntvfs,
1491                                         struct ntvfs_request *req,
1492                                         union smb_notify *nt, 
1493                                         union smb_notify *nt2, 
1494                                         NTSTATUS status)
1495 {
1496         NT_STATUS_NOT_OK_RETURN(status);
1497
1498         switch (nt->nttrans.level) {
1499         case RAW_NOTIFY_SMB2:
1500                 if (nt2->nttrans.out.num_changes == 0) {
1501                         return STATUS_NOTIFY_ENUM_DIR;
1502                 }
1503                 nt->smb2.out.num_changes        = nt2->nttrans.out.num_changes;
1504                 nt->smb2.out.changes            = talloc_steal(req, nt2->nttrans.out.changes);
1505                 break;
1506
1507         default:
1508                 return NT_STATUS_INVALID_LEVEL;
1509         }
1510
1511         return status;
1512 }
1513
1514
1515 /* 
1516    NTVFS notify generic to any mapper
1517 */
1518 NTSTATUS ntvfs_map_notify(struct ntvfs_module_context *ntvfs,
1519                                    struct ntvfs_request *req,
1520                                    union smb_notify *nt)
1521 {
1522         union smb_notify *nt2;
1523         NTSTATUS status;
1524
1525         nt2 = talloc(req, union smb_notify);
1526         NT_STATUS_HAVE_NO_MEMORY(nt2);
1527
1528         status = ntvfs_map_async_setup(ntvfs, req, nt, nt2, 
1529                                        (second_stage_t)ntvfs_map_notify_finish);
1530         NT_STATUS_NOT_OK_RETURN(status);
1531
1532         nt2->nttrans.level = RAW_NOTIFY_NTTRANS;
1533
1534         switch (nt->nttrans.level) {
1535         case RAW_NOTIFY_NTTRANS:
1536                 status = NT_STATUS_INVALID_LEVEL;
1537                 break;
1538
1539         case RAW_NOTIFY_SMB2:
1540                 nt2->nttrans.in.file.ntvfs              = nt->smb2.in.file.ntvfs;
1541                 nt2->nttrans.in.buffer_size             = nt->smb2.in.buffer_size;
1542                 nt2->nttrans.in.completion_filter       = nt->smb2.in.completion_filter;
1543                 nt2->nttrans.in.recursive               = nt->smb2.in.recursive;
1544                 status = ntvfs->ops->notify(ntvfs, req, nt2);
1545                 break;
1546         }
1547
1548         return ntvfs_map_async_finish(req, status);
1549 }