ensure that we honor SMB2 read min_count properly
[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, j;
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                                 break;
1049                         }
1050                         j = lck2->generic.in.ulock_cnt;
1051                         if (lck->smb2.in.locks[i].flags & 
1052                             (SMB2_LOCK_FLAG_SHARED|SMB2_LOCK_FLAG_EXCLUSIVE)) {
1053                                 return NT_STATUS_INVALID_PARAMETER;
1054                         }
1055                         lck2->generic.in.ulock_cnt++;
1056                         lck2->generic.in.locks[j].pid = 0;
1057                         lck2->generic.in.locks[j].offset = lck->smb2.in.locks[i].offset;
1058                         lck2->generic.in.locks[j].count = lck->smb2.in.locks[i].length;
1059                         lck2->generic.in.locks[j].pid = 0;
1060                 }
1061                 for (;i<lck->smb2.in.lock_count;i++) {
1062                         if (lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_UNLOCK) {
1063                                 /* w2008 requires unlocks to come first */
1064                                 return NT_STATUS_INVALID_PARAMETER;
1065                         }
1066                         j = lck2->generic.in.ulock_cnt + lck2->generic.in.lock_cnt;
1067                         lck2->generic.in.lock_cnt++;
1068                         lck2->generic.in.locks[j].pid = 0;
1069                         lck2->generic.in.locks[j].offset = lck->smb2.in.locks[i].offset;
1070                         lck2->generic.in.locks[j].count = lck->smb2.in.locks[i].length;
1071                         lck2->generic.in.locks[j].pid = 0;
1072                         if (!(lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_EXCLUSIVE)) {
1073                                 lck2->generic.in.mode = LOCKING_ANDX_SHARED_LOCK;
1074                         }
1075                         if (lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_FAIL_IMMEDIATELY) {
1076                                 lck2->generic.in.timeout = 0;
1077                         }
1078                 }
1079                 /* initialize output value */
1080                 lck->smb2.out.reserved = 0;
1081                 break;
1082         }
1083
1084         case RAW_LOCK_SMB2_BREAK:
1085                 lck2->generic.level             = RAW_LOCK_GENERIC;
1086                 lck2->generic.in.file.ntvfs     = lck->smb2_break.in.file.ntvfs;
1087                 lck2->generic.in.mode           = LOCKING_ANDX_OPLOCK_RELEASE |
1088                                                   ((lck->smb2_break.in.oplock_level << 8) & 0xFF00);
1089                 lck2->generic.in.timeout        = 0;
1090                 lck2->generic.in.ulock_cnt      = 0;
1091                 lck2->generic.in.lock_cnt       = 0;
1092                 lck2->generic.in.locks          = NULL;
1093
1094                 /* initialize output value */
1095                 lck->smb2_break.out.oplock_level= lck->smb2_break.in.oplock_level;
1096                 lck->smb2_break.out.reserved    = lck->smb2_break.in.reserved;
1097                 lck->smb2_break.out.reserved2   = lck->smb2_break.in.reserved2;
1098                 lck->smb2_break.out.file        = lck->smb2_break.in.file;
1099                 break;
1100         }
1101
1102         /* 
1103          * we don't need to call ntvfs_map_async_setup() here,
1104          * as lock() doesn't have any output fields
1105          */
1106
1107         return ntvfs->ops->lock(ntvfs, req, lck2);
1108 }
1109
1110
1111 /* 
1112    NTVFS write generic to any mapper
1113 */
1114 static NTSTATUS ntvfs_map_write_finish(struct ntvfs_module_context *ntvfs,
1115                                        struct ntvfs_request *req,
1116                                        union smb_write *wr, 
1117                                        union smb_write *wr2, 
1118                                        NTSTATUS status)
1119 {
1120         union smb_lock *lck;
1121         union smb_close *cl;
1122         uint_t state;
1123
1124         if (NT_STATUS_IS_ERR(status)) {
1125                 return status;
1126         }
1127
1128         switch (wr->generic.level) {
1129         case RAW_WRITE_WRITE:
1130                 wr->write.out.nwritten    = wr2->generic.out.nwritten;
1131                 break;
1132
1133         case RAW_WRITE_WRITEUNLOCK:
1134                 wr->writeunlock.out.nwritten = wr2->generic.out.nwritten;
1135
1136                 lck = talloc(wr2, union smb_lock);
1137                 if (lck == NULL) {
1138                         return NT_STATUS_NO_MEMORY;
1139                 }
1140
1141                 lck->unlock.level               = RAW_LOCK_UNLOCK;
1142                 lck->unlock.in.file.ntvfs       = wr->writeunlock.in.file.ntvfs;
1143                 lck->unlock.in.count            = wr->writeunlock.in.count;
1144                 lck->unlock.in.offset           = wr->writeunlock.in.offset;
1145
1146                 if (lck->unlock.in.count != 0) {
1147                         /* do the lock sync for now */
1148                         state = req->async_states->state;
1149                         req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1150                         status = ntvfs->ops->lock(ntvfs, req, lck);
1151                         req->async_states->state = state;
1152                 }
1153                 break;
1154
1155         case RAW_WRITE_WRITECLOSE:
1156                 wr->writeclose.out.nwritten    = wr2->generic.out.nwritten;
1157
1158                 cl = talloc(wr2, union smb_close);
1159                 if (cl == NULL) {
1160                         return NT_STATUS_NO_MEMORY;
1161                 }
1162
1163                 cl->close.level         = RAW_CLOSE_CLOSE;
1164                 cl->close.in.file.ntvfs = wr->writeclose.in.file.ntvfs;
1165                 cl->close.in.write_time = wr->writeclose.in.mtime;
1166
1167                 if (wr2->generic.in.count != 0) {
1168                         /* do the close sync for now */
1169                         state = req->async_states->state;
1170                         req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1171                         status = ntvfs->ops->close(ntvfs, req, cl);
1172                         req->async_states->state = state;
1173                 }
1174                 break;
1175
1176         case RAW_WRITE_SPLWRITE:
1177                 break;
1178
1179         case RAW_WRITE_SMB2:
1180                 wr->smb2.out._pad       = 0;
1181                 wr->smb2.out.nwritten   = wr2->generic.out.nwritten;
1182                 wr->smb2.out.unknown1   = 0;
1183                 break;
1184
1185         default:
1186                 return NT_STATUS_INVALID_LEVEL;
1187         }
1188
1189         return status;
1190 }
1191
1192
1193 /* 
1194    NTVFS write generic to any mapper
1195 */
1196 NTSTATUS ntvfs_map_write(struct ntvfs_module_context *ntvfs,
1197                                   struct ntvfs_request *req,
1198                                   union smb_write *wr)
1199 {
1200         union smb_write *wr2;
1201         NTSTATUS status;
1202
1203         wr2 = talloc(req, union smb_write);
1204         if (wr2 == NULL) {
1205                 return NT_STATUS_NO_MEMORY;
1206         }
1207
1208         status = ntvfs_map_async_setup(ntvfs, req, wr, wr2, 
1209                                        (second_stage_t)ntvfs_map_write_finish);
1210         if (!NT_STATUS_IS_OK(status)) {
1211                 return status;
1212         }
1213
1214         wr2->writex.level = RAW_WRITE_GENERIC;
1215
1216         switch (wr->generic.level) {
1217         case RAW_WRITE_WRITEX:
1218                 status = NT_STATUS_INVALID_LEVEL;
1219                 break;
1220
1221         case RAW_WRITE_WRITE:
1222                 wr2->writex.in.file.ntvfs= wr->write.in.file.ntvfs;
1223                 wr2->writex.in.offset    = wr->write.in.offset;
1224                 wr2->writex.in.wmode     = 0;
1225                 wr2->writex.in.remaining = wr->write.in.remaining;
1226                 wr2->writex.in.count     = wr->write.in.count;
1227                 wr2->writex.in.data      = wr->write.in.data;
1228                 status = ntvfs->ops->write(ntvfs, req, wr2);
1229                 break;
1230
1231         case RAW_WRITE_WRITEUNLOCK:
1232                 wr2->writex.in.file.ntvfs= wr->writeunlock.in.file.ntvfs;
1233                 wr2->writex.in.offset    = wr->writeunlock.in.offset;
1234                 wr2->writex.in.wmode     = 0;
1235                 wr2->writex.in.remaining = wr->writeunlock.in.remaining;
1236                 wr2->writex.in.count     = wr->writeunlock.in.count;
1237                 wr2->writex.in.data      = wr->writeunlock.in.data;
1238                 status = ntvfs->ops->write(ntvfs, req, wr2);
1239                 break;
1240
1241         case RAW_WRITE_WRITECLOSE:
1242                 wr2->writex.in.file.ntvfs= wr->writeclose.in.file.ntvfs;
1243                 wr2->writex.in.offset    = wr->writeclose.in.offset;
1244                 wr2->writex.in.wmode     = 0;
1245                 wr2->writex.in.remaining = 0;
1246                 wr2->writex.in.count     = wr->writeclose.in.count;
1247                 wr2->writex.in.data      = wr->writeclose.in.data;
1248                 status = ntvfs->ops->write(ntvfs, req, wr2);
1249                 break;
1250
1251         case RAW_WRITE_SPLWRITE:
1252                 wr2->writex.in.file.ntvfs= wr->splwrite.in.file.ntvfs;
1253                 wr2->writex.in.offset    = 0;
1254                 wr2->writex.in.wmode     = 0;
1255                 wr2->writex.in.remaining = 0;
1256                 wr2->writex.in.count     = wr->splwrite.in.count;
1257                 wr2->writex.in.data      = wr->splwrite.in.data;
1258                 status = ntvfs->ops->write(ntvfs, req, wr2);
1259                 break;
1260
1261         case RAW_WRITE_SMB2:
1262                 wr2->writex.in.file.ntvfs= wr->smb2.in.file.ntvfs;
1263                 wr2->writex.in.offset    = wr->smb2.in.offset;
1264                 wr2->writex.in.wmode     = 0;
1265                 wr2->writex.in.remaining = 0;
1266                 wr2->writex.in.count     = wr->smb2.in.data.length;
1267                 wr2->writex.in.data      = wr->smb2.in.data.data;
1268                 status = ntvfs->ops->write(ntvfs, req, wr2);
1269         }
1270
1271         return ntvfs_map_async_finish(req, status);
1272 }
1273
1274
1275 /* 
1276    NTVFS read generic to any mapper - finish the out mapping
1277 */
1278 static NTSTATUS ntvfs_map_read_finish(struct ntvfs_module_context *ntvfs,
1279                                       struct ntvfs_request *req, 
1280                                       union smb_read *rd, 
1281                                       union smb_read *rd2,
1282                                       NTSTATUS status)
1283 {
1284         switch (rd->generic.level) {
1285         case RAW_READ_READ:
1286                 rd->read.out.nread      = rd2->generic.out.nread;
1287                 break;
1288         case RAW_READ_READBRAW:
1289                 rd->readbraw.out.nread  = rd2->generic.out.nread;
1290                 break;
1291         case RAW_READ_LOCKREAD:
1292                 rd->lockread.out.nread  = rd2->generic.out.nread;
1293                 break;
1294         case RAW_READ_SMB2:
1295                 rd->smb2.out.data.length= rd2->generic.out.nread;
1296                 rd->smb2.out.remaining  = 0;
1297                 rd->smb2.out.reserved   = 0;
1298                 break;
1299         default:
1300                 return NT_STATUS_INVALID_LEVEL;
1301         }
1302
1303         return status;
1304 }
1305
1306 /* 
1307    NTVFS read* to readx mapper
1308 */
1309 NTSTATUS ntvfs_map_read(struct ntvfs_module_context *ntvfs,
1310                                  struct ntvfs_request *req,
1311                                  union smb_read *rd)
1312 {
1313         union smb_read *rd2;
1314         union smb_lock *lck;
1315         NTSTATUS status;
1316         uint_t state;
1317
1318         rd2 = talloc(req, union smb_read);
1319         if (rd2 == NULL) {
1320                 return NT_STATUS_NO_MEMORY;
1321         }
1322
1323         status = ntvfs_map_async_setup(ntvfs, req, rd, rd2, 
1324                                        (second_stage_t)ntvfs_map_read_finish);
1325         if (!NT_STATUS_IS_OK(status)) {
1326                 return status;
1327         }
1328
1329         rd2->readx.level = RAW_READ_READX;
1330         rd2->readx.in.read_for_execute = false;
1331
1332         switch (rd->generic.level) {
1333         case RAW_READ_READX:
1334                 status = NT_STATUS_INVALID_LEVEL;
1335                 break;
1336
1337         case RAW_READ_READ:
1338                 rd2->readx.in.file.ntvfs= rd->read.in.file.ntvfs;
1339                 rd2->readx.in.offset    = rd->read.in.offset;
1340                 rd2->readx.in.mincnt    = rd->read.in.count;
1341                 rd2->readx.in.maxcnt    = rd->read.in.count;
1342                 rd2->readx.in.remaining = rd->read.in.remaining;
1343                 rd2->readx.out.data     = rd->read.out.data;
1344                 status = ntvfs->ops->read(ntvfs, req, rd2);
1345                 break;
1346
1347         case RAW_READ_READBRAW:
1348                 rd2->readx.in.file.ntvfs= rd->readbraw.in.file.ntvfs;
1349                 rd2->readx.in.offset    = rd->readbraw.in.offset;
1350                 rd2->readx.in.mincnt    = rd->readbraw.in.mincnt;
1351                 rd2->readx.in.maxcnt    = rd->readbraw.in.maxcnt;
1352                 rd2->readx.in.remaining = 0;
1353                 rd2->readx.out.data     = rd->readbraw.out.data;
1354                 status = ntvfs->ops->read(ntvfs, req, rd2);
1355                 break;
1356
1357         case RAW_READ_LOCKREAD:
1358                 /* do the initial lock sync for now */
1359                 state = req->async_states->state;
1360                 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1361
1362                 lck = talloc(rd2, union smb_lock);
1363                 if (lck == NULL) {
1364                         status = NT_STATUS_NO_MEMORY;
1365                         goto done;
1366                 }
1367                 lck->lock.level         = RAW_LOCK_LOCK;
1368                 lck->lock.in.file.ntvfs = rd->lockread.in.file.ntvfs;
1369                 lck->lock.in.count      = rd->lockread.in.count;
1370                 lck->lock.in.offset     = rd->lockread.in.offset;
1371                 status = ntvfs->ops->lock(ntvfs, req, lck);
1372                 req->async_states->state = state;
1373
1374                 rd2->readx.in.file.ntvfs= rd->lockread.in.file.ntvfs;
1375                 rd2->readx.in.offset    = rd->lockread.in.offset;
1376                 rd2->readx.in.mincnt    = rd->lockread.in.count;
1377                 rd2->readx.in.maxcnt    = rd->lockread.in.count;
1378                 rd2->readx.in.remaining = rd->lockread.in.remaining;
1379                 rd2->readx.out.data     = rd->lockread.out.data;
1380
1381                 if (NT_STATUS_IS_OK(status)) {
1382                         status = ntvfs->ops->read(ntvfs, req, rd2);
1383                 }
1384                 break;
1385
1386         case RAW_READ_SMB2:
1387                 rd2->readx.in.file.ntvfs= rd->smb2.in.file.ntvfs;
1388                 rd2->readx.in.offset    = rd->smb2.in.offset;
1389                 rd2->readx.in.mincnt    = rd->smb2.in.min_count;
1390                 rd2->readx.in.maxcnt    = rd->smb2.in.length;
1391                 rd2->readx.in.remaining = 0;
1392                 rd2->readx.out.data     = rd->smb2.out.data.data;
1393                 status = ntvfs->ops->read(ntvfs, req, rd2);
1394                 break;
1395         }
1396
1397 done:
1398         return ntvfs_map_async_finish(req, status);
1399 }
1400
1401
1402 /* 
1403    NTVFS close generic to any mapper
1404 */
1405 static NTSTATUS ntvfs_map_close_finish(struct ntvfs_module_context *ntvfs,
1406                                         struct ntvfs_request *req,
1407                                         union smb_close *cl, 
1408                                         union smb_close *cl2, 
1409                                         NTSTATUS status)
1410 {
1411         NT_STATUS_NOT_OK_RETURN(status);
1412
1413         switch (cl->generic.level) {
1414         case RAW_CLOSE_SMB2:
1415                 cl->smb2.out.flags        = cl2->generic.out.flags;
1416                 cl->smb2.out._pad         = 0;
1417                 cl->smb2.out.create_time  = cl2->generic.out.create_time;
1418                 cl->smb2.out.access_time  = cl2->generic.out.access_time;
1419                 cl->smb2.out.write_time   = cl2->generic.out.write_time;
1420                 cl->smb2.out.change_time  = cl2->generic.out.change_time;
1421                 cl->smb2.out.alloc_size   = cl2->generic.out.alloc_size;
1422                 cl->smb2.out.size         = cl2->generic.out.size;
1423                 cl->smb2.out.file_attr    = cl2->generic.out.file_attr;
1424                 break;
1425         default:
1426                 break;
1427         }
1428
1429         return status;
1430 }
1431
1432 /* 
1433    NTVFS close generic to any mapper
1434 */
1435 NTSTATUS ntvfs_map_close(struct ntvfs_module_context *ntvfs,
1436                                   struct ntvfs_request *req,
1437                                   union smb_close *cl)
1438 {
1439         union smb_close *cl2;
1440         NTSTATUS status;
1441
1442         cl2 = talloc(req, union smb_close);
1443         if (cl2 == NULL) {
1444                 return NT_STATUS_NO_MEMORY;
1445         }
1446
1447         switch (cl->generic.level) {
1448         case RAW_CLOSE_GENERIC:
1449                 return NT_STATUS_INVALID_LEVEL;
1450
1451         case RAW_CLOSE_CLOSE:
1452                 cl2->generic.level              = RAW_CLOSE_GENERIC;
1453                 cl2->generic.in.file            = cl->close.in.file;
1454                 cl2->generic.in.write_time      = cl->close.in.write_time;
1455                 cl2->generic.in.flags           = 0;
1456                 break;
1457
1458         case RAW_CLOSE_SPLCLOSE:
1459                 cl2->generic.level              = RAW_CLOSE_GENERIC;
1460                 cl2->generic.in.file            = cl->splclose.in.file;
1461                 cl2->generic.in.write_time      = 0;
1462                 cl2->generic.in.flags           = 0;
1463                 break;
1464
1465         case RAW_CLOSE_SMB2:
1466                 cl2->generic.level              = RAW_CLOSE_GENERIC;
1467                 cl2->generic.in.file            = cl->smb2.in.file;
1468                 cl2->generic.in.write_time      = 0;
1469                 cl2->generic.in.flags           = cl->smb2.in.flags;
1470                 break;
1471         }
1472
1473         status = ntvfs_map_async_setup(ntvfs, req, cl, cl2, 
1474                                        (second_stage_t)ntvfs_map_close_finish);
1475         NT_STATUS_NOT_OK_RETURN(status);
1476
1477         status = ntvfs->ops->close(ntvfs, req, cl2);
1478
1479         return ntvfs_map_async_finish(req, status);
1480 }
1481
1482 /* 
1483    NTVFS notify generic to any mapper
1484 */
1485 static NTSTATUS ntvfs_map_notify_finish(struct ntvfs_module_context *ntvfs,
1486                                         struct ntvfs_request *req,
1487                                         union smb_notify *nt, 
1488                                         union smb_notify *nt2, 
1489                                         NTSTATUS status)
1490 {
1491         NT_STATUS_NOT_OK_RETURN(status);
1492
1493         switch (nt->nttrans.level) {
1494         case RAW_NOTIFY_SMB2:
1495                 if (nt2->nttrans.out.num_changes == 0) {
1496                         return STATUS_NOTIFY_ENUM_DIR;
1497                 }
1498                 nt->smb2.out.num_changes        = nt2->nttrans.out.num_changes;
1499                 nt->smb2.out.changes            = talloc_steal(req, nt2->nttrans.out.changes);
1500                 break;
1501
1502         default:
1503                 return NT_STATUS_INVALID_LEVEL;
1504         }
1505
1506         return status;
1507 }
1508
1509
1510 /* 
1511    NTVFS notify generic to any mapper
1512 */
1513 NTSTATUS ntvfs_map_notify(struct ntvfs_module_context *ntvfs,
1514                                    struct ntvfs_request *req,
1515                                    union smb_notify *nt)
1516 {
1517         union smb_notify *nt2;
1518         NTSTATUS status;
1519
1520         nt2 = talloc(req, union smb_notify);
1521         NT_STATUS_HAVE_NO_MEMORY(nt2);
1522
1523         status = ntvfs_map_async_setup(ntvfs, req, nt, nt2, 
1524                                        (second_stage_t)ntvfs_map_notify_finish);
1525         NT_STATUS_NOT_OK_RETURN(status);
1526
1527         nt2->nttrans.level = RAW_NOTIFY_NTTRANS;
1528
1529         switch (nt->nttrans.level) {
1530         case RAW_NOTIFY_NTTRANS:
1531                 status = NT_STATUS_INVALID_LEVEL;
1532                 break;
1533
1534         case RAW_NOTIFY_SMB2:
1535                 nt2->nttrans.in.file.ntvfs              = nt->smb2.in.file.ntvfs;
1536                 nt2->nttrans.in.buffer_size             = nt->smb2.in.buffer_size;
1537                 nt2->nttrans.in.completion_filter       = nt->smb2.in.completion_filter;
1538                 nt2->nttrans.in.recursive               = nt->smb2.in.recursive;
1539                 status = ntvfs->ops->notify(ntvfs, req, nt2);
1540                 break;
1541         }
1542
1543         return ntvfs_map_async_finish(req, status);
1544 }