stricter checks for valid inputs in SMB2 open and lock
[metze/samba/wip.git] / source4 / ntvfs / ntvfs_generic.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    NTVFS generic level mapping code
5
6    Copyright (C) Andrew Tridgell 2003-2004
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21 /*
22   this implements mappings between info levels for NTVFS backend calls
23
24   the idea is that each of these functions implements one of the NTVFS
25   backend calls in terms of the 'generic' call. All backends that use
26   these functions must supply the generic call, but can if it wants to
27   also implement other levels if the need arises
28
29   this allows backend writers to only implement one variant of each
30   call unless they need fine grained control of the calls.
31 */
32
33 #include "includes.h"
34 #include "ntvfs/ntvfs.h"
35 #include "libcli/smb2/smb2.h"
36 #include "libcli/smb2/smb2_calls.h"
37
38 /* a second stage function converts from the out parameters of the generic
39    call onto the out parameters of the specific call made */
40 typedef NTSTATUS (*second_stage_t)(struct ntvfs_module_context *,
41                                    struct ntvfs_request *,
42                                    void *, void *, NTSTATUS);
43
44 /* 
45    this structure holds the async state for pending mapped async calls
46 */
47 struct ntvfs_map_async {
48         struct ntvfs_module_context *ntvfs;
49         void *io, *io2;
50         second_stage_t fn;
51 };
52
53 /*
54   this is a async wrapper, called from the backend when it has completed
55   a function that it has decided to reply to in an async fashion
56 */
57 static void ntvfs_map_async_send(struct ntvfs_request *req)
58 {
59         struct ntvfs_map_async *m = req->async_states->private_data;
60
61         ntvfs_async_state_pop(req);
62
63         /* call the _finish function setup in ntvfs_map_async_setup() */
64         req->async_states->status = m->fn(m->ntvfs, req, m->io, m->io2, req->async_states->status);
65
66         /* call the send function from the next module up */
67         req->async_states->send_fn(req);
68 }
69
70 /*
71   prepare for calling a ntvfs backend with async support
72   io is the original call structure
73   io2 is the new call structure for the mapped call
74   fn is a second stage function for processing the out arguments
75 */
76 static NTSTATUS ntvfs_map_async_setup(struct ntvfs_module_context *ntvfs,
77                                       struct ntvfs_request *req,
78                                       void *io, void *io2,
79                                       second_stage_t fn)
80 {
81         struct ntvfs_map_async *m;
82         m = talloc(req, struct ntvfs_map_async);
83         if (m == NULL) {
84                 return NT_STATUS_NO_MEMORY;
85         }
86         m->ntvfs = ntvfs;
87         m->io = io;
88         m->io2 = io2;
89         m->fn = fn;
90         return ntvfs_async_state_push(ntvfs, req, m, ntvfs_map_async_send);
91 }
92
93 /*
94   called when first stage processing is complete. 
95 */      
96 static NTSTATUS ntvfs_map_async_finish(struct ntvfs_request *req, NTSTATUS status)
97 {
98         struct ntvfs_map_async *m;
99
100         /* if the backend has decided to reply in an async fashion then
101            we don't need to do any work here */
102         if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
103                 return status;
104         }
105
106         /* the backend is replying immediately. call the 2nd stage function after popping our local
107            async state */
108         m = req->async_states->private_data;
109
110         ntvfs_async_state_pop(req);
111
112         return m->fn(m->ntvfs, req, m->io, m->io2, status);
113 }
114
115 /*
116   see if a filename ends in EXE COM DLL or SYM. This is needed for the
117   DENY_DOS mapping for OpenX
118 */
119 bool is_exe_filename(const char *fname)
120 {
121         char *p;
122         p = strrchr(fname, '.');
123         if (!p) {
124                 return false;
125         }
126         p++;
127         if (strcasecmp(p, "EXE") == 0 ||
128             strcasecmp(p, "COM") == 0 ||
129             strcasecmp(p, "DLL") == 0 ||
130             strcasecmp(p, "SYM") == 0) {
131                 return true;
132         }
133         return false;
134 }
135
136
137 /* 
138    NTVFS openx to ntcreatex mapper
139 */
140 static NTSTATUS ntvfs_map_open_finish(struct ntvfs_module_context *ntvfs,
141                                       struct ntvfs_request *req, 
142                                       union smb_open *io, 
143                                       union smb_open *io2, 
144                                       NTSTATUS status)
145 {
146         time_t write_time = 0;
147         uint32_t set_size = 0;
148         union smb_setfileinfo *sf;
149         uint_t state;
150
151         if (!NT_STATUS_IS_OK(status)) {
152                 return status;
153         }
154
155         switch (io->generic.level) {
156         case RAW_OPEN_OPEN:
157                 io->openold.out.file.ntvfs = io2->generic.out.file.ntvfs;
158                 io->openold.out.attrib     = io2->generic.out.attrib;
159                 io->openold.out.write_time = nt_time_to_unix(io2->generic.out.write_time);
160                 io->openold.out.size       = io2->generic.out.size;
161                 io->openold.out.rmode      = io->openold.in.open_mode;
162                 break;
163
164         case RAW_OPEN_OPENX:
165                 io->openx.out.file.ntvfs  = io2->generic.out.file.ntvfs;
166                 io->openx.out.attrib      = io2->generic.out.attrib;
167                 io->openx.out.write_time  = nt_time_to_unix(io2->generic.out.write_time);
168                 io->openx.out.size        = io2->generic.out.size;
169                 io->openx.out.access      = (io->openx.in.open_mode & OPENX_MODE_ACCESS_MASK);
170                 io->openx.out.ftype       = 0;
171                 io->openx.out.devstate    = 0;
172                 io->openx.out.action      = io2->generic.out.create_action;
173                 io->openx.out.unique_fid  = 0;
174                 io->openx.out.access_mask = SEC_STD_ALL;
175                 io->openx.out.unknown     = 0;
176                 
177                 /* we need to extend the file to the requested size if
178                    it was newly created */
179                 if (io2->generic.out.create_action == NTCREATEX_ACTION_CREATED) {
180                         set_size = io->openx.in.size;
181                 }
182                 break;
183
184         case RAW_OPEN_T2OPEN:
185                 io->t2open.out.file.ntvfs  = io2->generic.out.file.ntvfs;
186                 io->t2open.out.attrib      = io2->generic.out.attrib;
187                 io->t2open.out.write_time  = nt_time_to_unix(io2->generic.out.write_time);
188                 io->t2open.out.size        = io2->generic.out.size;
189                 io->t2open.out.access      = io->t2open.in.open_mode;
190                 io->t2open.out.ftype       = 0;
191                 io->t2open.out.devstate    = 0;
192                 io->t2open.out.action      = io2->generic.out.create_action;
193                 io->t2open.out.file_id      = 0;
194                 break;
195
196         case RAW_OPEN_MKNEW:
197         case RAW_OPEN_CREATE:
198                 io->mknew.out.file.ntvfs= io2->generic.out.file.ntvfs;
199                 write_time              = io->mknew.in.write_time;
200                 break;
201
202         case RAW_OPEN_CTEMP:
203                 io->ctemp.out.file.ntvfs= io2->generic.out.file.ntvfs;
204                 io->ctemp.out.name      = talloc_strdup(req, io2->generic.in.fname + 
205                                                         strlen(io->ctemp.in.directory) + 1);
206                 NT_STATUS_HAVE_NO_MEMORY(io->ctemp.out.name);
207                 break;
208
209         case RAW_OPEN_SMB2:
210                 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 use a couple of bits of the create options internally */
527                 if (io2->generic.in.create_options & NTCREATEX_OPTIONS_PRIVATE_MASK) {
528                         return NT_STATUS_INVALID_PARAMETER;
529                 }
530
531                 status = ntvfs->ops->open(ntvfs, req, io2);             
532                 break;
533
534         default:
535                 status = NT_STATUS_INVALID_LEVEL;
536                 break;
537         }
538 done:
539         return ntvfs_map_async_finish(req, status);
540 }
541
542
543 /* 
544    NTVFS fsinfo generic to any mapper
545 */
546 NTSTATUS ntvfs_map_fsinfo(struct ntvfs_module_context *ntvfs,
547                                    struct ntvfs_request *req,
548                                    union smb_fsinfo *fs)
549 {
550         NTSTATUS status;
551         union smb_fsinfo *fs2;
552
553         fs2 = talloc(req, union smb_fsinfo);
554         if (fs2 == NULL) {
555                 return NT_STATUS_NO_MEMORY;
556         }
557
558         if (fs->generic.level == RAW_QFS_GENERIC) {
559                 return NT_STATUS_INVALID_LEVEL;
560         }
561         
562         /* only used by the simple backend, which doesn't do async */
563         req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
564
565         /* ask the backend for the generic info */
566         fs2->generic.level = RAW_QFS_GENERIC;
567
568         status = ntvfs->ops->fsinfo(ntvfs, req, fs2);
569         if (!NT_STATUS_IS_OK(status)) {
570                 return status;
571         }
572
573         /* and convert it to the required level */
574         switch (fs->generic.level) {
575         case RAW_QFS_GENERIC:
576                 return NT_STATUS_INVALID_LEVEL;
577
578         case RAW_QFS_DSKATTR: {
579                 /* map from generic to DSKATTR */
580                 uint_t bpunit = 64;
581
582                 /* we need to scale the sizes to fit */
583                 for (bpunit=64; bpunit<0x10000; bpunit *= 2) {
584                         if (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size < bpunit * 512 * 65535.0) {
585                                 break;
586                         }
587                 }
588
589                 fs->dskattr.out.blocks_per_unit = bpunit;
590                 fs->dskattr.out.block_size = 512;
591                 fs->dskattr.out.units_total = 
592                         (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size) / (bpunit * 512);
593                 fs->dskattr.out.units_free  = 
594                         (fs2->generic.out.blocks_free  * (double)fs2->generic.out.block_size) / (bpunit * 512);
595
596                 /* we must return a maximum of 2G to old DOS systems, or they get very confused */
597                 if (bpunit > 64 && req->ctx->protocol <= PROTOCOL_LANMAN2) {
598                         fs->dskattr.out.blocks_per_unit = 64;
599                         fs->dskattr.out.units_total = 0xFFFF;
600                         fs->dskattr.out.units_free = 0xFFFF;
601                 }
602                 return NT_STATUS_OK;
603         }
604
605         case RAW_QFS_ALLOCATION:
606                 fs->allocation.out.fs_id = fs2->generic.out.fs_id;
607                 fs->allocation.out.total_alloc_units = fs2->generic.out.blocks_total;
608                 fs->allocation.out.avail_alloc_units = fs2->generic.out.blocks_free;
609                 fs->allocation.out.sectors_per_unit = 1;
610                 fs->allocation.out.bytes_per_sector = fs2->generic.out.block_size;
611                 return NT_STATUS_OK;
612
613         case RAW_QFS_VOLUME:
614                 fs->volume.out.serial_number = fs2->generic.out.serial_number;
615                 fs->volume.out.volume_name.s = fs2->generic.out.volume_name;
616                 return NT_STATUS_OK;
617
618         case RAW_QFS_VOLUME_INFO:
619         case RAW_QFS_VOLUME_INFORMATION:
620                 fs->volume_info.out.create_time = fs2->generic.out.create_time;
621                 fs->volume_info.out.serial_number = fs2->generic.out.serial_number;
622                 fs->volume_info.out.volume_name.s = fs2->generic.out.volume_name;
623                 return NT_STATUS_OK;
624
625         case RAW_QFS_SIZE_INFO:
626         case RAW_QFS_SIZE_INFORMATION:
627                 fs->size_info.out.total_alloc_units = fs2->generic.out.blocks_total;
628                 fs->size_info.out.avail_alloc_units = fs2->generic.out.blocks_free;
629                 fs->size_info.out.sectors_per_unit = 1;
630                 fs->size_info.out.bytes_per_sector = fs2->generic.out.block_size;
631                 return NT_STATUS_OK;
632
633         case RAW_QFS_DEVICE_INFO:
634         case RAW_QFS_DEVICE_INFORMATION:
635                 fs->device_info.out.device_type = fs2->generic.out.device_type;
636                 fs->device_info.out.characteristics = fs2->generic.out.device_characteristics;
637                 return NT_STATUS_OK;
638
639         case RAW_QFS_ATTRIBUTE_INFO:
640         case RAW_QFS_ATTRIBUTE_INFORMATION:
641                 fs->attribute_info.out.fs_attr = fs2->generic.out.fs_attr;
642                 fs->attribute_info.out.max_file_component_length = fs2->generic.out.max_file_component_length;
643                 fs->attribute_info.out.fs_type.s = fs2->generic.out.fs_type;
644                 return NT_STATUS_OK;
645
646         case RAW_QFS_QUOTA_INFORMATION:
647                 ZERO_STRUCT(fs->quota_information.out.unknown);
648                 fs->quota_information.out.quota_soft = fs2->generic.out.quota_soft;
649                 fs->quota_information.out.quota_hard = fs2->generic.out.quota_hard;
650                 fs->quota_information.out.quota_flags = fs2->generic.out.quota_flags;
651                 return NT_STATUS_OK;
652
653         case RAW_QFS_FULL_SIZE_INFORMATION:
654                 fs->full_size_information.out.total_alloc_units = fs2->generic.out.blocks_total;
655                 fs->full_size_information.out.call_avail_alloc_units = fs2->generic.out.blocks_free;
656                 fs->full_size_information.out.actual_avail_alloc_units = fs2->generic.out.blocks_free;
657                 fs->full_size_information.out.sectors_per_unit = 1;
658                 fs->full_size_information.out.bytes_per_sector = fs2->generic.out.block_size;
659                 return NT_STATUS_OK;
660
661         case RAW_QFS_OBJECTID_INFORMATION:
662                 fs->objectid_information.out.guid = fs2->generic.out.guid;
663                 ZERO_STRUCT(fs->objectid_information.out.unknown);
664                 return NT_STATUS_OK;
665         }
666
667
668         return NT_STATUS_INVALID_LEVEL;
669 }
670
671
672 /* 
673    NTVFS fileinfo generic to any mapper
674 */
675 NTSTATUS ntvfs_map_fileinfo(TALLOC_CTX *mem_ctx,
676                                      union smb_fileinfo *info, 
677                                      union smb_fileinfo *info2)
678 {
679         int i;
680         /* and convert it to the required level using results in info2 */
681         switch (info->generic.level) {
682                 case RAW_FILEINFO_GENERIC:
683                 return NT_STATUS_INVALID_LEVEL;
684         case RAW_FILEINFO_GETATTR:
685                 info->getattr.out.attrib = info2->generic.out.attrib & 0xff;
686                 info->getattr.out.size = info2->generic.out.size;
687                 info->getattr.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
688                 return NT_STATUS_OK;
689                 
690         case RAW_FILEINFO_GETATTRE:
691                 info->getattre.out.attrib = info2->generic.out.attrib;
692                 info->getattre.out.size = info2->generic.out.size;
693                 info->getattre.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
694                 info->getattre.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
695                 info->getattre.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
696                 info->getattre.out.alloc_size = info2->generic.out.alloc_size;
697                 return NT_STATUS_OK;
698                 
699         case RAW_FILEINFO_NETWORK_OPEN_INFORMATION:
700                 info->network_open_information.out.create_time = info2->generic.out.create_time;
701                 info->network_open_information.out.access_time = info2->generic.out.access_time;
702                 info->network_open_information.out.write_time =  info2->generic.out.write_time;
703                 info->network_open_information.out.change_time = info2->generic.out.change_time;
704                 info->network_open_information.out.alloc_size = info2->generic.out.alloc_size;
705                 info->network_open_information.out.size = info2->generic.out.size;
706                 info->network_open_information.out.attrib = info2->generic.out.attrib;
707                 return NT_STATUS_OK;
708
709         case RAW_FILEINFO_ALL_INFO:
710         case RAW_FILEINFO_ALL_INFORMATION:
711                 info->all_info.out.create_time = info2->generic.out.create_time;
712                 info->all_info.out.access_time = info2->generic.out.access_time;
713                 info->all_info.out.write_time =  info2->generic.out.write_time;
714                 info->all_info.out.change_time = info2->generic.out.change_time;
715                 info->all_info.out.attrib = info2->generic.out.attrib;
716                 info->all_info.out.alloc_size = info2->generic.out.alloc_size;
717                 info->all_info.out.size = info2->generic.out.size;
718                 info->all_info.out.nlink = info2->generic.out.nlink;
719                 info->all_info.out.delete_pending = info2->generic.out.delete_pending;
720                 info->all_info.out.directory = info2->generic.out.directory;
721                 info->all_info.out.ea_size = info2->generic.out.ea_size;
722                 info->all_info.out.fname.s = info2->generic.out.fname.s;
723                 info->all_info.out.fname.private_length = info2->generic.out.fname.private_length;
724                 return NT_STATUS_OK;
725
726         case RAW_FILEINFO_BASIC_INFO:
727         case RAW_FILEINFO_BASIC_INFORMATION:
728                 info->basic_info.out.create_time = info2->generic.out.create_time;
729                 info->basic_info.out.access_time = info2->generic.out.access_time;
730                 info->basic_info.out.write_time = info2->generic.out.write_time;
731                 info->basic_info.out.change_time = info2->generic.out.change_time;
732                 info->basic_info.out.attrib = info2->generic.out.attrib;
733                 return NT_STATUS_OK;
734
735         case RAW_FILEINFO_STANDARD:
736                 info->standard.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
737                 info->standard.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
738                 info->standard.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
739                 info->standard.out.size = info2->generic.out.size;
740                 info->standard.out.alloc_size = info2->generic.out.alloc_size;
741                 info->standard.out.attrib = info2->generic.out.attrib;
742                 return NT_STATUS_OK;
743
744         case RAW_FILEINFO_EA_SIZE:
745                 info->ea_size.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
746                 info->ea_size.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
747                 info->ea_size.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
748                 info->ea_size.out.size = info2->generic.out.size;
749                 info->ea_size.out.alloc_size = info2->generic.out.alloc_size;
750                 info->ea_size.out.attrib = info2->generic.out.attrib;
751                 info->ea_size.out.ea_size = info2->generic.out.ea_size;
752                 return NT_STATUS_OK;
753
754         case RAW_FILEINFO_STANDARD_INFO:
755         case RAW_FILEINFO_STANDARD_INFORMATION:
756                 info->standard_info.out.alloc_size = info2->generic.out.alloc_size;
757                 info->standard_info.out.size = info2->generic.out.size;
758                 info->standard_info.out.nlink = info2->generic.out.nlink;
759                 info->standard_info.out.delete_pending = info2->generic.out.delete_pending;
760                 info->standard_info.out.directory = info2->generic.out.directory;
761                 return NT_STATUS_OK;
762
763         case RAW_FILEINFO_INTERNAL_INFORMATION:
764                 info->internal_information.out.file_id = info2->generic.out.file_id;
765                 return NT_STATUS_OK;
766
767         case RAW_FILEINFO_EA_INFO:
768         case RAW_FILEINFO_EA_INFORMATION:
769                 info->ea_info.out.ea_size = info2->generic.out.ea_size;
770                 return NT_STATUS_OK;
771
772         case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION:
773                 info->attribute_tag_information.out.attrib = info2->generic.out.attrib;
774                 info->attribute_tag_information.out.reparse_tag = info2->generic.out.reparse_tag;
775                 return NT_STATUS_OK;
776
777         case RAW_FILEINFO_STREAM_INFO:
778         case RAW_FILEINFO_STREAM_INFORMATION:
779                 info->stream_info.out.num_streams = info2->generic.out.num_streams;
780                 if (info->stream_info.out.num_streams > 0) {
781                         info->stream_info.out.streams = 
782                                 talloc_array(mem_ctx, 
783                                                struct stream_struct,
784                                                info->stream_info.out.num_streams);
785                         if (!info->stream_info.out.streams) {
786                                 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d streams\n",
787                                         info->stream_info.out.num_streams));
788                                 return NT_STATUS_NO_MEMORY;
789                         }
790                         for (i=0; i < info->stream_info.out.num_streams; i++) {
791                                 info->stream_info.out.streams[i] = info2->generic.out.streams[i];
792                                 info->stream_info.out.streams[i].stream_name.s = 
793                                         talloc_strdup(info->stream_info.out.streams,
794                                                       info2->generic.out.streams[i].stream_name.s);
795                                 if (!info->stream_info.out.streams[i].stream_name.s) {
796                                         DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
797                                         return NT_STATUS_NO_MEMORY;
798                                 }
799                         }
800                 }
801                 return NT_STATUS_OK;
802
803         case RAW_FILEINFO_NAME_INFO:
804         case RAW_FILEINFO_NAME_INFORMATION:
805                 info->name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.fname.s);
806                 NT_STATUS_HAVE_NO_MEMORY(info->name_info.out.fname.s);
807                 info->name_info.out.fname.private_length = info2->generic.out.fname.private_length;
808                 return NT_STATUS_OK;
809                 
810         case RAW_FILEINFO_ALT_NAME_INFO:
811         case RAW_FILEINFO_ALT_NAME_INFORMATION:
812                 info->alt_name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.alt_fname.s);
813                 NT_STATUS_HAVE_NO_MEMORY(info->alt_name_info.out.fname.s);
814                 info->alt_name_info.out.fname.private_length = info2->generic.out.alt_fname.private_length;
815                 return NT_STATUS_OK;
816         
817         case RAW_FILEINFO_POSITION_INFORMATION:
818                 info->position_information.out.position = info2->generic.out.position;
819                 return NT_STATUS_OK;
820         
821         case RAW_FILEINFO_ALL_EAS:
822                 info->all_eas.out.num_eas = info2->generic.out.num_eas;
823                 if (info->all_eas.out.num_eas > 0) {
824                         info->all_eas.out.eas = talloc_array(mem_ctx, 
825                                                                struct ea_struct,
826                                                                info->all_eas.out.num_eas);
827                         if (!info->all_eas.out.eas) {
828                                 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d eas\n",
829                                         info->all_eas.out.num_eas));
830                                 return NT_STATUS_NO_MEMORY;
831                         }
832                         for (i = 0; i < info->all_eas.out.num_eas; i++) {
833                                 info->all_eas.out.eas[i] = info2->generic.out.eas[i];
834                                 info->all_eas.out.eas[i].name.s = 
835                                         talloc_strdup(info->all_eas.out.eas,
836                                                       info2->generic.out.eas[i].name.s);
837                                 if (!info->all_eas.out.eas[i].name.s) {
838                                         DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
839                                         return NT_STATUS_NO_MEMORY;
840                                 }
841                                 info->all_eas.out.eas[i].value.data = 
842                                         talloc_memdup(info->all_eas.out.eas,
843                                                 info2->generic.out.eas[i].value.data,
844                                                 info2->generic.out.eas[i].value.length);
845                                 if (!info->all_eas.out.eas[i].value.data) {
846                                         DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
847                                         return NT_STATUS_NO_MEMORY;
848                                 }
849                         }
850                 }
851                 return NT_STATUS_OK;
852                 
853         case RAW_FILEINFO_IS_NAME_VALID:
854                 return NT_STATUS_OK;
855                 
856         case RAW_FILEINFO_COMPRESSION_INFO:
857         case RAW_FILEINFO_COMPRESSION_INFORMATION:
858                 info->compression_info.out.compressed_size = info2->generic.out.compressed_size;
859                 info->compression_info.out.format = info2->generic.out.format;
860                 info->compression_info.out.unit_shift = info2->generic.out.unit_shift;
861                 info->compression_info.out.chunk_shift = info2->generic.out.chunk_shift;
862                 info->compression_info.out.cluster_shift = info2->generic.out.cluster_shift;
863                 return NT_STATUS_OK;
864                 
865         case RAW_FILEINFO_ACCESS_INFORMATION:
866                 info->access_information.out.access_flags = info2->generic.out.access_flags;
867                 return NT_STATUS_OK;
868                 
869         case RAW_FILEINFO_MODE_INFORMATION:
870                 info->mode_information.out.mode = info2->generic.out.mode;
871                 return NT_STATUS_OK;
872                 
873         case RAW_FILEINFO_ALIGNMENT_INFORMATION:
874                 info->alignment_information.out.alignment_requirement =
875                         info2->generic.out.alignment_requirement;
876                 return NT_STATUS_OK;
877 #if 0   
878         case RAW_FILEINFO_UNIX_BASIC:
879                 info->unix_basic_info.out.end_of_file = info2->generic.out.end_of_file;
880                 info->unix_basic_info.out.num_bytes = info2->generic.out.size;
881                 info->unix_basic_info.out.status_change_time = info2->generic.out.change_time;
882                 info->unix_basic_info.out.access_time = info2->generic.out.access_time;
883                 info->unix_basic_info.out.change_time = info2->generic.out.change_time;
884                 info->unix_basic_info.out.uid = info2->generic.out.uid;
885                 info->unix_basic_info.out.gid = info2->generic.out.gid;
886                 info->unix_basic_info.out.file_type = info2->generic.out.file_type;
887                 info->unix_basic_info.out.dev_major = info2->generic.out.device;
888                 info->unix_basic_info.out.dev_minor = info2->generic.out.device;
889                 info->unix_basic_info.out.unique_id = info2->generic.out.inode;
890                 info->unix_basic_info.out.permissions = info2->generic.out.permissions;
891                 info->unix_basic_info.out.nlink = info2->generic.out.nlink;
892                 return NT_STATUS_OK;
893                 
894         case RAW_FILEINFO_UNIX_LINK:
895                 info->unix_link_info.out.link_dest = info2->generic.out.link_dest;
896                 return NT_STATUS_OK;
897 #endif
898         }
899
900         return NT_STATUS_INVALID_LEVEL;
901 }
902
903 /* 
904    NTVFS fileinfo generic to any mapper
905 */
906 NTSTATUS ntvfs_map_qfileinfo(struct ntvfs_module_context *ntvfs,
907                                       struct ntvfs_request *req,
908                                       union smb_fileinfo *info)
909 {
910         NTSTATUS status;
911         union smb_fileinfo *info2;
912
913         info2 = talloc(req, union smb_fileinfo);
914         if (info2 == NULL) {
915                 return NT_STATUS_NO_MEMORY;
916         }
917
918         if (info->generic.level == RAW_FILEINFO_GENERIC) {
919                 return NT_STATUS_INVALID_LEVEL;
920         }
921
922         /* ask the backend for the generic info */
923         info2->generic.level = RAW_FILEINFO_GENERIC;
924         info2->generic.in.file.ntvfs= info->generic.in.file.ntvfs;
925
926         /* only used by the simple backend, which doesn't do async */
927         req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
928
929         status = ntvfs->ops->qfileinfo(ntvfs, req, info2);
930         if (!NT_STATUS_IS_OK(status)) {
931                 return status;
932         }
933         return ntvfs_map_fileinfo(req, info, info2);
934 }
935
936 /* 
937    NTVFS pathinfo generic to any mapper
938 */
939 NTSTATUS ntvfs_map_qpathinfo(struct ntvfs_module_context *ntvfs,
940                                       struct ntvfs_request *req,
941                                       union smb_fileinfo *info)
942 {
943         NTSTATUS status;
944         union smb_fileinfo *info2;
945
946         info2 = talloc(req, union smb_fileinfo);
947         if (info2 == NULL) {
948                 return NT_STATUS_NO_MEMORY;
949         }
950
951         if (info->generic.level == RAW_FILEINFO_GENERIC) {
952                 return NT_STATUS_INVALID_LEVEL;
953         }
954
955         /* ask the backend for the generic info */
956         info2->generic.level            = RAW_FILEINFO_GENERIC;
957         info2->generic.in.file.path     = info->generic.in.file.path;
958
959         /* only used by the simple backend, which doesn't do async */
960         req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
961
962         status = ntvfs->ops->qpathinfo(ntvfs, req, info2);
963         if (!NT_STATUS_IS_OK(status)) {
964                 return status;
965         }
966         return ntvfs_map_fileinfo(req, info, info2);
967 }
968
969
970 /* 
971    NTVFS lock generic to any mapper
972 */
973 NTSTATUS ntvfs_map_lock(struct ntvfs_module_context *ntvfs,
974                                  struct ntvfs_request *req,
975                                  union smb_lock *lck)
976 {
977         union smb_lock *lck2;
978         struct smb_lock_entry *locks;
979
980         lck2 = talloc(req, union smb_lock);
981         if (lck2 == NULL) {
982                 return NT_STATUS_NO_MEMORY;
983         }
984
985         locks = talloc_array(lck2, struct smb_lock_entry, 1);
986         if (locks == NULL) {
987                 return NT_STATUS_NO_MEMORY;
988         }
989
990         switch (lck->generic.level) {
991         case RAW_LOCK_LOCKX:
992                 return NT_STATUS_INVALID_LEVEL;
993
994         case RAW_LOCK_LOCK:
995                 lck2->generic.level = RAW_LOCK_GENERIC;
996                 lck2->generic.in.file.ntvfs= lck->lock.in.file.ntvfs;
997                 lck2->generic.in.mode = 0;
998                 lck2->generic.in.timeout = 0;
999                 lck2->generic.in.ulock_cnt = 0;
1000                 lck2->generic.in.lock_cnt = 1;
1001                 lck2->generic.in.locks = locks;
1002                 locks->pid = req->smbpid;
1003                 locks->offset = lck->lock.in.offset;
1004                 locks->count = lck->lock.in.count;
1005                 break;
1006
1007         case RAW_LOCK_UNLOCK:
1008                 lck2->generic.level = RAW_LOCK_GENERIC;
1009                 lck2->generic.in.file.ntvfs= lck->unlock.in.file.ntvfs;
1010                 lck2->generic.in.mode = 0;
1011                 lck2->generic.in.timeout = 0;
1012                 lck2->generic.in.ulock_cnt = 1;
1013                 lck2->generic.in.lock_cnt = 0;
1014                 lck2->generic.in.locks = locks;
1015                 locks->pid = req->smbpid;
1016                 locks->offset = lck->unlock.in.offset;
1017                 locks->count = lck->unlock.in.count;
1018                 break;
1019
1020         case RAW_LOCK_SMB2: {
1021                 /* this is only approximate! We need to change the
1022                    generic structure to fix this properly */
1023                 int i;
1024                 if (lck->smb2.in.lock_count < 1) {
1025                         return NT_STATUS_INVALID_PARAMETER;
1026                 }
1027
1028                 lck2->generic.level = RAW_LOCK_GENERIC;
1029                 lck2->generic.in.file.ntvfs= lck->smb2.in.file.ntvfs;
1030                 lck2->generic.in.timeout = UINT32_MAX;
1031                 lck2->generic.in.mode = 0;
1032                 lck2->generic.in.lock_cnt = 0;
1033                 lck2->generic.in.ulock_cnt = 0;
1034                 lck2->generic.in.locks = talloc_zero_array(lck2, struct smb_lock_entry, 
1035                                                            lck->smb2.in.lock_count);
1036                 if (lck2->generic.in.locks == NULL) {
1037                         return NT_STATUS_NO_MEMORY;
1038                 }
1039                 for (i=0;i<lck->smb2.in.lock_count;i++) {
1040                         if (lck->smb2.in.locks[i].flags & ~SMB2_LOCK_FLAG_ALL_MASK) {
1041                                 return NT_STATUS_INVALID_PARAMETER;
1042                         }
1043                         if (lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_UNLOCK) {
1044                                 int j = lck2->generic.in.ulock_cnt;
1045                                 lck2->generic.in.ulock_cnt++;
1046                                 lck2->generic.in.locks[j].pid = 0;
1047                                 lck2->generic.in.locks[j].offset = lck->smb2.in.locks[i].offset;
1048                                 lck2->generic.in.locks[j].count = lck->smb2.in.locks[i].length;
1049                                 lck2->generic.in.locks[j].pid = 0;
1050                         }
1051                 }
1052                 for (i=0;i<lck->smb2.in.lock_count;i++) {
1053                         if (!(lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_UNLOCK)) {
1054                                 int j = lck2->generic.in.ulock_cnt + 
1055                                         lck2->generic.in.lock_cnt;
1056                                 lck2->generic.in.lock_cnt++;
1057                                 lck2->generic.in.locks[j].pid = 0;
1058                                 lck2->generic.in.locks[j].offset = lck->smb2.in.locks[i].offset;
1059                                 lck2->generic.in.locks[j].count = lck->smb2.in.locks[i].length;
1060                                 lck2->generic.in.locks[j].pid = 0;
1061                                 if (!(lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_EXCLUSIVE)) {
1062                                         lck2->generic.in.mode = LOCKING_ANDX_SHARED_LOCK;
1063                                 }
1064                                 if (lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_FAIL_IMMEDIATELY) {
1065                                         lck2->generic.in.timeout = 0;
1066                                 }
1067                         }
1068                 }
1069                 /* initialize output value */
1070                 lck->smb2.out.reserved = 0;
1071                 break;
1072         }
1073
1074         case RAW_LOCK_SMB2_BREAK:
1075                 lck2->generic.level             = RAW_LOCK_GENERIC;
1076                 lck2->generic.in.file.ntvfs     = lck->smb2_break.in.file.ntvfs;
1077                 lck2->generic.in.mode           = LOCKING_ANDX_OPLOCK_RELEASE |
1078                                                   ((lck->smb2_break.in.oplock_level << 8) & 0xFF00);
1079                 lck2->generic.in.timeout        = 0;
1080                 lck2->generic.in.ulock_cnt      = 0;
1081                 lck2->generic.in.lock_cnt       = 0;
1082                 lck2->generic.in.locks          = NULL;
1083
1084                 /* initialize output value */
1085                 lck->smb2_break.out.oplock_level= lck->smb2_break.in.oplock_level;
1086                 lck->smb2_break.out.reserved    = lck->smb2_break.in.reserved;
1087                 lck->smb2_break.out.reserved2   = lck->smb2_break.in.reserved2;
1088                 lck->smb2_break.out.file        = lck->smb2_break.in.file;
1089                 break;
1090         }
1091
1092         /* 
1093          * we don't need to call ntvfs_map_async_setup() here,
1094          * as lock() doesn't have any output fields
1095          */
1096
1097         return ntvfs->ops->lock(ntvfs, req, lck2);
1098 }
1099
1100
1101 /* 
1102    NTVFS write generic to any mapper
1103 */
1104 static NTSTATUS ntvfs_map_write_finish(struct ntvfs_module_context *ntvfs,
1105                                        struct ntvfs_request *req,
1106                                        union smb_write *wr, 
1107                                        union smb_write *wr2, 
1108                                        NTSTATUS status)
1109 {
1110         union smb_lock *lck;
1111         union smb_close *cl;
1112         uint_t state;
1113
1114         if (NT_STATUS_IS_ERR(status)) {
1115                 return status;
1116         }
1117
1118         switch (wr->generic.level) {
1119         case RAW_WRITE_WRITE:
1120                 wr->write.out.nwritten    = wr2->generic.out.nwritten;
1121                 break;
1122
1123         case RAW_WRITE_WRITEUNLOCK:
1124                 wr->writeunlock.out.nwritten = wr2->generic.out.nwritten;
1125
1126                 lck = talloc(wr2, union smb_lock);
1127                 if (lck == NULL) {
1128                         return NT_STATUS_NO_MEMORY;
1129                 }
1130
1131                 lck->unlock.level               = RAW_LOCK_UNLOCK;
1132                 lck->unlock.in.file.ntvfs       = wr->writeunlock.in.file.ntvfs;
1133                 lck->unlock.in.count            = wr->writeunlock.in.count;
1134                 lck->unlock.in.offset           = wr->writeunlock.in.offset;
1135
1136                 if (lck->unlock.in.count != 0) {
1137                         /* do the lock sync for now */
1138                         state = req->async_states->state;
1139                         req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1140                         status = ntvfs->ops->lock(ntvfs, req, lck);
1141                         req->async_states->state = state;
1142                 }
1143                 break;
1144
1145         case RAW_WRITE_WRITECLOSE:
1146                 wr->writeclose.out.nwritten    = wr2->generic.out.nwritten;
1147
1148                 cl = talloc(wr2, union smb_close);
1149                 if (cl == NULL) {
1150                         return NT_STATUS_NO_MEMORY;
1151                 }
1152
1153                 cl->close.level         = RAW_CLOSE_CLOSE;
1154                 cl->close.in.file.ntvfs = wr->writeclose.in.file.ntvfs;
1155                 cl->close.in.write_time = wr->writeclose.in.mtime;
1156
1157                 if (wr2->generic.in.count != 0) {
1158                         /* do the close sync for now */
1159                         state = req->async_states->state;
1160                         req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1161                         status = ntvfs->ops->close(ntvfs, req, cl);
1162                         req->async_states->state = state;
1163                 }
1164                 break;
1165
1166         case RAW_WRITE_SPLWRITE:
1167                 break;
1168
1169         case RAW_WRITE_SMB2:
1170                 wr->smb2.out._pad       = 0;
1171                 wr->smb2.out.nwritten   = wr2->generic.out.nwritten;
1172                 wr->smb2.out.unknown1   = 0;
1173                 break;
1174
1175         default:
1176                 return NT_STATUS_INVALID_LEVEL;
1177         }
1178
1179         return status;
1180 }
1181
1182
1183 /* 
1184    NTVFS write generic to any mapper
1185 */
1186 NTSTATUS ntvfs_map_write(struct ntvfs_module_context *ntvfs,
1187                                   struct ntvfs_request *req,
1188                                   union smb_write *wr)
1189 {
1190         union smb_write *wr2;
1191         NTSTATUS status;
1192
1193         wr2 = talloc(req, union smb_write);
1194         if (wr2 == NULL) {
1195                 return NT_STATUS_NO_MEMORY;
1196         }
1197
1198         status = ntvfs_map_async_setup(ntvfs, req, wr, wr2, 
1199                                        (second_stage_t)ntvfs_map_write_finish);
1200         if (!NT_STATUS_IS_OK(status)) {
1201                 return status;
1202         }
1203
1204         wr2->writex.level = RAW_WRITE_GENERIC;
1205
1206         switch (wr->generic.level) {
1207         case RAW_WRITE_WRITEX:
1208                 status = NT_STATUS_INVALID_LEVEL;
1209                 break;
1210
1211         case RAW_WRITE_WRITE:
1212                 wr2->writex.in.file.ntvfs= wr->write.in.file.ntvfs;
1213                 wr2->writex.in.offset    = wr->write.in.offset;
1214                 wr2->writex.in.wmode     = 0;
1215                 wr2->writex.in.remaining = wr->write.in.remaining;
1216                 wr2->writex.in.count     = wr->write.in.count;
1217                 wr2->writex.in.data      = wr->write.in.data;
1218                 status = ntvfs->ops->write(ntvfs, req, wr2);
1219                 break;
1220
1221         case RAW_WRITE_WRITEUNLOCK:
1222                 wr2->writex.in.file.ntvfs= wr->writeunlock.in.file.ntvfs;
1223                 wr2->writex.in.offset    = wr->writeunlock.in.offset;
1224                 wr2->writex.in.wmode     = 0;
1225                 wr2->writex.in.remaining = wr->writeunlock.in.remaining;
1226                 wr2->writex.in.count     = wr->writeunlock.in.count;
1227                 wr2->writex.in.data      = wr->writeunlock.in.data;
1228                 status = ntvfs->ops->write(ntvfs, req, wr2);
1229                 break;
1230
1231         case RAW_WRITE_WRITECLOSE:
1232                 wr2->writex.in.file.ntvfs= wr->writeclose.in.file.ntvfs;
1233                 wr2->writex.in.offset    = wr->writeclose.in.offset;
1234                 wr2->writex.in.wmode     = 0;
1235                 wr2->writex.in.remaining = 0;
1236                 wr2->writex.in.count     = wr->writeclose.in.count;
1237                 wr2->writex.in.data      = wr->writeclose.in.data;
1238                 status = ntvfs->ops->write(ntvfs, req, wr2);
1239                 break;
1240
1241         case RAW_WRITE_SPLWRITE:
1242                 wr2->writex.in.file.ntvfs= wr->splwrite.in.file.ntvfs;
1243                 wr2->writex.in.offset    = 0;
1244                 wr2->writex.in.wmode     = 0;
1245                 wr2->writex.in.remaining = 0;
1246                 wr2->writex.in.count     = wr->splwrite.in.count;
1247                 wr2->writex.in.data      = wr->splwrite.in.data;
1248                 status = ntvfs->ops->write(ntvfs, req, wr2);
1249                 break;
1250
1251         case RAW_WRITE_SMB2:
1252                 wr2->writex.in.file.ntvfs= wr->smb2.in.file.ntvfs;
1253                 wr2->writex.in.offset    = wr->smb2.in.offset;
1254                 wr2->writex.in.wmode     = 0;
1255                 wr2->writex.in.remaining = 0;
1256                 wr2->writex.in.count     = wr->smb2.in.data.length;
1257                 wr2->writex.in.data      = wr->smb2.in.data.data;
1258                 status = ntvfs->ops->write(ntvfs, req, wr2);
1259         }
1260
1261         return ntvfs_map_async_finish(req, status);
1262 }
1263
1264
1265 /* 
1266    NTVFS read generic to any mapper - finish the out mapping
1267 */
1268 static NTSTATUS ntvfs_map_read_finish(struct ntvfs_module_context *ntvfs,
1269                                       struct ntvfs_request *req, 
1270                                       union smb_read *rd, 
1271                                       union smb_read *rd2,
1272                                       NTSTATUS status)
1273 {
1274         switch (rd->generic.level) {
1275         case RAW_READ_READ:
1276                 rd->read.out.nread      = rd2->generic.out.nread;
1277                 break;
1278         case RAW_READ_READBRAW:
1279                 rd->readbraw.out.nread  = rd2->generic.out.nread;
1280                 break;
1281         case RAW_READ_LOCKREAD:
1282                 rd->lockread.out.nread  = rd2->generic.out.nread;
1283                 break;
1284         case RAW_READ_SMB2:
1285                 rd->smb2.out.data.length= rd2->generic.out.nread;
1286                 rd->smb2.out.remaining  = 0;
1287                 rd->smb2.out.reserved   = 0;
1288                 if (NT_STATUS_IS_OK(status) &&
1289                     rd->smb2.out.data.length == 0) {
1290                         status = NT_STATUS_END_OF_FILE;
1291                 }
1292                 /* SMB2 does honor the min_count field, SMB does not */
1293                 if (NT_STATUS_IS_OK(status) && 
1294                     rd->smb2.in.min_count > rd->smb2.out.data.length) {
1295                         rd->smb2.out.data.length = 0;
1296                         status = NT_STATUS_END_OF_FILE;                 
1297                 }
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.length;
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 NTSTATUS ntvfs_map_close(struct ntvfs_module_context *ntvfs,
1406                                   struct ntvfs_request *req,
1407                                   union smb_close *cl)
1408 {
1409         union smb_close *cl2;
1410
1411         cl2 = talloc(req, union smb_close);
1412         if (cl2 == NULL) {
1413                 return NT_STATUS_NO_MEMORY;
1414         }
1415
1416         switch (cl->generic.level) {
1417         case RAW_CLOSE_CLOSE:
1418                 return NT_STATUS_INVALID_LEVEL;
1419
1420         case RAW_CLOSE_SPLCLOSE:
1421                 cl2->generic.level              = RAW_CLOSE_CLOSE;
1422                 cl2->generic.in.file.ntvfs      = cl->splclose.in.file.ntvfs;
1423                 cl2->generic.in.write_time      = 0;
1424                 break;
1425
1426         case RAW_CLOSE_SMB2:
1427                 cl2->generic.level              = RAW_CLOSE_CLOSE;
1428                 cl2->generic.in.file.ntvfs      = cl->smb2.in.file.ntvfs;
1429                 cl2->generic.in.write_time      = 0;
1430                 /* SMB2 Close has output parameter, but we just zero them */
1431                 ZERO_STRUCT(cl->smb2.out);
1432                 break;
1433         }
1434
1435         /* 
1436          * we don't need to call ntvfs_map_async_setup() here,
1437          * as close() doesn't have any output fields
1438          */
1439
1440         return ntvfs->ops->close(ntvfs, req, cl2);
1441 }
1442
1443 /* 
1444    NTVFS notify generic to any mapper
1445 */
1446 static NTSTATUS ntvfs_map_notify_finish(struct ntvfs_module_context *ntvfs,
1447                                         struct ntvfs_request *req,
1448                                         union smb_notify *nt, 
1449                                         union smb_notify *nt2, 
1450                                         NTSTATUS status)
1451 {
1452         NT_STATUS_NOT_OK_RETURN(status);
1453
1454         switch (nt->nttrans.level) {
1455         case RAW_NOTIFY_SMB2:
1456                 if (nt2->nttrans.out.num_changes == 0) {
1457                         return STATUS_NOTIFY_ENUM_DIR;
1458                 }
1459                 nt->smb2.out.num_changes        = nt2->nttrans.out.num_changes;
1460                 nt->smb2.out.changes            = talloc_steal(req, nt2->nttrans.out.changes);
1461                 break;
1462
1463         default:
1464                 return NT_STATUS_INVALID_LEVEL;
1465         }
1466
1467         return status;
1468 }
1469
1470
1471 /* 
1472    NTVFS notify generic to any mapper
1473 */
1474 NTSTATUS ntvfs_map_notify(struct ntvfs_module_context *ntvfs,
1475                                    struct ntvfs_request *req,
1476                                    union smb_notify *nt)
1477 {
1478         union smb_notify *nt2;
1479         NTSTATUS status;
1480
1481         nt2 = talloc(req, union smb_notify);
1482         NT_STATUS_HAVE_NO_MEMORY(nt2);
1483
1484         status = ntvfs_map_async_setup(ntvfs, req, nt, nt2, 
1485                                        (second_stage_t)ntvfs_map_notify_finish);
1486         NT_STATUS_NOT_OK_RETURN(status);
1487
1488         nt2->nttrans.level = RAW_NOTIFY_NTTRANS;
1489
1490         switch (nt->nttrans.level) {
1491         case RAW_NOTIFY_NTTRANS:
1492                 status = NT_STATUS_INVALID_LEVEL;
1493                 break;
1494
1495         case RAW_NOTIFY_SMB2:
1496                 nt2->nttrans.in.file.ntvfs              = nt->smb2.in.file.ntvfs;
1497                 nt2->nttrans.in.buffer_size             = nt->smb2.in.buffer_size;
1498                 nt2->nttrans.in.completion_filter       = nt->smb2.in.completion_filter;
1499                 nt2->nttrans.in.recursive               = nt->smb2.in.recursive;
1500                 status = ntvfs->ops->notify(ntvfs, req, nt2);
1501                 break;
1502         }
1503
1504         return ntvfs_map_async_finish(req, status);
1505 }