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