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