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