051e92b19cea33790878f458f6a1009e1861ce01
[jelmer/samba4-debian.git] / source / 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 2 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, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22 /*
23   this implements mappings between info levels for NTVFS backend calls
24
25   the idea is that each of these functions implements one of the NTVFS
26   backend calls in terms of the 'generic' call. All backends that use
27   these functions must supply the generic call, but can if it wants to
28   also implement other levels if the need arises
29
30   this allows backend writers to only implement one variant of each
31   call unless they need fine grained control of the calls.
32 */
33
34 #include "includes.h"
35 #include "smb_server/smb_server.h"
36 #include "librpc/gen_ndr/ndr_security.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 smbsrv_request *, 
41                                    struct ntvfs_module_context *,
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 smbsrv_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(req, m->ntvfs, 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 smbsrv_request *req,
77                                       struct ntvfs_module_context *ntvfs,
78                                       void *io, void *io2,
79                                       second_stage_t fn)
80 {
81         struct ntvfs_map_async *m;
82         m = talloc_p(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(req, m, ntvfs_map_async_send, ntvfs);
91 }
92
93
94 /*
95   called when first stage processing is complete. 
96 */      
97 static NTSTATUS ntvfs_map_async_finish(struct smbsrv_request *req, NTSTATUS status)
98 {
99         struct ntvfs_map_async *m;
100
101         /* if the backend has decided to reply in an async fashion then
102            we don't need to do any work here */
103         if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
104                 return status;
105         }
106
107         /* the backend is replying immediately. call the 2nd stage function after popping our local
108            async state */
109         m = req->async_states->private_data;
110
111         ntvfs_async_state_pop(req);
112
113         return m->fn(req, m->ntvfs, m->io, m->io2, status);
114 }
115
116
117 /*
118   see if a filename ends in EXE COM DLL or SYM. This is needed for the
119   DENY_DOS mapping for OpenX
120 */
121 BOOL is_exe_filename(const char *fname)
122 {
123         char *p;
124         p = strrchr(fname, '.');
125         if (!p) {
126                 return False;
127         }
128         p++;
129         if (strcasecmp(p, "EXE") == 0 ||
130             strcasecmp(p, "COM") == 0 ||
131             strcasecmp(p, "DLL") == 0 ||
132             strcasecmp(p, "SYM") == 0) {
133                 return True;
134         }
135         return False;
136 }
137
138
139 /* 
140    NTVFS openx to ntcreatex mapper
141 */
142 static NTSTATUS ntvfs_map_open_finish(struct smbsrv_request *req, 
143                                       struct ntvfs_module_context *ntvfs,
144                                       union smb_open *io, 
145                                       union smb_open *io2, 
146                                       NTSTATUS status)
147 {
148         time_t write_time = 0;
149         uint32_t set_size = 0;
150         union smb_setfileinfo *sf;
151         uint_t state;
152
153         if (!NT_STATUS_IS_OK(status)) {
154                 return status;
155         }
156
157         switch (io->generic.level) {
158         case RAW_OPEN_OPEN:
159                 io->openold.out.fnum       = io2->generic.out.fnum;
160                 io->openold.out.attrib     = io2->generic.out.attrib;
161                 io->openold.out.write_time = nt_time_to_unix(io2->generic.out.write_time);
162                 io->openold.out.size       = io2->generic.out.size;
163                 io->openold.out.rmode      = io->openold.in.open_mode;
164                 break;
165
166         case RAW_OPEN_OPENX:
167                 io->openx.out.fnum        = io2->generic.out.fnum;
168                 io->openx.out.attrib      = io2->generic.out.attrib;
169                 io->openx.out.write_time  = nt_time_to_unix(io2->generic.out.write_time);
170                 io->openx.out.size        = io2->generic.out.size;
171                 io->openx.out.access      = (io->openx.in.open_mode & OPENX_MODE_ACCESS_MASK);
172                 io->openx.out.ftype       = 0;
173                 io->openx.out.devstate    = 0;
174                 io->openx.out.action      = io2->generic.out.create_action;
175                 io->openx.out.unique_fid  = 0;
176                 io->openx.out.access_mask = SEC_STD_ALL;
177                 io->openx.out.unknown     = 0;
178                 
179                 /* we need to extend the file to the requested size if
180                    it was newly created */
181                 if (io2->generic.out.create_action == NTCREATEX_ACTION_CREATED) {
182                         set_size = io->openx.in.size;
183                 }
184                 break;
185
186         case RAW_OPEN_T2OPEN:
187                 io->t2open.out.fnum        = io2->generic.out.fnum;
188                 io->t2open.out.attrib      = io2->generic.out.attrib;
189                 io->t2open.out.write_time  = nt_time_to_unix(io2->generic.out.write_time);
190                 io->t2open.out.size        = io2->generic.out.size;
191                 io->t2open.out.access      = io->t2open.in.open_mode;
192                 io->t2open.out.ftype       = 0;
193                 io->t2open.out.devstate    = 0;
194                 io->t2open.out.action      = io2->generic.out.create_action;
195                 io->t2open.out.file_id      = 0;
196                 break;
197
198         case RAW_OPEN_MKNEW:
199         case RAW_OPEN_CREATE:
200                 io->mknew.out.fnum = io2->generic.out.fnum;
201                 write_time = io->mknew.in.write_time;
202                 break;
203
204         case RAW_OPEN_CTEMP:
205                 io->ctemp.out.fnum  = io2->generic.out.fnum;
206                 io->ctemp.out.name = talloc_strdup(req, io2->generic.in.fname + 
207                                                    strlen(io->ctemp.in.directory) + 1);
208                 break;
209
210         default:
211                 return NT_STATUS_INVALID_LEVEL;
212         }
213
214         /* doing a secondary request async is more trouble than its
215            worth */
216         state = req->async_states->state;
217         req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
218
219         if (write_time != 0) {
220                 sf = talloc_p(req, union smb_setfileinfo);                      
221                 sf->generic.level            = RAW_SFILEINFO_STANDARD;
222                 sf->generic.file.fnum        = io2->generic.out.fnum;
223                 sf->standard.in.create_time = 0;
224                 sf->standard.in.write_time  = write_time;
225                 sf->standard.in.access_time = 0;
226                 status = ntvfs->ops->setfileinfo(ntvfs, req, sf);
227         }
228
229         if (set_size != 0) {
230                 sf = talloc_p(req, union smb_setfileinfo);                      
231                 sf->generic.level            = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
232                 sf->generic.file.fnum        = io2->generic.out.fnum;
233                 sf->end_of_file_info.in.size = set_size;
234                 status = ntvfs->ops->setfileinfo(ntvfs, req, sf);
235                 if (NT_STATUS_IS_OK(status)) {
236                         io->openx.out.size = io->openx.in.size;
237                 }
238         }
239
240         req->async_states->state = state;
241
242         return NT_STATUS_OK;
243 }
244
245 /*
246   the core of the mapping between openx style parameters and ntcreatex 
247   parameters
248 */
249 static NTSTATUS map_openx_open(uint16_t flags, uint16_t open_mode, 
250                                uint16_t open_func, const char *fname,
251                                union smb_open *io2)
252 {
253         if (flags & OPENX_FLAGS_REQUEST_OPLOCK) {
254                 io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_OPLOCK;
255         }
256         if (flags & OPENX_FLAGS_REQUEST_BATCH_OPLOCK) {
257                 io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
258         }
259
260         switch (open_mode & OPENX_MODE_ACCESS_MASK) {
261         case OPENX_MODE_ACCESS_READ:
262                 io2->generic.in.access_mask = SEC_RIGHTS_FILE_READ;
263                 break;
264         case OPENX_MODE_ACCESS_WRITE:
265                 io2->generic.in.access_mask = SEC_RIGHTS_FILE_WRITE;
266                 break;
267         case OPENX_MODE_ACCESS_RDWR:
268         case OPENX_MODE_ACCESS_FCB:
269         case OPENX_MODE_ACCESS_EXEC:
270                 io2->generic.in.access_mask = 
271                         SEC_RIGHTS_FILE_READ | 
272                         SEC_RIGHTS_FILE_WRITE;
273                 break;
274         default:
275                 return NT_STATUS_INVALID_LOCK_SEQUENCE;
276         }
277
278         switch (open_mode & OPENX_MODE_DENY_MASK) {
279         case OPENX_MODE_DENY_READ:
280                 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_WRITE;
281                 break;
282         case OPENX_MODE_DENY_WRITE:
283                 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
284                 break;
285         case OPENX_MODE_DENY_ALL:
286                 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
287                 break;
288         case OPENX_MODE_DENY_NONE:
289                 io2->generic.in.share_access = 
290                         NTCREATEX_SHARE_ACCESS_READ | 
291                         NTCREATEX_SHARE_ACCESS_WRITE;
292                 break;
293         case OPENX_MODE_DENY_DOS:
294                 /* DENY_DOS is quite strange - it depends on the filename! */
295                 io2->generic.in.create_options |= 
296                         NTCREATEX_OPTIONS_PRIVATE_DENY_DOS;
297                 if (is_exe_filename(fname)) {
298                         io2->generic.in.share_access = 
299                                 NTCREATEX_SHARE_ACCESS_READ | 
300                                 NTCREATEX_SHARE_ACCESS_WRITE;
301                 } else {
302                         if ((open_mode & OPENX_MODE_ACCESS_MASK) == OPENX_MODE_ACCESS_READ) {
303                                 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
304                         } else {
305                                 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
306                         }
307                 }
308                 break;
309         case OPENX_MODE_DENY_FCB:
310                 io2->generic.in.create_options |= NTCREATEX_OPTIONS_PRIVATE_DENY_FCB;
311                 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
312                 break;
313         default:
314                 return NT_STATUS_INVALID_LOCK_SEQUENCE;
315         }
316
317         switch (open_func) {
318         case (OPENX_OPEN_FUNC_OPEN):
319                 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN;
320                 break;
321         case (OPENX_OPEN_FUNC_TRUNC):
322                 io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
323                 break;
324         case (OPENX_OPEN_FUNC_FAIL | OPENX_OPEN_FUNC_CREATE):
325                 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
326                 break;
327         case (OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE):
328                 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
329                 break;
330         case (OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE):
331                 io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
332                 break;                  
333         default:
334                 /* this one is very strange */
335                 if ((open_mode & OPENX_MODE_ACCESS_MASK) == OPENX_MODE_ACCESS_EXEC) {
336                         io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
337                         break;
338                 }
339                 return NT_STATUS_INVALID_LOCK_SEQUENCE;
340         }
341
342         return NT_STATUS_OK;
343 }
344
345 /* 
346    NTVFS open generic to any mapper
347 */
348 NTSTATUS ntvfs_map_open(struct smbsrv_request *req, union smb_open *io, 
349                         struct ntvfs_module_context *ntvfs)
350 {
351         NTSTATUS status;
352         union smb_open *io2;
353
354         io2 = talloc_zero_p(req, union smb_open);
355         if (io2 == NULL) {
356                 return NT_STATUS_NO_MEMORY;
357         }
358
359         status = ntvfs_map_async_setup(req, ntvfs, io, io2, 
360                                        (second_stage_t)ntvfs_map_open_finish);
361         if (!NT_STATUS_IS_OK(status)) {
362                 return status;
363         }
364
365         io2->generic.level = RAW_OPEN_GENERIC;
366                 
367         switch (io->generic.level) {
368         case RAW_OPEN_OPENX:
369                 status = map_openx_open(io->openx.in.flags,
370                                         io->openx.in.open_mode, 
371                                         io->openx.in.open_func, 
372                                         io->openx.in.fname,
373                                         io2);
374                 if (!NT_STATUS_IS_OK(status)) {
375                         goto done;
376                 }
377                 
378                 io2->generic.in.file_attr = io->openx.in.file_attrs;
379                 io2->generic.in.fname = io->openx.in.fname;
380                 
381                 status = ntvfs->ops->openfile(ntvfs, req, io2);
382                 break;
383                 
384                 
385         case RAW_OPEN_OPEN:
386                 status = map_openx_open(0,
387                                         io->openold.in.open_mode, 
388                                         OPENX_OPEN_FUNC_OPEN, 
389                                         io->openold.in.fname,
390                                         io2);
391                 if (!NT_STATUS_IS_OK(status)) {
392                         goto done;
393                 }
394
395                 io2->generic.in.file_attr = io->openold.in.search_attrs;
396                 io2->generic.in.fname = io->openold.in.fname;
397
398                 status = ntvfs->ops->openfile(ntvfs, req, io2);
399                 break;
400
401         case RAW_OPEN_T2OPEN:
402                 io2->generic.level         = RAW_OPEN_NTTRANS_CREATE;
403
404                 if (io->t2open.in.open_func == 0) {
405                         status = NT_STATUS_OBJECT_NAME_COLLISION;
406                         goto done;
407                 }
408
409                 status = map_openx_open(io->t2open.in.flags,
410                                         io->t2open.in.open_mode, 
411                                         io->t2open.in.open_func, 
412                                         io->t2open.in.fname,
413                                         io2);
414                 if (!NT_STATUS_IS_OK(status)) {
415                         goto done;
416                 }
417
418                 io2->generic.in.file_attr        = io->t2open.in.file_attrs;
419                 io2->generic.in.fname            = io->t2open.in.fname;
420                 io2->generic.in.ea_list          = talloc_p(io2, struct smb_ea_list);
421                 io2->generic.in.ea_list->num_eas = io->t2open.in.num_eas;
422                 io2->generic.in.ea_list->eas     = io->t2open.in.eas;
423
424                 status = ntvfs->ops->openfile(ntvfs, req, io2);
425                 break;
426
427         case RAW_OPEN_MKNEW:
428                 io2->generic.in.file_attr = io->mknew.in.attrib;
429                 io2->generic.in.fname = io->mknew.in.fname;
430                 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
431                 io2->generic.in.access_mask = 
432                         SEC_RIGHTS_FILE_READ |
433                         SEC_RIGHTS_FILE_WRITE;
434                 io2->generic.in.share_access = 
435                         NTCREATEX_SHARE_ACCESS_READ | 
436                         NTCREATEX_SHARE_ACCESS_WRITE;
437                 status = ntvfs->ops->openfile(ntvfs, req, io2);
438                 break;
439
440         case RAW_OPEN_CREATE:
441                 io2->generic.in.file_attr = io->mknew.in.attrib;
442                 io2->generic.in.fname = io->mknew.in.fname;
443                 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
444                 io2->generic.in.access_mask = 
445                         SEC_RIGHTS_FILE_READ |
446                         SEC_RIGHTS_FILE_WRITE;
447                 io2->generic.in.share_access = 
448                         NTCREATEX_SHARE_ACCESS_READ | 
449                         NTCREATEX_SHARE_ACCESS_WRITE;
450                 status = ntvfs->ops->openfile(ntvfs, req, io2);
451                 break;
452
453         case RAW_OPEN_CTEMP:
454                 io2->generic.in.file_attr = io->ctemp.in.attrib;
455                 io2->generic.in.file_attr = 0;
456                 io2->generic.in.fname = 
457                         talloc_asprintf(io2, "%s\\SRV%s", 
458                                         io->ctemp.in.directory,
459                                         generate_random_str_list(io2, 5, "0123456789"));
460                 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
461                 io2->generic.in.access_mask = 
462                         SEC_RIGHTS_FILE_READ |
463                         SEC_RIGHTS_FILE_WRITE;
464                 io2->generic.in.share_access = 
465                         NTCREATEX_SHARE_ACCESS_READ | 
466                         NTCREATEX_SHARE_ACCESS_WRITE;
467                 status = ntvfs->ops->openfile(ntvfs, req, io2);
468                 break;
469
470         default:
471                 status = NT_STATUS_INVALID_LEVEL;
472                 break;
473         }
474 done:
475         return ntvfs_map_async_finish(req, status);
476 }
477
478
479 /* 
480    NTVFS fsinfo generic to any mapper
481 */
482 NTSTATUS ntvfs_map_fsinfo(struct smbsrv_request *req, union smb_fsinfo *fs, 
483                           struct ntvfs_module_context *ntvfs)
484 {
485         NTSTATUS status;
486         union smb_fsinfo *fs2;
487
488         fs2 = talloc_p(req, union smb_fsinfo);
489         if (fs2 == NULL) {
490                 return NT_STATUS_NO_MEMORY;
491         }
492
493         if (fs->generic.level == RAW_QFS_GENERIC) {
494                 return NT_STATUS_INVALID_LEVEL;
495         }
496         
497         /* this map function is only used by the simple backend, which
498            doesn't do async */
499         req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
500
501         /* ask the backend for the generic info */
502         fs2->generic.level = RAW_QFS_GENERIC;
503
504         status = ntvfs->ops->fsinfo(ntvfs, req, fs2);
505         if (!NT_STATUS_IS_OK(status)) {
506                 return status;
507         }
508
509         /* and convert it to the required level */
510         switch (fs->generic.level) {
511         case RAW_QFS_GENERIC:
512                 return NT_STATUS_INVALID_LEVEL;
513
514         case RAW_QFS_DSKATTR: {
515                 /* map from generic to DSKATTR */
516                 uint_t bpunit = 64;
517
518                 /* we need to scale the sizes to fit */
519                 for (bpunit=64; bpunit<0x10000; bpunit *= 2) {
520                         if (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size < bpunit * 512 * 65535.0) {
521                                 break;
522                         }
523                 }
524
525                 fs->dskattr.out.blocks_per_unit = bpunit;
526                 fs->dskattr.out.block_size = 512;
527                 fs->dskattr.out.units_total = 
528                         (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size) / (bpunit * 512);
529                 fs->dskattr.out.units_free  = 
530                         (fs2->generic.out.blocks_free  * (double)fs2->generic.out.block_size) / (bpunit * 512);
531
532                 /* we must return a maximum of 2G to old DOS systems, or they get very confused */
533                 if (bpunit > 64 && req->smb_conn->negotiate.protocol <= PROTOCOL_LANMAN2) {
534                         fs->dskattr.out.blocks_per_unit = 64;
535                         fs->dskattr.out.units_total = 0xFFFF;
536                         fs->dskattr.out.units_free = 0xFFFF;
537                 }
538                 return NT_STATUS_OK;
539         }
540
541         case RAW_QFS_ALLOCATION:
542                 fs->allocation.out.fs_id = fs2->generic.out.fs_id;
543                 fs->allocation.out.total_alloc_units = fs2->generic.out.blocks_total;
544                 fs->allocation.out.avail_alloc_units = fs2->generic.out.blocks_free;
545                 fs->allocation.out.sectors_per_unit = 1;
546                 fs->allocation.out.bytes_per_sector = fs2->generic.out.block_size;
547                 return NT_STATUS_OK;
548
549         case RAW_QFS_VOLUME:
550                 fs->volume.out.serial_number = fs2->generic.out.serial_number;
551                 fs->volume.out.volume_name.s = fs2->generic.out.volume_name;
552                 return NT_STATUS_OK;
553
554         case RAW_QFS_VOLUME_INFO:
555         case RAW_QFS_VOLUME_INFORMATION:
556                 fs->volume_info.out.create_time = fs2->generic.out.create_time;
557                 fs->volume_info.out.serial_number = fs2->generic.out.serial_number;
558                 fs->volume_info.out.volume_name.s = fs2->generic.out.volume_name;
559                 return NT_STATUS_OK;
560
561         case RAW_QFS_SIZE_INFO:
562         case RAW_QFS_SIZE_INFORMATION:
563                 fs->size_info.out.total_alloc_units = fs2->generic.out.blocks_total;
564                 fs->size_info.out.avail_alloc_units = fs2->generic.out.blocks_free;
565                 fs->size_info.out.sectors_per_unit = 1;
566                 fs->size_info.out.bytes_per_sector = fs2->generic.out.block_size;
567                 return NT_STATUS_OK;
568
569         case RAW_QFS_DEVICE_INFO:
570         case RAW_QFS_DEVICE_INFORMATION:
571                 fs->device_info.out.device_type = fs2->generic.out.device_type;
572                 fs->device_info.out.characteristics = fs2->generic.out.device_characteristics;
573                 return NT_STATUS_OK;
574
575         case RAW_QFS_ATTRIBUTE_INFO:
576         case RAW_QFS_ATTRIBUTE_INFORMATION:
577                 fs->attribute_info.out.fs_attr = fs2->generic.out.fs_attr;
578                 fs->attribute_info.out.max_file_component_length = fs2->generic.out.max_file_component_length;
579                 fs->attribute_info.out.fs_type.s = fs2->generic.out.fs_type;
580                 return NT_STATUS_OK;
581
582         case RAW_QFS_QUOTA_INFORMATION:
583                 ZERO_STRUCT(fs->quota_information.out.unknown);
584                 fs->quota_information.out.quota_soft = fs2->generic.out.quota_soft;
585                 fs->quota_information.out.quota_hard = fs2->generic.out.quota_hard;
586                 fs->quota_information.out.quota_flags = fs2->generic.out.quota_flags;
587                 return NT_STATUS_OK;
588
589         case RAW_QFS_FULL_SIZE_INFORMATION:
590                 fs->full_size_information.out.total_alloc_units = fs2->generic.out.blocks_total;
591                 fs->full_size_information.out.call_avail_alloc_units = fs2->generic.out.blocks_free;
592                 fs->full_size_information.out.actual_avail_alloc_units = fs2->generic.out.blocks_free;
593                 fs->full_size_information.out.sectors_per_unit = 1;
594                 fs->full_size_information.out.bytes_per_sector = fs2->generic.out.block_size;
595                 return NT_STATUS_OK;
596
597         case RAW_QFS_OBJECTID_INFORMATION:
598                 fs->objectid_information.out.guid = fs2->generic.out.guid;
599                 ZERO_STRUCT(fs->objectid_information.out.unknown);
600                 return NT_STATUS_OK;
601         }
602
603
604         return NT_STATUS_INVALID_LEVEL;
605 }
606
607
608 /* 
609    NTVFS fileinfo generic to any mapper
610 */
611 NTSTATUS ntvfs_map_fileinfo(struct smbsrv_request *req, union smb_fileinfo *info, 
612                             union smb_fileinfo *info2)
613 {
614         int i;
615         /* and convert it to the required level using results in info2 */
616         switch (info->generic.level) {
617                 case RAW_FILEINFO_GENERIC:
618                 return NT_STATUS_INVALID_LEVEL;
619         case RAW_FILEINFO_GETATTR:
620                 info->getattr.out.attrib = info2->generic.out.attrib & 0xff;
621                 info->getattr.out.size = info2->generic.out.size;
622                 info->getattr.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
623                 return NT_STATUS_OK;
624                 
625         case RAW_FILEINFO_GETATTRE:
626                 info->getattre.out.attrib = info2->generic.out.attrib;
627                 info->getattre.out.size = info2->generic.out.size;
628                 info->getattre.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
629                 info->getattre.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
630                 info->getattre.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
631                 info->getattre.out.alloc_size = info2->generic.out.alloc_size;
632                 return NT_STATUS_OK;
633                 
634         case RAW_FILEINFO_NETWORK_OPEN_INFORMATION:
635                 info->network_open_information.out.create_time = info2->generic.out.create_time;
636                 info->network_open_information.out.access_time = info2->generic.out.access_time;
637                 info->network_open_information.out.write_time =  info2->generic.out.write_time;
638                 info->network_open_information.out.change_time = info2->generic.out.change_time;
639                 info->network_open_information.out.alloc_size = info2->generic.out.alloc_size;
640                 info->network_open_information.out.size = info2->generic.out.size;
641                 info->network_open_information.out.attrib = info2->generic.out.attrib;
642                 return NT_STATUS_OK;
643
644         case RAW_FILEINFO_ALL_INFO:
645         case RAW_FILEINFO_ALL_INFORMATION:
646                 info->all_info.out.create_time = info2->generic.out.create_time;
647                 info->all_info.out.access_time = info2->generic.out.access_time;
648                 info->all_info.out.write_time =  info2->generic.out.write_time;
649                 info->all_info.out.change_time = info2->generic.out.change_time;
650                 info->all_info.out.attrib = info2->generic.out.attrib;
651                 info->all_info.out.alloc_size = info2->generic.out.alloc_size;
652                 info->all_info.out.size = info2->generic.out.size;
653                 info->all_info.out.nlink = info2->generic.out.nlink;
654                 info->all_info.out.delete_pending = info2->generic.out.delete_pending;
655                 info->all_info.out.directory = info2->generic.out.directory;
656                 info->all_info.out.ea_size = info2->generic.out.ea_size;
657                 info->all_info.out.fname.s = info2->generic.out.fname.s;
658                 info->all_info.out.fname.private_length = info2->generic.out.fname.private_length;
659                 return NT_STATUS_OK;
660
661         case RAW_FILEINFO_BASIC_INFO:
662         case RAW_FILEINFO_BASIC_INFORMATION:
663                 info->basic_info.out.create_time = info2->generic.out.create_time;
664                 info->basic_info.out.access_time = info2->generic.out.access_time;
665                 info->basic_info.out.write_time = info2->generic.out.write_time;
666                 info->basic_info.out.change_time = info2->generic.out.change_time;
667                 info->basic_info.out.attrib = info2->generic.out.attrib;
668                 return NT_STATUS_OK;
669
670         case RAW_FILEINFO_STANDARD:
671                 info->standard.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
672                 info->standard.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
673                 info->standard.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
674                 info->standard.out.size = info2->generic.out.size;
675                 info->standard.out.alloc_size = info2->generic.out.alloc_size;
676                 info->standard.out.attrib = info2->generic.out.attrib;
677                 return NT_STATUS_OK;
678
679         case RAW_FILEINFO_EA_SIZE:
680                 info->ea_size.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
681                 info->ea_size.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
682                 info->ea_size.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
683                 info->ea_size.out.size = info2->generic.out.size;
684                 info->ea_size.out.alloc_size = info2->generic.out.alloc_size;
685                 info->ea_size.out.attrib = info2->generic.out.attrib;
686                 info->ea_size.out.ea_size = info2->generic.out.ea_size;
687                 return NT_STATUS_OK;
688
689         case RAW_FILEINFO_STANDARD_INFO:
690         case RAW_FILEINFO_STANDARD_INFORMATION:
691                 info->standard_info.out.alloc_size = info2->generic.out.alloc_size;
692                 info->standard_info.out.size = info2->generic.out.size;
693                 info->standard_info.out.nlink = info2->generic.out.nlink;
694                 info->standard_info.out.delete_pending = info2->generic.out.delete_pending;
695                 info->standard_info.out.directory = info2->generic.out.directory;
696                 return NT_STATUS_OK;
697
698         case RAW_FILEINFO_INTERNAL_INFORMATION:
699                 info->internal_information.out.file_id = info2->generic.out.file_id;
700                 return NT_STATUS_OK;
701
702         case RAW_FILEINFO_EA_INFO:
703         case RAW_FILEINFO_EA_INFORMATION:
704                 info->ea_info.out.ea_size = info2->generic.out.ea_size;
705                 return NT_STATUS_OK;
706
707         case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION:
708                 info->attribute_tag_information.out.attrib = info2->generic.out.attrib;
709                 info->attribute_tag_information.out.reparse_tag = info2->generic.out.reparse_tag;
710                 return NT_STATUS_OK;
711
712         case RAW_FILEINFO_STREAM_INFO:
713         case RAW_FILEINFO_STREAM_INFORMATION:
714                 info->stream_info.out.num_streams = info2->generic.out.num_streams;
715                 if (info->stream_info.out.num_streams > 0) {
716                         info->stream_info.out.streams = 
717                                 talloc_array_p(req, 
718                                                struct stream_struct,
719                                                info->stream_info.out.num_streams);
720                         if (!info->stream_info.out.streams) {
721                                 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d streams\n",
722                                         info->stream_info.out.num_streams));
723                                 return NT_STATUS_NO_MEMORY;
724                         }
725                         for (i=0; i < info->stream_info.out.num_streams; i++) {
726                                 info->stream_info.out.streams[i] = info2->generic.out.streams[i];
727                                 info->stream_info.out.streams[i].stream_name.s = 
728                                         talloc_strdup(req, info2->generic.out.streams[i].stream_name.s);
729                                 if (!info->stream_info.out.streams[i].stream_name.s) {
730                                         DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
731                                         return NT_STATUS_NO_MEMORY;
732                                 }
733                         }
734                 }
735                 return NT_STATUS_OK;
736
737         case RAW_FILEINFO_NAME_INFO:
738         case RAW_FILEINFO_NAME_INFORMATION:
739                 info->name_info.out.fname.s = talloc_strdup(req, info2->generic.out.fname.s);
740                 info->name_info.out.fname.private_length = info2->generic.out.fname.private_length;
741                 return NT_STATUS_OK;
742                 
743         case RAW_FILEINFO_ALT_NAME_INFO:
744         case RAW_FILEINFO_ALT_NAME_INFORMATION:
745                 info->alt_name_info.out.fname.s = talloc_strdup(req, info2->generic.out.alt_fname.s);
746                 info->alt_name_info.out.fname.private_length = info2->generic.out.alt_fname.private_length;
747                 return NT_STATUS_OK;
748         
749         case RAW_FILEINFO_POSITION_INFORMATION:
750                 info->position_information.out.position = info2->generic.out.position;
751                 return NT_STATUS_OK;
752         
753         case RAW_FILEINFO_ALL_EAS:
754                 info->all_eas.out.num_eas = info2->generic.out.num_eas;
755                 if (info->all_eas.out.num_eas > 0) {
756                         info->all_eas.out.eas = talloc_array_p(req, 
757                                                                struct ea_struct,
758                                                                info->all_eas.out.num_eas);
759                         if (!info->all_eas.out.eas) {
760                                 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d eas\n",
761                                         info->all_eas.out.num_eas));
762                                 return NT_STATUS_NO_MEMORY;
763                         }
764                         for (i = 0; i < info->all_eas.out.num_eas; i++) {
765                                 info->all_eas.out.eas[i] = info2->generic.out.eas[i];
766                                 info->all_eas.out.eas[i].name.s = 
767                                         talloc_strdup(req, info2->generic.out.eas[i].name.s);
768                                 if (!info->all_eas.out.eas[i].name.s) {
769                                         DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
770                                         return NT_STATUS_NO_MEMORY;
771                                 }
772                                 info->all_eas.out.eas[i].value.data = 
773                                         talloc_memdup(req,
774                                                 info2->generic.out.eas[i].value.data,
775                                                 info2->generic.out.eas[i].value.length);
776                                 if (!info->all_eas.out.eas[i].value.data) {
777                                         DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
778                                         return NT_STATUS_NO_MEMORY;
779                                 }
780                         }
781                 }
782                 return NT_STATUS_OK;
783                 
784         case RAW_FILEINFO_IS_NAME_VALID:
785                 return NT_STATUS_OK;
786                 
787         case RAW_FILEINFO_COMPRESSION_INFO:
788         case RAW_FILEINFO_COMPRESSION_INFORMATION:
789                 info->compression_info.out.compressed_size = info2->generic.out.compressed_size;
790                 info->compression_info.out.format = info2->generic.out.format;
791                 info->compression_info.out.unit_shift = info2->generic.out.unit_shift;
792                 info->compression_info.out.chunk_shift = info2->generic.out.chunk_shift;
793                 info->compression_info.out.cluster_shift = info2->generic.out.cluster_shift;
794                 return NT_STATUS_OK;
795                 
796         case RAW_FILEINFO_ACCESS_INFORMATION:
797                 info->access_information.out.access_flags = info2->generic.out.access_flags;
798                 return NT_STATUS_OK;
799                 
800         case RAW_FILEINFO_MODE_INFORMATION:
801                 info->mode_information.out.mode = info2->generic.out.mode;
802                 return NT_STATUS_OK;
803                 
804         case RAW_FILEINFO_ALIGNMENT_INFORMATION:
805                 info->alignment_information.out.alignment_requirement =
806                         info2->generic.out.alignment_requirement;
807                 return NT_STATUS_OK;
808 #if 0   
809         case RAW_FILEINFO_UNIX_BASIC:
810                 info->unix_basic_info.out.end_of_file = info2->generic.out.end_of_file;
811                 info->unix_basic_info.out.num_bytes = info2->generic.out.size;
812                 info->unix_basic_info.out.status_change_time = info2->generic.out.change_time;
813                 info->unix_basic_info.out.access_time = info2->generic.out.access_time;
814                 info->unix_basic_info.out.change_time = info2->generic.out.change_time;
815                 info->unix_basic_info.out.uid = info2->generic.out.uid;
816                 info->unix_basic_info.out.gid = info2->generic.out.gid;
817                 info->unix_basic_info.out.file_type = info2->generic.out.file_type;
818                 info->unix_basic_info.out.dev_major = info2->generic.out.device;
819                 info->unix_basic_info.out.dev_minor = info2->generic.out.device;
820                 info->unix_basic_info.out.unique_id = info2->generic.out.inode;
821                 info->unix_basic_info.out.permissions = info2->generic.out.permissions;
822                 info->unix_basic_info.out.nlink = info2->generic.out.nlink;
823                 return NT_STATUS_OK;
824                 
825         case RAW_FILEINFO_UNIX_LINK:
826                 info->unix_link_info.out.link_dest = info2->generic.out.link_dest;
827                 return NT_STATUS_OK;
828 #endif
829         }
830
831         return NT_STATUS_INVALID_LEVEL;
832 }
833
834 /* 
835    NTVFS fileinfo generic to any mapper
836 */
837 NTSTATUS ntvfs_map_qfileinfo(struct smbsrv_request *req, union smb_fileinfo *info, 
838                              struct ntvfs_module_context *ntvfs)
839 {
840         NTSTATUS status;
841         union smb_fileinfo *info2;
842
843         info2 = talloc_p(req, union smb_fileinfo);
844         if (info2 == NULL) {
845                 return NT_STATUS_NO_MEMORY;
846         }
847
848         if (info->generic.level == RAW_FILEINFO_GENERIC) {
849                 return NT_STATUS_INVALID_LEVEL;
850         }
851
852         /* ask the backend for the generic info */
853         info2->generic.level = RAW_FILEINFO_GENERIC;
854         info2->generic.in.fnum = info->generic.in.fnum;
855
856         status = ntvfs->ops->qfileinfo(ntvfs, req, info2);
857         if (!NT_STATUS_IS_OK(status)) {
858                 return status;
859         }
860         return ntvfs_map_fileinfo(req, info, info2);
861 }
862
863 /* 
864    NTVFS pathinfo generic to any mapper
865 */
866 NTSTATUS ntvfs_map_qpathinfo(struct smbsrv_request *req, union smb_fileinfo *info, 
867                              struct ntvfs_module_context *ntvfs)
868 {
869         NTSTATUS status;
870         union smb_fileinfo *info2;
871
872         info2 = talloc_p(req, union smb_fileinfo);
873         if (info2 == NULL) {
874                 return NT_STATUS_NO_MEMORY;
875         }
876
877         if (info->generic.level == RAW_FILEINFO_GENERIC) {
878                 return NT_STATUS_INVALID_LEVEL;
879         }
880
881         /* ask the backend for the generic info */
882         info2->generic.level = RAW_FILEINFO_GENERIC;
883         info2->generic.in.fname = info->generic.in.fname;
884
885         /* only used by the simple backend, which doesn't do async */
886         req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
887
888         status = ntvfs->ops->qpathinfo(ntvfs, req, info2);
889         if (!NT_STATUS_IS_OK(status)) {
890                 return status;
891         }
892         return ntvfs_map_fileinfo(req, info, info2);
893 }
894
895
896 /* 
897    NTVFS lock generic to any mapper
898 */
899 NTSTATUS ntvfs_map_lock(struct smbsrv_request *req, union smb_lock *lck, 
900                         struct ntvfs_module_context *ntvfs)
901 {
902         union smb_lock *lck2;
903         struct smb_lock_entry *locks;
904
905         lck2 = talloc_p(req, union smb_lock);
906         if (lck2 == NULL) {
907                 return NT_STATUS_NO_MEMORY;
908         }
909
910         locks = talloc_array_p(lck2, struct smb_lock_entry, 1);
911         if (locks == NULL) {
912                 return NT_STATUS_NO_MEMORY;
913         }
914
915         switch (lck->generic.level) {
916         case RAW_LOCK_LOCKX:
917                 return NT_STATUS_INVALID_LEVEL;
918
919         case RAW_LOCK_LOCK:
920                 lck2->generic.in.ulock_cnt = 0;
921                 lck2->generic.in.lock_cnt = 1;
922                 break;
923
924         case RAW_LOCK_UNLOCK:
925                 lck2->generic.in.ulock_cnt = 1;
926                 lck2->generic.in.lock_cnt = 0;
927                 break;
928         }
929
930         lck2->generic.level = RAW_LOCK_GENERIC;
931         lck2->generic.in.fnum = lck->lock.in.fnum;
932         lck2->generic.in.mode = 0;
933         lck2->generic.in.timeout = 0;
934         lck2->generic.in.locks = locks;
935         locks->pid = req->smbpid;
936         locks->offset = lck->lock.in.offset;
937         locks->count = lck->lock.in.count;
938
939         return ntvfs->ops->lock(ntvfs, req, lck2);
940 }
941
942
943 /* 
944    NTVFS write generic to any mapper
945 */
946 static NTSTATUS ntvfs_map_write_finish(struct smbsrv_request *req, 
947                                        struct ntvfs_module_context *ntvfs,
948                                        union smb_write *wr, 
949                                        union smb_write *wr2, 
950                                        NTSTATUS status)
951                                        
952 {
953         union smb_lock *lck;
954         union smb_close *cl;
955         uint_t state;
956
957         if (NT_STATUS_IS_ERR(status)) {
958                 return status;
959         }
960
961         switch (wr->generic.level) {
962         case RAW_WRITE_WRITE:
963                 wr->write.out.nwritten    = wr2->generic.out.nwritten;
964                 break;
965
966         case RAW_WRITE_WRITEUNLOCK:
967                 wr->writeunlock.out.nwritten = wr2->generic.out.nwritten;
968
969                 lck = talloc_p(wr2, union smb_lock);
970                 if (lck == NULL) {
971                         return NT_STATUS_NO_MEMORY;
972                 }
973
974                 lck->unlock.level      = RAW_LOCK_UNLOCK;
975                 lck->unlock.in.fnum    = wr->writeunlock.in.fnum;
976                 lck->unlock.in.count   = wr->writeunlock.in.count;
977                 lck->unlock.in.offset  = wr->writeunlock.in.offset;
978
979                 if (lck->unlock.in.count != 0) {
980                         /* do the lock sync for now */
981                         state = req->async_states->state;
982                         req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
983                         status = ntvfs->ops->lock(ntvfs, req, lck);
984                         req->async_states->state = state;
985                 }
986                 break;
987
988         case RAW_WRITE_WRITECLOSE:
989                 wr->writeclose.out.nwritten    = wr2->generic.out.nwritten;
990
991                 cl = talloc_p(wr2, union smb_close);
992                 if (cl == NULL) {
993                         return NT_STATUS_NO_MEMORY;
994                 }
995
996                 cl->close.level           = RAW_CLOSE_CLOSE;
997                 cl->close.in.fnum         = wr->writeclose.in.fnum;
998                 cl->close.in.write_time   = wr->writeclose.in.mtime;
999
1000                 if (wr2->generic.in.count != 0) {
1001                         /* do the close sync for now */
1002                         state = req->async_states->state;
1003                         req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1004                         status = ntvfs->ops->close(ntvfs, req, cl);
1005                         req->async_states->state = state;
1006                 }
1007                 break;
1008
1009         case RAW_WRITE_SPLWRITE:
1010                 break;
1011         default:
1012                 return NT_STATUS_INVALID_LEVEL;
1013         }
1014
1015         return status;
1016 }
1017
1018
1019 /* 
1020    NTVFS write generic to any mapper
1021 */
1022 NTSTATUS ntvfs_map_write(struct smbsrv_request *req, union smb_write *wr, 
1023                          struct ntvfs_module_context *ntvfs)
1024 {
1025         union smb_write *wr2;
1026         NTSTATUS status;
1027
1028         wr2 = talloc_p(req, union smb_write);
1029         if (wr2 == NULL) {
1030                 return NT_STATUS_NO_MEMORY;
1031         }
1032
1033         status = ntvfs_map_async_setup(req, ntvfs, wr, wr2, 
1034                                        (second_stage_t)ntvfs_map_write_finish);
1035         if (!NT_STATUS_IS_OK(status)) {
1036                 return status;
1037         }
1038
1039         wr2->writex.level = RAW_WRITE_GENERIC;
1040
1041         switch (wr->generic.level) {
1042         case RAW_WRITE_WRITEX:
1043                 status = NT_STATUS_INVALID_LEVEL;
1044                 break;
1045
1046         case RAW_WRITE_WRITE:
1047                 wr2->writex.in.fnum      = wr->write.in.fnum;
1048                 wr2->writex.in.offset    = wr->write.in.offset;
1049                 wr2->writex.in.wmode     = 0;
1050                 wr2->writex.in.remaining = wr->write.in.remaining;
1051                 wr2->writex.in.count     = wr->write.in.count;
1052                 wr2->writex.in.data      = wr->write.in.data;
1053                 status = ntvfs->ops->write(ntvfs, req, wr2);
1054                 break;
1055
1056         case RAW_WRITE_WRITEUNLOCK:
1057                 wr2->writex.in.fnum      = wr->writeunlock.in.fnum;
1058                 wr2->writex.in.offset    = wr->writeunlock.in.offset;
1059                 wr2->writex.in.wmode     = 0;
1060                 wr2->writex.in.remaining = wr->writeunlock.in.remaining;
1061                 wr2->writex.in.count     = wr->writeunlock.in.count;
1062                 wr2->writex.in.data      = wr->writeunlock.in.data;
1063                 status = ntvfs->ops->write(ntvfs, req, wr2);
1064                 break;
1065
1066         case RAW_WRITE_WRITECLOSE:
1067                 wr2->writex.in.fnum      = wr->writeclose.in.fnum;
1068                 wr2->writex.in.offset    = wr->writeclose.in.offset;
1069                 wr2->writex.in.wmode     = 0;
1070                 wr2->writex.in.remaining = 0;
1071                 wr2->writex.in.count     = wr->writeclose.in.count;
1072                 wr2->writex.in.data      = wr->writeclose.in.data;
1073                 status = ntvfs->ops->write(ntvfs, req, wr2);
1074                 break;
1075
1076         case RAW_WRITE_SPLWRITE:
1077                 wr2->writex.in.fnum      = wr->splwrite.in.fnum;
1078                 wr2->writex.in.offset    = 0;
1079                 wr2->writex.in.wmode     = 0;
1080                 wr2->writex.in.remaining = 0;
1081                 wr2->writex.in.count     = wr->splwrite.in.count;
1082                 wr2->writex.in.data      = wr->splwrite.in.data;
1083                 status = ntvfs->ops->write(ntvfs, req, wr2);
1084                 break;
1085         }
1086
1087         return ntvfs_map_async_finish(req, status);
1088 }
1089
1090
1091 /* 
1092    NTVFS read generic to any mapper - finish the out mapping
1093 */
1094 static NTSTATUS ntvfs_map_read_finish(struct smbsrv_request *req, 
1095                                       struct ntvfs_module_context *ntvfs, 
1096                                       union smb_read *rd, 
1097                                       union smb_read *rd2,
1098                                       NTSTATUS status)
1099 {
1100         switch (rd->generic.level) {
1101         case RAW_READ_READ:
1102                 rd->read.out.nread        = rd2->generic.out.nread;
1103                 break;
1104         case RAW_READ_READBRAW:
1105                 rd->readbraw.out.nread    = rd2->generic.out.nread;
1106                 break;
1107         case RAW_READ_LOCKREAD:
1108                 rd->lockread.out.nread = rd2->generic.out.nread;
1109                 break;
1110         default:
1111                 return NT_STATUS_INVALID_LEVEL;
1112         }
1113
1114         return status;
1115 }
1116
1117 /* 
1118    NTVFS read* to readx mapper
1119 */
1120 NTSTATUS ntvfs_map_read(struct smbsrv_request *req, union smb_read *rd, 
1121                          struct ntvfs_module_context *ntvfs)
1122 {
1123         union smb_read *rd2;
1124         union smb_lock *lck;
1125         NTSTATUS status;
1126         uint_t state;
1127
1128         rd2 = talloc_p(req, union smb_read);
1129         if (rd2 == NULL) {
1130                 return NT_STATUS_NO_MEMORY;
1131         }
1132
1133         status = ntvfs_map_async_setup(req, ntvfs, rd, rd2, 
1134                                        (second_stage_t)ntvfs_map_read_finish);
1135         if (!NT_STATUS_IS_OK(status)) {
1136                 return status;
1137         }
1138
1139         rd2->readx.level = RAW_READ_READX;
1140
1141         switch (rd->generic.level) {
1142         case RAW_READ_READX:
1143                 status = NT_STATUS_INVALID_LEVEL;
1144                 break;
1145
1146         case RAW_READ_READ:
1147                 rd2->readx.in.fnum      = rd->read.in.fnum;
1148                 rd2->readx.in.offset    = rd->read.in.offset;
1149                 rd2->readx.in.mincnt    = rd->read.in.count;
1150                 rd2->readx.in.maxcnt    = rd->read.in.count;
1151                 rd2->readx.in.remaining = rd->read.in.remaining;
1152                 rd2->readx.out.data     = rd->read.out.data;
1153                 status = ntvfs->ops->read(ntvfs, req, rd2);
1154                 break;
1155
1156         case RAW_READ_READBRAW:
1157                 rd2->readx.in.fnum      = rd->readbraw.in.fnum;
1158                 rd2->readx.in.offset    = rd->readbraw.in.offset;
1159                 rd2->readx.in.mincnt    = rd->readbraw.in.mincnt;
1160                 rd2->readx.in.maxcnt    = rd->readbraw.in.maxcnt;
1161                 rd2->readx.in.remaining = 0;
1162                 rd2->readx.out.data     = rd->readbraw.out.data;
1163                 status = ntvfs->ops->read(ntvfs, req, rd2);
1164                 break;
1165
1166         case RAW_READ_LOCKREAD:
1167                 /* do the initial lock sync for now */
1168                 state = req->async_states->state;
1169                 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1170
1171                 lck = talloc_p(rd2, union smb_lock);
1172                 if (lck == NULL) {
1173                         status = NT_STATUS_NO_MEMORY;
1174                         goto done;
1175                 }
1176                 lck->lock.level      = RAW_LOCK_LOCK;
1177                 lck->lock.in.fnum    = rd->lockread.in.fnum;
1178                 lck->lock.in.count   = rd->lockread.in.count;
1179                 lck->lock.in.offset  = rd->lockread.in.offset;
1180                 status = ntvfs->ops->lock(ntvfs, req, lck);
1181                 req->async_states->state = state;
1182
1183                 rd2->readx.in.fnum      = rd->lockread.in.fnum;
1184                 rd2->readx.in.offset    = rd->lockread.in.offset;
1185                 rd2->readx.in.mincnt    = rd->lockread.in.count;
1186                 rd2->readx.in.maxcnt    = rd->lockread.in.count;
1187                 rd2->readx.in.remaining = rd->lockread.in.remaining;
1188                 rd2->readx.out.data     = rd->lockread.out.data;
1189
1190                 if (NT_STATUS_IS_OK(status)) {
1191                         status = ntvfs->ops->read(ntvfs, req, rd2);
1192                 }
1193                 break;
1194         }
1195
1196 done:
1197         return ntvfs_map_async_finish(req, status);
1198 }
1199
1200
1201 /* 
1202    NTVFS close generic to any mapper
1203 */
1204 NTSTATUS ntvfs_map_close(struct smbsrv_request *req, union smb_close *cl, 
1205                          struct ntvfs_module_context *ntvfs)
1206 {
1207         union smb_close *cl2;
1208
1209         cl2 = talloc_p(req, union smb_close);
1210         if (cl2 == NULL) {
1211                 return NT_STATUS_NO_MEMORY;
1212         }
1213
1214         switch (cl->generic.level) {
1215         case RAW_CLOSE_CLOSE:
1216                 return NT_STATUS_INVALID_LEVEL;
1217
1218         case RAW_CLOSE_SPLCLOSE:
1219                 cl2->close.level   = RAW_CLOSE_CLOSE;
1220                 cl2->close.in.fnum = cl->splclose.in.fnum;
1221                 break;
1222         }
1223
1224         return ntvfs->ops->close(ntvfs, req, cl2);
1225 }