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