r14040: report errors better
[ira/wip.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 #include "ntvfs/ntvfs.h"
38
39 /* a second stage function converts from the out parameters of the generic
40    call onto the out parameters of the specific call made */
41 typedef NTSTATUS (*second_stage_t)(struct smbsrv_request *, 
42                                    struct ntvfs_module_context *,
43                                    void *, void *, NTSTATUS);
44
45 /* 
46    this structure holds the async state for pending mapped async calls
47 */
48 struct ntvfs_map_async {
49         struct ntvfs_module_context *ntvfs;
50         void *io, *io2;
51         second_stage_t fn;
52 };
53
54 /*
55   this is a async wrapper, called from the backend when it has completed
56   a function that it has decided to reply to in an async fashion
57 */
58 static void ntvfs_map_async_send(struct smbsrv_request *req)
59 {
60         struct ntvfs_map_async *m = req->async_states->private_data;
61
62         ntvfs_async_state_pop(req);
63
64         /* call the _finish function setup in ntvfs_map_async_setup() */
65         req->async_states->status = m->fn(req, m->ntvfs, m->io, m->io2, req->async_states->status);
66
67         /* call the send function from the next module up */
68         req->async_states->send_fn(req);
69 }
70
71 /*
72   prepare for calling a ntvfs backend with async support
73   io is the original call structure
74   io2 is the new call structure for the mapped call
75   fn is a second stage function for processing the out arguments
76 */
77 static NTSTATUS ntvfs_map_async_setup(struct smbsrv_request *req,
78                                       struct ntvfs_module_context *ntvfs,
79                                       void *io, void *io2,
80                                       second_stage_t fn)
81 {
82         struct ntvfs_map_async *m;
83         m = talloc(req, struct ntvfs_map_async);
84         if (m == NULL) {
85                 return NT_STATUS_NO_MEMORY;
86         }
87         m->ntvfs = ntvfs;
88         m->io = io;
89         m->io2 = io2;
90         m->fn = fn;
91         return ntvfs_async_state_push(req, m, ntvfs_map_async_send, ntvfs);
92 }
93
94
95 /*
96   called when first stage processing is complete. 
97 */      
98 static NTSTATUS ntvfs_map_async_finish(struct smbsrv_request *req, NTSTATUS status)
99 {
100         struct ntvfs_map_async *m;
101
102         /* if the backend has decided to reply in an async fashion then
103            we don't need to do any work here */
104         if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
105                 return status;
106         }
107
108         /* the backend is replying immediately. call the 2nd stage function after popping our local
109            async state */
110         m = req->async_states->private_data;
111
112         ntvfs_async_state_pop(req);
113
114         return m->fn(req, m->ntvfs, m->io, m->io2, status);
115 }
116
117
118 /*
119   see if a filename ends in EXE COM DLL or SYM. This is needed for the
120   DENY_DOS mapping for OpenX
121 */
122 BOOL is_exe_filename(const char *fname)
123 {
124         char *p;
125         p = strrchr(fname, '.');
126         if (!p) {
127                 return False;
128         }
129         p++;
130         if (strcasecmp(p, "EXE") == 0 ||
131             strcasecmp(p, "COM") == 0 ||
132             strcasecmp(p, "DLL") == 0 ||
133             strcasecmp(p, "SYM") == 0) {
134                 return True;
135         }
136         return False;
137 }
138
139
140 /* 
141    NTVFS openx to ntcreatex mapper
142 */
143 static NTSTATUS ntvfs_map_open_finish(struct smbsrv_request *req, 
144                                       struct ntvfs_module_context *ntvfs,
145                                       union smb_open *io, 
146                                       union smb_open *io2, 
147                                       NTSTATUS status)
148 {
149         time_t write_time = 0;
150         uint32_t set_size = 0;
151         union smb_setfileinfo *sf;
152         uint_t state;
153
154         if (!NT_STATUS_IS_OK(status)) {
155                 return status;
156         }
157
158         switch (io->generic.level) {
159         case RAW_OPEN_OPEN:
160                 io->openold.out.fnum       = io2->generic.out.fnum;
161                 io->openold.out.attrib     = io2->generic.out.attrib;
162                 io->openold.out.write_time = nt_time_to_unix(io2->generic.out.write_time);
163                 io->openold.out.size       = io2->generic.out.size;
164                 io->openold.out.rmode      = io->openold.in.open_mode;
165                 break;
166
167         case RAW_OPEN_OPENX:
168                 io->openx.out.fnum        = io2->generic.out.fnum;
169                 io->openx.out.attrib      = io2->generic.out.attrib;
170                 io->openx.out.write_time  = nt_time_to_unix(io2->generic.out.write_time);
171                 io->openx.out.size        = io2->generic.out.size;
172                 io->openx.out.access      = (io->openx.in.open_mode & OPENX_MODE_ACCESS_MASK);
173                 io->openx.out.ftype       = 0;
174                 io->openx.out.devstate    = 0;
175                 io->openx.out.action      = io2->generic.out.create_action;
176                 io->openx.out.unique_fid  = 0;
177                 io->openx.out.access_mask = SEC_STD_ALL;
178                 io->openx.out.unknown     = 0;
179                 
180                 /* we need to extend the file to the requested size if
181                    it was newly created */
182                 if (io2->generic.out.create_action == NTCREATEX_ACTION_CREATED) {
183                         set_size = io->openx.in.size;
184                 }
185                 break;
186
187         case RAW_OPEN_T2OPEN:
188                 io->t2open.out.fnum        = io2->generic.out.fnum;
189                 io->t2open.out.attrib      = io2->generic.out.attrib;
190                 io->t2open.out.write_time  = nt_time_to_unix(io2->generic.out.write_time);
191                 io->t2open.out.size        = io2->generic.out.size;
192                 io->t2open.out.access      = io->t2open.in.open_mode;
193                 io->t2open.out.ftype       = 0;
194                 io->t2open.out.devstate    = 0;
195                 io->t2open.out.action      = io2->generic.out.create_action;
196                 io->t2open.out.file_id      = 0;
197                 break;
198
199         case RAW_OPEN_MKNEW:
200         case RAW_OPEN_CREATE:
201                 io->mknew.out.fnum = io2->generic.out.fnum;
202                 write_time = io->mknew.in.write_time;
203                 break;
204
205         case RAW_OPEN_CTEMP:
206                 io->ctemp.out.fnum  = io2->generic.out.fnum;
207                 io->ctemp.out.name = talloc_strdup(req, io2->generic.in.fname + 
208                                                    strlen(io->ctemp.in.directory) + 1);
209                 break;
210
211         default:
212                 return NT_STATUS_INVALID_LEVEL;
213         }
214
215         /* doing a secondary request async is more trouble than its
216            worth */
217         state = req->async_states->state;
218         req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
219
220         if (write_time != 0) {
221                 sf = talloc(req, union smb_setfileinfo);                        
222                 sf->generic.level            = RAW_SFILEINFO_STANDARD;
223                 sf->generic.file.fnum        = io2->generic.out.fnum;
224                 sf->standard.in.create_time = 0;
225                 sf->standard.in.write_time  = write_time;
226                 sf->standard.in.access_time = 0;
227                 status = ntvfs->ops->setfileinfo(ntvfs, req, sf);
228         }
229
230         if (set_size != 0) {
231                 sf = talloc(req, union smb_setfileinfo);                        
232                 sf->generic.level            = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
233                 sf->generic.file.fnum        = io2->generic.out.fnum;
234                 sf->end_of_file_info.in.size = set_size;
235                 status = ntvfs->ops->setfileinfo(ntvfs, req, sf);
236                 if (NT_STATUS_IS_OK(status)) {
237                         io->openx.out.size = io->openx.in.size;
238                 }
239         }
240
241         req->async_states->state = state;
242
243         return NT_STATUS_OK;
244 }
245
246 /*
247   the core of the mapping between openx style parameters and ntcreatex 
248   parameters
249 */
250 static NTSTATUS map_openx_open(uint16_t flags, uint16_t open_mode, 
251                                uint16_t open_func, const char *fname,
252                                union smb_open *io2)
253 {
254         if (flags & OPENX_FLAGS_REQUEST_OPLOCK) {
255                 io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_OPLOCK;
256         }
257         if (flags & OPENX_FLAGS_REQUEST_BATCH_OPLOCK) {
258                 io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
259         }
260
261         switch (open_mode & OPENX_MODE_ACCESS_MASK) {
262         case OPENX_MODE_ACCESS_READ:
263         case OPENX_MODE_ACCESS_EXEC:
264                 io2->generic.in.access_mask = SEC_RIGHTS_FILE_READ;
265                 break;
266         case OPENX_MODE_ACCESS_WRITE:
267                 io2->generic.in.access_mask = SEC_RIGHTS_FILE_WRITE;
268                 break;
269         case OPENX_MODE_ACCESS_RDWR:
270         case OPENX_MODE_ACCESS_FCB:
271                 io2->generic.in.access_mask = 
272                         SEC_RIGHTS_FILE_READ | 
273                         SEC_RIGHTS_FILE_WRITE;
274                 break;
275         default:
276                 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
277         }
278
279         switch (open_mode & OPENX_MODE_DENY_MASK) {
280         case OPENX_MODE_DENY_READ:
281                 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_WRITE;
282                 break;
283         case OPENX_MODE_DENY_WRITE:
284                 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
285                 break;
286         case OPENX_MODE_DENY_ALL:
287                 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
288                 break;
289         case OPENX_MODE_DENY_NONE:
290                 io2->generic.in.share_access = 
291                         NTCREATEX_SHARE_ACCESS_READ | 
292                         NTCREATEX_SHARE_ACCESS_WRITE;
293                 break;
294         case OPENX_MODE_DENY_DOS:
295                 /* DENY_DOS is quite strange - it depends on the filename! */
296                 io2->generic.in.create_options |= 
297                         NTCREATEX_OPTIONS_PRIVATE_DENY_DOS;
298                 if (is_exe_filename(fname)) {
299                         io2->generic.in.share_access = 
300                                 NTCREATEX_SHARE_ACCESS_READ | 
301                                 NTCREATEX_SHARE_ACCESS_WRITE;
302                 } else {
303                         if ((open_mode & OPENX_MODE_ACCESS_MASK) == OPENX_MODE_ACCESS_READ) {
304                                 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
305                         } else {
306                                 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
307                         }
308                 }
309                 break;
310         case OPENX_MODE_DENY_FCB:
311                 io2->generic.in.create_options |= NTCREATEX_OPTIONS_PRIVATE_DENY_FCB;
312                 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
313                 break;
314         default:
315                 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
316         }
317
318         switch (open_func) {
319         case (OPENX_OPEN_FUNC_OPEN):
320                 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN;
321                 break;
322         case (OPENX_OPEN_FUNC_TRUNC):
323                 io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
324                 break;
325         case (OPENX_OPEN_FUNC_FAIL | OPENX_OPEN_FUNC_CREATE):
326                 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
327                 break;
328         case (OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE):
329                 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
330                 break;
331         case (OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE):
332                 io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
333                 break;                  
334         default:
335                 /* this one is very strange */
336                 if ((open_mode & OPENX_MODE_ACCESS_MASK) == OPENX_MODE_ACCESS_EXEC) {
337                         io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
338                         break;
339                 }
340                 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
341         }
342
343         return NT_STATUS_OK;
344 }
345
346 /* 
347    NTVFS open generic to any mapper
348 */
349 _PUBLIC_ NTSTATUS ntvfs_map_open(struct smbsrv_request *req, union smb_open *io, 
350                                  struct ntvfs_module_context *ntvfs)
351 {
352         NTSTATUS status;
353         union smb_open *io2;
354
355         io2 = talloc_zero(req, union smb_open);
356         if (io2 == NULL) {
357                 return NT_STATUS_NO_MEMORY;
358         }
359
360         status = ntvfs_map_async_setup(req, ntvfs, io, io2, 
361                                        (second_stage_t)ntvfs_map_open_finish);
362         if (!NT_STATUS_IS_OK(status)) {
363                 return status;
364         }
365
366         io2->generic.level = RAW_OPEN_GENERIC;
367                 
368         switch (io->generic.level) {
369         case RAW_OPEN_OPENX:
370                 status = map_openx_open(io->openx.in.flags,
371                                         io->openx.in.open_mode, 
372                                         io->openx.in.open_func, 
373                                         io->openx.in.fname,
374                                         io2);
375                 if (!NT_STATUS_IS_OK(status)) {
376                         goto done;
377                 }
378                 
379                 io2->generic.in.file_attr = io->openx.in.file_attrs;
380                 io2->generic.in.fname = io->openx.in.fname;
381                 
382                 status = ntvfs->ops->openfile(ntvfs, req, io2);
383                 break;
384                 
385                 
386         case RAW_OPEN_OPEN:
387                 status = map_openx_open(0,
388                                         io->openold.in.open_mode, 
389                                         OPENX_OPEN_FUNC_OPEN, 
390                                         io->openold.in.fname,
391                                         io2);
392                 if (!NT_STATUS_IS_OK(status)) {
393                         goto done;
394                 }
395
396                 io2->generic.in.file_attr = io->openold.in.search_attrs;
397                 io2->generic.in.fname = io->openold.in.fname;
398
399                 status = ntvfs->ops->openfile(ntvfs, req, io2);
400                 break;
401
402         case RAW_OPEN_T2OPEN:
403                 io2->generic.level         = RAW_OPEN_NTTRANS_CREATE;
404
405                 if (io->t2open.in.open_func == 0) {
406                         status = NT_STATUS_OBJECT_NAME_COLLISION;
407                         goto done;
408                 }
409
410                 status = map_openx_open(io->t2open.in.flags,
411                                         io->t2open.in.open_mode, 
412                                         io->t2open.in.open_func, 
413                                         io->t2open.in.fname,
414                                         io2);
415                 if (!NT_STATUS_IS_OK(status)) {
416                         goto done;
417                 }
418
419                 io2->generic.in.file_attr        = io->t2open.in.file_attrs;
420                 io2->generic.in.fname            = io->t2open.in.fname;
421                 io2->generic.in.ea_list          = talloc(io2, struct smb_ea_list);
422                 io2->generic.in.ea_list->num_eas = io->t2open.in.num_eas;
423                 io2->generic.in.ea_list->eas     = io->t2open.in.eas;
424
425                 status = ntvfs->ops->openfile(ntvfs, req, io2);
426                 break;
427
428         case RAW_OPEN_MKNEW:
429                 io2->generic.in.file_attr = io->mknew.in.attrib;
430                 io2->generic.in.fname = io->mknew.in.fname;
431                 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
432                 io2->generic.in.access_mask = 
433                         SEC_RIGHTS_FILE_READ |
434                         SEC_RIGHTS_FILE_WRITE;
435                 io2->generic.in.share_access = 
436                         NTCREATEX_SHARE_ACCESS_READ | 
437                         NTCREATEX_SHARE_ACCESS_WRITE;
438                 status = ntvfs->ops->openfile(ntvfs, req, io2);
439                 break;
440
441         case RAW_OPEN_CREATE:
442                 io2->generic.in.file_attr = io->mknew.in.attrib;
443                 io2->generic.in.fname = io->mknew.in.fname;
444                 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
445                 io2->generic.in.access_mask = 
446                         SEC_RIGHTS_FILE_READ |
447                         SEC_RIGHTS_FILE_WRITE;
448                 io2->generic.in.share_access = 
449                         NTCREATEX_SHARE_ACCESS_READ | 
450                         NTCREATEX_SHARE_ACCESS_WRITE;
451                 status = ntvfs->ops->openfile(ntvfs, req, io2);
452                 break;
453
454         case RAW_OPEN_CTEMP:
455                 io2->generic.in.file_attr = io->ctemp.in.attrib;
456                 io2->generic.in.file_attr = 0;
457                 io2->generic.in.fname = 
458                         talloc_asprintf(io2, "%s\\SRV%s", 
459                                         io->ctemp.in.directory,
460                                         generate_random_str_list(io2, 5, "0123456789"));
461                 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
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->openfile(ntvfs, req, io2);
469                 break;
470
471         default:
472                 status = NT_STATUS_INVALID_LEVEL;
473                 break;
474         }
475 done:
476         return ntvfs_map_async_finish(req, status);
477 }
478
479
480 /* 
481    NTVFS fsinfo generic to any mapper
482 */
483 _PUBLIC_ NTSTATUS ntvfs_map_fsinfo(struct smbsrv_request *req, union smb_fsinfo *fs, 
484                                    struct ntvfs_module_context *ntvfs)
485 {
486         NTSTATUS status;
487         union smb_fsinfo *fs2;
488
489         fs2 = talloc(req, union smb_fsinfo);
490         if (fs2 == NULL) {
491                 return NT_STATUS_NO_MEMORY;
492         }
493
494         if (fs->generic.level == RAW_QFS_GENERIC) {
495                 return NT_STATUS_INVALID_LEVEL;
496         }
497         
498         /* only used by the simple backend, which 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 _PUBLIC_ 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(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(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 _PUBLIC_ 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(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         /* only used by the simple backend, which doesn't do async */
857         req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
858
859         status = ntvfs->ops->qfileinfo(ntvfs, req, info2);
860         if (!NT_STATUS_IS_OK(status)) {
861                 return status;
862         }
863         return ntvfs_map_fileinfo(req, info, info2);
864 }
865
866 /* 
867    NTVFS pathinfo generic to any mapper
868 */
869 _PUBLIC_ NTSTATUS ntvfs_map_qpathinfo(struct smbsrv_request *req, union smb_fileinfo *info, 
870                                       struct ntvfs_module_context *ntvfs)
871 {
872         NTSTATUS status;
873         union smb_fileinfo *info2;
874
875         info2 = talloc(req, union smb_fileinfo);
876         if (info2 == NULL) {
877                 return NT_STATUS_NO_MEMORY;
878         }
879
880         if (info->generic.level == RAW_FILEINFO_GENERIC) {
881                 return NT_STATUS_INVALID_LEVEL;
882         }
883
884         /* ask the backend for the generic info */
885         info2->generic.level = RAW_FILEINFO_GENERIC;
886         info2->generic.in.fname = info->generic.in.fname;
887
888         /* only used by the simple backend, which doesn't do async */
889         req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
890
891         status = ntvfs->ops->qpathinfo(ntvfs, req, info2);
892         if (!NT_STATUS_IS_OK(status)) {
893                 return status;
894         }
895         return ntvfs_map_fileinfo(req, info, info2);
896 }
897
898
899 /* 
900    NTVFS lock generic to any mapper
901 */
902 _PUBLIC_ NTSTATUS ntvfs_map_lock(struct smbsrv_request *req, union smb_lock *lck, 
903                                  struct ntvfs_module_context *ntvfs)
904 {
905         union smb_lock *lck2;
906         struct smb_lock_entry *locks;
907
908         lck2 = talloc(req, union smb_lock);
909         if (lck2 == NULL) {
910                 return NT_STATUS_NO_MEMORY;
911         }
912
913         locks = talloc_array(lck2, struct smb_lock_entry, 1);
914         if (locks == NULL) {
915                 return NT_STATUS_NO_MEMORY;
916         }
917
918         switch (lck->generic.level) {
919         case RAW_LOCK_LOCKX:
920                 return NT_STATUS_INVALID_LEVEL;
921
922         case RAW_LOCK_LOCK:
923                 lck2->generic.in.ulock_cnt = 0;
924                 lck2->generic.in.lock_cnt = 1;
925                 break;
926
927         case RAW_LOCK_UNLOCK:
928                 lck2->generic.in.ulock_cnt = 1;
929                 lck2->generic.in.lock_cnt = 0;
930                 break;
931         }
932
933         lck2->generic.level = RAW_LOCK_GENERIC;
934         lck2->generic.in.fnum = lck->lock.in.fnum;
935         lck2->generic.in.mode = 0;
936         lck2->generic.in.timeout = 0;
937         lck2->generic.in.locks = locks;
938         locks->pid = req->smbpid;
939         locks->offset = lck->lock.in.offset;
940         locks->count = lck->lock.in.count;
941
942         /* 
943          * we don't need to call ntvfs_map_async_setup() here,
944          * as lock() doesn't have any output fields
945          */
946
947         return ntvfs->ops->lock(ntvfs, req, lck2);
948 }
949
950
951 /* 
952    NTVFS write generic to any mapper
953 */
954 static NTSTATUS ntvfs_map_write_finish(struct smbsrv_request *req, 
955                                        struct ntvfs_module_context *ntvfs,
956                                        union smb_write *wr, 
957                                        union smb_write *wr2, 
958                                        NTSTATUS status)
959                                        
960 {
961         union smb_lock *lck;
962         union smb_close *cl;
963         uint_t state;
964
965         if (NT_STATUS_IS_ERR(status)) {
966                 return status;
967         }
968
969         switch (wr->generic.level) {
970         case RAW_WRITE_WRITE:
971                 wr->write.out.nwritten    = wr2->generic.out.nwritten;
972                 break;
973
974         case RAW_WRITE_WRITEUNLOCK:
975                 wr->writeunlock.out.nwritten = wr2->generic.out.nwritten;
976
977                 lck = talloc(wr2, union smb_lock);
978                 if (lck == NULL) {
979                         return NT_STATUS_NO_MEMORY;
980                 }
981
982                 lck->unlock.level      = RAW_LOCK_UNLOCK;
983                 lck->unlock.in.fnum    = wr->writeunlock.in.fnum;
984                 lck->unlock.in.count   = wr->writeunlock.in.count;
985                 lck->unlock.in.offset  = wr->writeunlock.in.offset;
986
987                 if (lck->unlock.in.count != 0) {
988                         /* do the lock sync for now */
989                         state = req->async_states->state;
990                         req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
991                         status = ntvfs->ops->lock(ntvfs, req, lck);
992                         req->async_states->state = state;
993                 }
994                 break;
995
996         case RAW_WRITE_WRITECLOSE:
997                 wr->writeclose.out.nwritten    = wr2->generic.out.nwritten;
998
999                 cl = talloc(wr2, union smb_close);
1000                 if (cl == NULL) {
1001                         return NT_STATUS_NO_MEMORY;
1002                 }
1003
1004                 cl->close.level           = RAW_CLOSE_CLOSE;
1005                 cl->close.in.fnum         = wr->writeclose.in.fnum;
1006                 cl->close.in.write_time   = wr->writeclose.in.mtime;
1007
1008                 if (wr2->generic.in.count != 0) {
1009                         /* do the close sync for now */
1010                         state = req->async_states->state;
1011                         req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1012                         status = ntvfs->ops->close(ntvfs, req, cl);
1013                         req->async_states->state = state;
1014                 }
1015                 break;
1016
1017         case RAW_WRITE_SPLWRITE:
1018                 break;
1019         default:
1020                 return NT_STATUS_INVALID_LEVEL;
1021         }
1022
1023         return status;
1024 }
1025
1026
1027 /* 
1028    NTVFS write generic to any mapper
1029 */
1030 _PUBLIC_ NTSTATUS ntvfs_map_write(struct smbsrv_request *req, union smb_write *wr, 
1031                                   struct ntvfs_module_context *ntvfs)
1032 {
1033         union smb_write *wr2;
1034         NTSTATUS status;
1035
1036         wr2 = talloc(req, union smb_write);
1037         if (wr2 == NULL) {
1038                 return NT_STATUS_NO_MEMORY;
1039         }
1040
1041         status = ntvfs_map_async_setup(req, ntvfs, wr, wr2, 
1042                                        (second_stage_t)ntvfs_map_write_finish);
1043         if (!NT_STATUS_IS_OK(status)) {
1044                 return status;
1045         }
1046
1047         wr2->writex.level = RAW_WRITE_GENERIC;
1048
1049         switch (wr->generic.level) {
1050         case RAW_WRITE_WRITEX:
1051                 status = NT_STATUS_INVALID_LEVEL;
1052                 break;
1053
1054         case RAW_WRITE_WRITE:
1055                 wr2->writex.in.fnum      = wr->write.in.fnum;
1056                 wr2->writex.in.offset    = wr->write.in.offset;
1057                 wr2->writex.in.wmode     = 0;
1058                 wr2->writex.in.remaining = wr->write.in.remaining;
1059                 wr2->writex.in.count     = wr->write.in.count;
1060                 wr2->writex.in.data      = wr->write.in.data;
1061                 status = ntvfs->ops->write(ntvfs, req, wr2);
1062                 break;
1063
1064         case RAW_WRITE_WRITEUNLOCK:
1065                 wr2->writex.in.fnum      = wr->writeunlock.in.fnum;
1066                 wr2->writex.in.offset    = wr->writeunlock.in.offset;
1067                 wr2->writex.in.wmode     = 0;
1068                 wr2->writex.in.remaining = wr->writeunlock.in.remaining;
1069                 wr2->writex.in.count     = wr->writeunlock.in.count;
1070                 wr2->writex.in.data      = wr->writeunlock.in.data;
1071                 status = ntvfs->ops->write(ntvfs, req, wr2);
1072                 break;
1073
1074         case RAW_WRITE_WRITECLOSE:
1075                 wr2->writex.in.fnum      = wr->writeclose.in.fnum;
1076                 wr2->writex.in.offset    = wr->writeclose.in.offset;
1077                 wr2->writex.in.wmode     = 0;
1078                 wr2->writex.in.remaining = 0;
1079                 wr2->writex.in.count     = wr->writeclose.in.count;
1080                 wr2->writex.in.data      = wr->writeclose.in.data;
1081                 status = ntvfs->ops->write(ntvfs, req, wr2);
1082                 break;
1083
1084         case RAW_WRITE_SPLWRITE:
1085                 wr2->writex.in.fnum      = wr->splwrite.in.fnum;
1086                 wr2->writex.in.offset    = 0;
1087                 wr2->writex.in.wmode     = 0;
1088                 wr2->writex.in.remaining = 0;
1089                 wr2->writex.in.count     = wr->splwrite.in.count;
1090                 wr2->writex.in.data      = wr->splwrite.in.data;
1091                 status = ntvfs->ops->write(ntvfs, req, wr2);
1092                 break;
1093         }
1094
1095         return ntvfs_map_async_finish(req, status);
1096 }
1097
1098
1099 /* 
1100    NTVFS read generic to any mapper - finish the out mapping
1101 */
1102 static NTSTATUS ntvfs_map_read_finish(struct smbsrv_request *req, 
1103                                       struct ntvfs_module_context *ntvfs, 
1104                                       union smb_read *rd, 
1105                                       union smb_read *rd2,
1106                                       NTSTATUS status)
1107 {
1108         switch (rd->generic.level) {
1109         case RAW_READ_READ:
1110                 rd->read.out.nread        = rd2->generic.out.nread;
1111                 break;
1112         case RAW_READ_READBRAW:
1113                 rd->readbraw.out.nread    = rd2->generic.out.nread;
1114                 break;
1115         case RAW_READ_LOCKREAD:
1116                 rd->lockread.out.nread = rd2->generic.out.nread;
1117                 break;
1118         default:
1119                 return NT_STATUS_INVALID_LEVEL;
1120         }
1121
1122         return status;
1123 }
1124
1125 /* 
1126    NTVFS read* to readx mapper
1127 */
1128 _PUBLIC_ NTSTATUS ntvfs_map_read(struct smbsrv_request *req, union smb_read *rd, 
1129                                  struct ntvfs_module_context *ntvfs)
1130 {
1131         union smb_read *rd2;
1132         union smb_lock *lck;
1133         NTSTATUS status;
1134         uint_t state;
1135
1136         rd2 = talloc(req, union smb_read);
1137         if (rd2 == NULL) {
1138                 return NT_STATUS_NO_MEMORY;
1139         }
1140
1141         status = ntvfs_map_async_setup(req, ntvfs, rd, rd2, 
1142                                        (second_stage_t)ntvfs_map_read_finish);
1143         if (!NT_STATUS_IS_OK(status)) {
1144                 return status;
1145         }
1146
1147         rd2->readx.level = RAW_READ_READX;
1148
1149         switch (rd->generic.level) {
1150         case RAW_READ_READX:
1151                 status = NT_STATUS_INVALID_LEVEL;
1152                 break;
1153
1154         case RAW_READ_READ:
1155                 rd2->readx.in.fnum      = rd->read.in.fnum;
1156                 rd2->readx.in.offset    = rd->read.in.offset;
1157                 rd2->readx.in.mincnt    = rd->read.in.count;
1158                 rd2->readx.in.maxcnt    = rd->read.in.count;
1159                 rd2->readx.in.remaining = rd->read.in.remaining;
1160                 rd2->readx.out.data     = rd->read.out.data;
1161                 status = ntvfs->ops->read(ntvfs, req, rd2);
1162                 break;
1163
1164         case RAW_READ_READBRAW:
1165                 rd2->readx.in.fnum      = rd->readbraw.in.fnum;
1166                 rd2->readx.in.offset    = rd->readbraw.in.offset;
1167                 rd2->readx.in.mincnt    = rd->readbraw.in.mincnt;
1168                 rd2->readx.in.maxcnt    = rd->readbraw.in.maxcnt;
1169                 rd2->readx.in.remaining = 0;
1170                 rd2->readx.out.data     = rd->readbraw.out.data;
1171                 status = ntvfs->ops->read(ntvfs, req, rd2);
1172                 break;
1173
1174         case RAW_READ_LOCKREAD:
1175                 /* do the initial lock sync for now */
1176                 state = req->async_states->state;
1177                 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1178
1179                 lck = talloc(rd2, union smb_lock);
1180                 if (lck == NULL) {
1181                         status = NT_STATUS_NO_MEMORY;
1182                         goto done;
1183                 }
1184                 lck->lock.level      = RAW_LOCK_LOCK;
1185                 lck->lock.in.fnum    = rd->lockread.in.fnum;
1186                 lck->lock.in.count   = rd->lockread.in.count;
1187                 lck->lock.in.offset  = rd->lockread.in.offset;
1188                 status = ntvfs->ops->lock(ntvfs, req, lck);
1189                 req->async_states->state = state;
1190
1191                 rd2->readx.in.fnum      = rd->lockread.in.fnum;
1192                 rd2->readx.in.offset    = rd->lockread.in.offset;
1193                 rd2->readx.in.mincnt    = rd->lockread.in.count;
1194                 rd2->readx.in.maxcnt    = rd->lockread.in.count;
1195                 rd2->readx.in.remaining = rd->lockread.in.remaining;
1196                 rd2->readx.out.data     = rd->lockread.out.data;
1197
1198                 if (NT_STATUS_IS_OK(status)) {
1199                         status = ntvfs->ops->read(ntvfs, req, rd2);
1200                 }
1201                 break;
1202         }
1203
1204 done:
1205         return ntvfs_map_async_finish(req, status);
1206 }
1207
1208
1209 /* 
1210    NTVFS close generic to any mapper
1211 */
1212 _PUBLIC_ NTSTATUS ntvfs_map_close(struct smbsrv_request *req, union smb_close *cl, 
1213                                   struct ntvfs_module_context *ntvfs)
1214 {
1215         union smb_close *cl2;
1216
1217         cl2 = talloc(req, union smb_close);
1218         if (cl2 == NULL) {
1219                 return NT_STATUS_NO_MEMORY;
1220         }
1221
1222         switch (cl->generic.level) {
1223         case RAW_CLOSE_CLOSE:
1224                 return NT_STATUS_INVALID_LEVEL;
1225
1226         case RAW_CLOSE_SPLCLOSE:
1227                 cl2->close.level   = RAW_CLOSE_CLOSE;
1228                 cl2->close.in.fnum = cl->splclose.in.fnum;
1229                 break;
1230         }
1231
1232         /* 
1233          * we don't need to call ntvfs_map_async_setup() here,
1234          * as close() doesn't have any output fields
1235          */
1236
1237         return ntvfs->ops->close(ntvfs, req, cl2);
1238 }