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