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