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