r15750: don't clear after setting
[ira/wip.git] / source4 / ntvfs / ntvfs_generic.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    NTVFS generic level mapping code
5
6    Copyright (C) Andrew Tridgell 2003-2004
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 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 "ntvfs/ntvfs.h"
36
37 /* a second stage function converts from the out parameters of the generic
38    call onto the out parameters of the specific call made */
39 typedef NTSTATUS (*second_stage_t)(struct ntvfs_module_context *,
40                                    struct ntvfs_request *,
41                                    void *, void *, NTSTATUS);
42
43 /* 
44    this structure holds the async state for pending mapped async calls
45 */
46 struct ntvfs_map_async {
47         struct ntvfs_module_context *ntvfs;
48         void *io, *io2;
49         second_stage_t fn;
50 };
51
52 /*
53   this is a async wrapper, called from the backend when it has completed
54   a function that it has decided to reply to in an async fashion
55 */
56 static void ntvfs_map_async_send(struct ntvfs_request *req)
57 {
58         struct ntvfs_map_async *m = req->async_states->private_data;
59
60         ntvfs_async_state_pop(req);
61
62         /* call the _finish function setup in ntvfs_map_async_setup() */
63         req->async_states->status = m->fn(m->ntvfs, req, m->io, m->io2, req->async_states->status);
64
65         /* call the send function from the next module up */
66         req->async_states->send_fn(req);
67 }
68
69 /*
70   prepare for calling a ntvfs backend with async support
71   io is the original call structure
72   io2 is the new call structure for the mapped call
73   fn is a second stage function for processing the out arguments
74 */
75 static NTSTATUS ntvfs_map_async_setup(struct ntvfs_module_context *ntvfs,
76                                       struct ntvfs_request *req,
77                                       void *io, void *io2,
78                                       second_stage_t fn)
79 {
80         struct ntvfs_map_async *m;
81         m = talloc(req, struct ntvfs_map_async);
82         if (m == NULL) {
83                 return NT_STATUS_NO_MEMORY;
84         }
85         m->ntvfs = ntvfs;
86         m->io = io;
87         m->io2 = io2;
88         m->fn = fn;
89         return ntvfs_async_state_push(ntvfs, req, m, ntvfs_map_async_send);
90 }
91
92 /*
93   called when first stage processing is complete. 
94 */      
95 static NTSTATUS ntvfs_map_async_finish(struct ntvfs_request *req, NTSTATUS status)
96 {
97         struct ntvfs_map_async *m;
98
99         /* if the backend has decided to reply in an async fashion then
100            we don't need to do any work here */
101         if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
102                 return status;
103         }
104
105         /* the backend is replying immediately. call the 2nd stage function after popping our local
106            async state */
107         m = req->async_states->private_data;
108
109         ntvfs_async_state_pop(req);
110
111         return m->fn(m->ntvfs, req, m->io, m->io2, status);
112 }
113
114 /*
115   see if a filename ends in EXE COM DLL or SYM. This is needed for the
116   DENY_DOS mapping for OpenX
117 */
118 BOOL is_exe_filename(const char *fname)
119 {
120         char *p;
121         p = strrchr(fname, '.');
122         if (!p) {
123                 return False;
124         }
125         p++;
126         if (strcasecmp(p, "EXE") == 0 ||
127             strcasecmp(p, "COM") == 0 ||
128             strcasecmp(p, "DLL") == 0 ||
129             strcasecmp(p, "SYM") == 0) {
130                 return True;
131         }
132         return False;
133 }
134
135
136 /* 
137    NTVFS openx to ntcreatex mapper
138 */
139 static NTSTATUS ntvfs_map_open_finish(struct ntvfs_module_context *ntvfs,
140                                       struct ntvfs_request *req, 
141                                       union smb_open *io, 
142                                       union smb_open *io2, 
143                                       NTSTATUS status)
144 {
145         time_t write_time = 0;
146         uint32_t set_size = 0;
147         union smb_setfileinfo *sf;
148         uint_t state;
149
150         if (!NT_STATUS_IS_OK(status)) {
151                 return status;
152         }
153
154         switch (io->generic.level) {
155         case RAW_OPEN_OPEN:
156                 io->openold.out.file.ntvfs = io2->generic.out.file.ntvfs;
157                 io->openold.out.attrib     = io2->generic.out.attrib;
158                 io->openold.out.write_time = nt_time_to_unix(io2->generic.out.write_time);
159                 io->openold.out.size       = io2->generic.out.size;
160                 io->openold.out.rmode      = io->openold.in.open_mode;
161                 break;
162
163         case RAW_OPEN_OPENX:
164                 io->openx.out.file.ntvfs  = io2->generic.out.file.ntvfs;
165                 io->openx.out.attrib      = io2->generic.out.attrib;
166                 io->openx.out.write_time  = nt_time_to_unix(io2->generic.out.write_time);
167                 io->openx.out.size        = io2->generic.out.size;
168                 io->openx.out.access      = (io->openx.in.open_mode & OPENX_MODE_ACCESS_MASK);
169                 io->openx.out.ftype       = 0;
170                 io->openx.out.devstate    = 0;
171                 io->openx.out.action      = io2->generic.out.create_action;
172                 io->openx.out.unique_fid  = 0;
173                 io->openx.out.access_mask = SEC_STD_ALL;
174                 io->openx.out.unknown     = 0;
175                 
176                 /* we need to extend the file to the requested size if
177                    it was newly created */
178                 if (io2->generic.out.create_action == NTCREATEX_ACTION_CREATED) {
179                         set_size = io->openx.in.size;
180                 }
181                 break;
182
183         case RAW_OPEN_T2OPEN:
184                 io->t2open.out.file.ntvfs  = io2->generic.out.file.ntvfs;
185                 io->t2open.out.attrib      = io2->generic.out.attrib;
186                 io->t2open.out.write_time  = nt_time_to_unix(io2->generic.out.write_time);
187                 io->t2open.out.size        = io2->generic.out.size;
188                 io->t2open.out.access      = io->t2open.in.open_mode;
189                 io->t2open.out.ftype       = 0;
190                 io->t2open.out.devstate    = 0;
191                 io->t2open.out.action      = io2->generic.out.create_action;
192                 io->t2open.out.file_id      = 0;
193                 break;
194
195         case RAW_OPEN_MKNEW:
196         case RAW_OPEN_CREATE:
197                 io->mknew.out.file.ntvfs= io2->generic.out.file.ntvfs;
198                 write_time              = io->mknew.in.write_time;
199                 break;
200
201         case RAW_OPEN_CTEMP:
202                 io->ctemp.out.file.ntvfs= io2->generic.out.file.ntvfs;
203                 io->ctemp.out.name      = talloc_strdup(req, io2->generic.in.fname + 
204                                                         strlen(io->ctemp.in.directory) + 1);
205                 NT_STATUS_HAVE_NO_MEMORY(io->ctemp.out.name);
206                 break;
207
208         default:
209                 return NT_STATUS_INVALID_LEVEL;
210         }
211
212         /* doing a secondary request async is more trouble than its
213            worth */
214         state = req->async_states->state;
215         req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
216
217         if (write_time != 0) {
218                 sf = talloc(req, union smb_setfileinfo);
219                 NT_STATUS_HAVE_NO_MEMORY(sf);
220                 sf->generic.level           = RAW_SFILEINFO_STANDARD;
221                 sf->generic.in.file.ntvfs   = io2->generic.out.file.ntvfs;
222                 sf->standard.in.create_time = 0;
223                 sf->standard.in.write_time  = write_time;
224                 sf->standard.in.access_time = 0;
225                 status = ntvfs->ops->setfileinfo(ntvfs, req, sf);
226         }
227
228         if (set_size != 0) {
229                 sf = talloc(req, union smb_setfileinfo);                        
230                 NT_STATUS_HAVE_NO_MEMORY(sf);
231                 sf->generic.level            = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
232                 sf->generic.in.file.ntvfs    = io2->generic.out.file.ntvfs;
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         case OPENX_MODE_ACCESS_EXEC:
263                 io2->generic.in.access_mask = SEC_RIGHTS_FILE_READ;
264                 break;
265         case OPENX_MODE_ACCESS_WRITE:
266                 io2->generic.in.access_mask = SEC_RIGHTS_FILE_WRITE;
267                 break;
268         case OPENX_MODE_ACCESS_RDWR:
269         case OPENX_MODE_ACCESS_FCB:
270                 io2->generic.in.access_mask = 
271                         SEC_RIGHTS_FILE_READ | 
272                         SEC_RIGHTS_FILE_WRITE;
273                 break;
274         default:
275                 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
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_DOS(ERRDOS, ERRbadaccess);
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_DOS(ERRDOS, ERRbadaccess);
340         }
341
342         return NT_STATUS_OK;
343 }
344
345 /* 
346    NTVFS open generic to any mapper
347 */
348 _PUBLIC_ NTSTATUS ntvfs_map_open(struct ntvfs_module_context *ntvfs,
349                                  struct ntvfs_request *req,
350                                  union smb_open *io)
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(ntvfs, req,
361                                        io, io2, 
362                                        (second_stage_t)ntvfs_map_open_finish);
363         if (!NT_STATUS_IS_OK(status)) {
364                 return status;
365         }
366
367         io2->generic.level = RAW_OPEN_GENERIC;
368                 
369         switch (io->generic.level) {
370         case RAW_OPEN_OPENX:
371                 status = map_openx_open(io->openx.in.flags,
372                                         io->openx.in.open_mode, 
373                                         io->openx.in.open_func, 
374                                         io->openx.in.fname,
375                                         io2);
376                 if (!NT_STATUS_IS_OK(status)) {
377                         goto done;
378                 }
379                 
380                 io2->generic.in.file_attr = io->openx.in.file_attrs;
381                 io2->generic.in.fname = io->openx.in.fname;
382                 
383                 status = ntvfs->ops->open(ntvfs, req, io2);
384                 break;
385                 
386                 
387         case RAW_OPEN_OPEN:
388                 status = map_openx_open(0,
389                                         io->openold.in.open_mode, 
390                                         OPENX_OPEN_FUNC_OPEN, 
391                                         io->openold.in.fname,
392                                         io2);
393                 if (!NT_STATUS_IS_OK(status)) {
394                         goto done;
395                 }
396
397                 io2->generic.in.file_attr = io->openold.in.search_attrs;
398                 io2->generic.in.fname = io->openold.in.fname;
399
400                 status = ntvfs->ops->open(ntvfs, req, io2);
401                 break;
402
403         case RAW_OPEN_T2OPEN:
404                 io2->generic.level         = RAW_OPEN_NTTRANS_CREATE;
405
406                 if (io->t2open.in.open_func == 0) {
407                         status = NT_STATUS_OBJECT_NAME_COLLISION;
408                         goto done;
409                 }
410
411                 status = map_openx_open(io->t2open.in.flags,
412                                         io->t2open.in.open_mode, 
413                                         io->t2open.in.open_func, 
414                                         io->t2open.in.fname,
415                                         io2);
416                 if (!NT_STATUS_IS_OK(status)) {
417                         goto done;
418                 }
419
420                 io2->generic.in.file_attr        = io->t2open.in.file_attrs;
421                 io2->generic.in.fname            = io->t2open.in.fname;
422                 io2->generic.in.ea_list          = talloc(io2, struct smb_ea_list);
423                 io2->generic.in.ea_list->num_eas = io->t2open.in.num_eas;
424                 io2->generic.in.ea_list->eas     = io->t2open.in.eas;
425
426                 status = ntvfs->ops->open(ntvfs, req, io2);
427                 break;
428
429         case RAW_OPEN_MKNEW:
430                 io2->generic.in.file_attr = io->mknew.in.attrib;
431                 io2->generic.in.fname = io->mknew.in.fname;
432                 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
433                 io2->generic.in.access_mask = 
434                         SEC_RIGHTS_FILE_READ |
435                         SEC_RIGHTS_FILE_WRITE;
436                 io2->generic.in.share_access = 
437                         NTCREATEX_SHARE_ACCESS_READ | 
438                         NTCREATEX_SHARE_ACCESS_WRITE;
439                 status = ntvfs->ops->open(ntvfs, req, io2);
440                 break;
441
442         case RAW_OPEN_CREATE:
443                 io2->generic.in.file_attr = io->mknew.in.attrib;
444                 io2->generic.in.fname = io->mknew.in.fname;
445                 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
446                 io2->generic.in.access_mask = 
447                         SEC_RIGHTS_FILE_READ |
448                         SEC_RIGHTS_FILE_WRITE;
449                 io2->generic.in.share_access = 
450                         NTCREATEX_SHARE_ACCESS_READ | 
451                         NTCREATEX_SHARE_ACCESS_WRITE;
452                 status = ntvfs->ops->open(ntvfs, req, io2);
453                 break;
454
455         case RAW_OPEN_CTEMP:
456                 io2->generic.in.file_attr = io->ctemp.in.attrib;
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->open(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 ntvfs_module_context *ntvfs,
484                                    struct ntvfs_request *req,
485                                    union smb_fsinfo *fs)
486 {
487         NTSTATUS status;
488         union smb_fsinfo *fs2;
489
490         fs2 = talloc(req, union smb_fsinfo);
491         if (fs2 == NULL) {
492                 return NT_STATUS_NO_MEMORY;
493         }
494
495         if (fs->generic.level == RAW_QFS_GENERIC) {
496                 return NT_STATUS_INVALID_LEVEL;
497         }
498         
499         /* only used by the simple backend, which doesn't do async */
500         req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
501
502         /* ask the backend for the generic info */
503         fs2->generic.level = RAW_QFS_GENERIC;
504
505         status = ntvfs->ops->fsinfo(ntvfs, req, fs2);
506         if (!NT_STATUS_IS_OK(status)) {
507                 return status;
508         }
509
510         /* and convert it to the required level */
511         switch (fs->generic.level) {
512         case RAW_QFS_GENERIC:
513                 return NT_STATUS_INVALID_LEVEL;
514
515         case RAW_QFS_DSKATTR: {
516                 /* map from generic to DSKATTR */
517                 uint_t bpunit = 64;
518
519                 /* we need to scale the sizes to fit */
520                 for (bpunit=64; bpunit<0x10000; bpunit *= 2) {
521                         if (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size < bpunit * 512 * 65535.0) {
522                                 break;
523                         }
524                 }
525
526                 fs->dskattr.out.blocks_per_unit = bpunit;
527                 fs->dskattr.out.block_size = 512;
528                 fs->dskattr.out.units_total = 
529                         (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size) / (bpunit * 512);
530                 fs->dskattr.out.units_free  = 
531                         (fs2->generic.out.blocks_free  * (double)fs2->generic.out.block_size) / (bpunit * 512);
532
533                 /* we must return a maximum of 2G to old DOS systems, or they get very confused */
534                 if (bpunit > 64 && req->ctx->protocol <= PROTOCOL_LANMAN2) {
535                         fs->dskattr.out.blocks_per_unit = 64;
536                         fs->dskattr.out.units_total = 0xFFFF;
537                         fs->dskattr.out.units_free = 0xFFFF;
538                 }
539                 return NT_STATUS_OK;
540         }
541
542         case RAW_QFS_ALLOCATION:
543                 fs->allocation.out.fs_id = fs2->generic.out.fs_id;
544                 fs->allocation.out.total_alloc_units = fs2->generic.out.blocks_total;
545                 fs->allocation.out.avail_alloc_units = fs2->generic.out.blocks_free;
546                 fs->allocation.out.sectors_per_unit = 1;
547                 fs->allocation.out.bytes_per_sector = fs2->generic.out.block_size;
548                 return NT_STATUS_OK;
549
550         case RAW_QFS_VOLUME:
551                 fs->volume.out.serial_number = fs2->generic.out.serial_number;
552                 fs->volume.out.volume_name.s = fs2->generic.out.volume_name;
553                 return NT_STATUS_OK;
554
555         case RAW_QFS_VOLUME_INFO:
556         case RAW_QFS_VOLUME_INFORMATION:
557                 fs->volume_info.out.create_time = fs2->generic.out.create_time;
558                 fs->volume_info.out.serial_number = fs2->generic.out.serial_number;
559                 fs->volume_info.out.volume_name.s = fs2->generic.out.volume_name;
560                 return NT_STATUS_OK;
561
562         case RAW_QFS_SIZE_INFO:
563         case RAW_QFS_SIZE_INFORMATION:
564                 fs->size_info.out.total_alloc_units = fs2->generic.out.blocks_total;
565                 fs->size_info.out.avail_alloc_units = fs2->generic.out.blocks_free;
566                 fs->size_info.out.sectors_per_unit = 1;
567                 fs->size_info.out.bytes_per_sector = fs2->generic.out.block_size;
568                 return NT_STATUS_OK;
569
570         case RAW_QFS_DEVICE_INFO:
571         case RAW_QFS_DEVICE_INFORMATION:
572                 fs->device_info.out.device_type = fs2->generic.out.device_type;
573                 fs->device_info.out.characteristics = fs2->generic.out.device_characteristics;
574                 return NT_STATUS_OK;
575
576         case RAW_QFS_ATTRIBUTE_INFO:
577         case RAW_QFS_ATTRIBUTE_INFORMATION:
578                 fs->attribute_info.out.fs_attr = fs2->generic.out.fs_attr;
579                 fs->attribute_info.out.max_file_component_length = fs2->generic.out.max_file_component_length;
580                 fs->attribute_info.out.fs_type.s = fs2->generic.out.fs_type;
581                 return NT_STATUS_OK;
582
583         case RAW_QFS_QUOTA_INFORMATION:
584                 ZERO_STRUCT(fs->quota_information.out.unknown);
585                 fs->quota_information.out.quota_soft = fs2->generic.out.quota_soft;
586                 fs->quota_information.out.quota_hard = fs2->generic.out.quota_hard;
587                 fs->quota_information.out.quota_flags = fs2->generic.out.quota_flags;
588                 return NT_STATUS_OK;
589
590         case RAW_QFS_FULL_SIZE_INFORMATION:
591                 fs->full_size_information.out.total_alloc_units = fs2->generic.out.blocks_total;
592                 fs->full_size_information.out.call_avail_alloc_units = fs2->generic.out.blocks_free;
593                 fs->full_size_information.out.actual_avail_alloc_units = fs2->generic.out.blocks_free;
594                 fs->full_size_information.out.sectors_per_unit = 1;
595                 fs->full_size_information.out.bytes_per_sector = fs2->generic.out.block_size;
596                 return NT_STATUS_OK;
597
598         case RAW_QFS_OBJECTID_INFORMATION:
599                 fs->objectid_information.out.guid = fs2->generic.out.guid;
600                 ZERO_STRUCT(fs->objectid_information.out.unknown);
601                 return NT_STATUS_OK;
602         }
603
604
605         return NT_STATUS_INVALID_LEVEL;
606 }
607
608
609 /* 
610    NTVFS fileinfo generic to any mapper
611 */
612 _PUBLIC_ NTSTATUS ntvfs_map_fileinfo(TALLOC_CTX *mem_ctx,
613                                      union smb_fileinfo *info, 
614                                      union smb_fileinfo *info2)
615 {
616         int i;
617         /* and convert it to the required level using results in info2 */
618         switch (info->generic.level) {
619                 case RAW_FILEINFO_GENERIC:
620                 return NT_STATUS_INVALID_LEVEL;
621         case RAW_FILEINFO_GETATTR:
622                 info->getattr.out.attrib = info2->generic.out.attrib & 0xff;
623                 info->getattr.out.size = info2->generic.out.size;
624                 info->getattr.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
625                 return NT_STATUS_OK;
626                 
627         case RAW_FILEINFO_GETATTRE:
628                 info->getattre.out.attrib = info2->generic.out.attrib;
629                 info->getattre.out.size = info2->generic.out.size;
630                 info->getattre.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
631                 info->getattre.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
632                 info->getattre.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
633                 info->getattre.out.alloc_size = info2->generic.out.alloc_size;
634                 return NT_STATUS_OK;
635                 
636         case RAW_FILEINFO_NETWORK_OPEN_INFORMATION:
637                 info->network_open_information.out.create_time = info2->generic.out.create_time;
638                 info->network_open_information.out.access_time = info2->generic.out.access_time;
639                 info->network_open_information.out.write_time =  info2->generic.out.write_time;
640                 info->network_open_information.out.change_time = info2->generic.out.change_time;
641                 info->network_open_information.out.alloc_size = info2->generic.out.alloc_size;
642                 info->network_open_information.out.size = info2->generic.out.size;
643                 info->network_open_information.out.attrib = info2->generic.out.attrib;
644                 return NT_STATUS_OK;
645
646         case RAW_FILEINFO_ALL_INFO:
647         case RAW_FILEINFO_ALL_INFORMATION:
648                 info->all_info.out.create_time = info2->generic.out.create_time;
649                 info->all_info.out.access_time = info2->generic.out.access_time;
650                 info->all_info.out.write_time =  info2->generic.out.write_time;
651                 info->all_info.out.change_time = info2->generic.out.change_time;
652                 info->all_info.out.attrib = info2->generic.out.attrib;
653                 info->all_info.out.alloc_size = info2->generic.out.alloc_size;
654                 info->all_info.out.size = info2->generic.out.size;
655                 info->all_info.out.nlink = info2->generic.out.nlink;
656                 info->all_info.out.delete_pending = info2->generic.out.delete_pending;
657                 info->all_info.out.directory = info2->generic.out.directory;
658                 info->all_info.out.ea_size = info2->generic.out.ea_size;
659                 info->all_info.out.fname.s = info2->generic.out.fname.s;
660                 info->all_info.out.fname.private_length = info2->generic.out.fname.private_length;
661                 return NT_STATUS_OK;
662
663         case RAW_FILEINFO_BASIC_INFO:
664         case RAW_FILEINFO_BASIC_INFORMATION:
665                 info->basic_info.out.create_time = info2->generic.out.create_time;
666                 info->basic_info.out.access_time = info2->generic.out.access_time;
667                 info->basic_info.out.write_time = info2->generic.out.write_time;
668                 info->basic_info.out.change_time = info2->generic.out.change_time;
669                 info->basic_info.out.attrib = info2->generic.out.attrib;
670                 return NT_STATUS_OK;
671
672         case RAW_FILEINFO_STANDARD:
673                 info->standard.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
674                 info->standard.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
675                 info->standard.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
676                 info->standard.out.size = info2->generic.out.size;
677                 info->standard.out.alloc_size = info2->generic.out.alloc_size;
678                 info->standard.out.attrib = info2->generic.out.attrib;
679                 return NT_STATUS_OK;
680
681         case RAW_FILEINFO_EA_SIZE:
682                 info->ea_size.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
683                 info->ea_size.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
684                 info->ea_size.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
685                 info->ea_size.out.size = info2->generic.out.size;
686                 info->ea_size.out.alloc_size = info2->generic.out.alloc_size;
687                 info->ea_size.out.attrib = info2->generic.out.attrib;
688                 info->ea_size.out.ea_size = info2->generic.out.ea_size;
689                 return NT_STATUS_OK;
690
691         case RAW_FILEINFO_STANDARD_INFO:
692         case RAW_FILEINFO_STANDARD_INFORMATION:
693                 info->standard_info.out.alloc_size = info2->generic.out.alloc_size;
694                 info->standard_info.out.size = info2->generic.out.size;
695                 info->standard_info.out.nlink = info2->generic.out.nlink;
696                 info->standard_info.out.delete_pending = info2->generic.out.delete_pending;
697                 info->standard_info.out.directory = info2->generic.out.directory;
698                 return NT_STATUS_OK;
699
700         case RAW_FILEINFO_INTERNAL_INFORMATION:
701                 info->internal_information.out.file_id = info2->generic.out.file_id;
702                 return NT_STATUS_OK;
703
704         case RAW_FILEINFO_EA_INFO:
705         case RAW_FILEINFO_EA_INFORMATION:
706                 info->ea_info.out.ea_size = info2->generic.out.ea_size;
707                 return NT_STATUS_OK;
708
709         case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION:
710                 info->attribute_tag_information.out.attrib = info2->generic.out.attrib;
711                 info->attribute_tag_information.out.reparse_tag = info2->generic.out.reparse_tag;
712                 return NT_STATUS_OK;
713
714         case RAW_FILEINFO_STREAM_INFO:
715         case RAW_FILEINFO_STREAM_INFORMATION:
716                 info->stream_info.out.num_streams = info2->generic.out.num_streams;
717                 if (info->stream_info.out.num_streams > 0) {
718                         info->stream_info.out.streams = 
719                                 talloc_array(mem_ctx, 
720                                                struct stream_struct,
721                                                info->stream_info.out.num_streams);
722                         if (!info->stream_info.out.streams) {
723                                 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d streams\n",
724                                         info->stream_info.out.num_streams));
725                                 return NT_STATUS_NO_MEMORY;
726                         }
727                         for (i=0; i < info->stream_info.out.num_streams; i++) {
728                                 info->stream_info.out.streams[i] = info2->generic.out.streams[i];
729                                 info->stream_info.out.streams[i].stream_name.s = 
730                                         talloc_strdup(info->stream_info.out.streams,
731                                                       info2->generic.out.streams[i].stream_name.s);
732                                 if (!info->stream_info.out.streams[i].stream_name.s) {
733                                         DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
734                                         return NT_STATUS_NO_MEMORY;
735                                 }
736                         }
737                 }
738                 return NT_STATUS_OK;
739
740         case RAW_FILEINFO_NAME_INFO:
741         case RAW_FILEINFO_NAME_INFORMATION:
742                 info->name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.fname.s);
743                 NT_STATUS_HAVE_NO_MEMORY(info->name_info.out.fname.s);
744                 info->name_info.out.fname.private_length = info2->generic.out.fname.private_length;
745                 return NT_STATUS_OK;
746                 
747         case RAW_FILEINFO_ALT_NAME_INFO:
748         case RAW_FILEINFO_ALT_NAME_INFORMATION:
749                 info->alt_name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.alt_fname.s);
750                 NT_STATUS_HAVE_NO_MEMORY(info->alt_name_info.out.fname.s);
751                 info->alt_name_info.out.fname.private_length = info2->generic.out.alt_fname.private_length;
752                 return NT_STATUS_OK;
753         
754         case RAW_FILEINFO_POSITION_INFORMATION:
755                 info->position_information.out.position = info2->generic.out.position;
756                 return NT_STATUS_OK;
757         
758         case RAW_FILEINFO_ALL_EAS:
759                 info->all_eas.out.num_eas = info2->generic.out.num_eas;
760                 if (info->all_eas.out.num_eas > 0) {
761                         info->all_eas.out.eas = talloc_array(mem_ctx, 
762                                                                struct ea_struct,
763                                                                info->all_eas.out.num_eas);
764                         if (!info->all_eas.out.eas) {
765                                 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d eas\n",
766                                         info->all_eas.out.num_eas));
767                                 return NT_STATUS_NO_MEMORY;
768                         }
769                         for (i = 0; i < info->all_eas.out.num_eas; i++) {
770                                 info->all_eas.out.eas[i] = info2->generic.out.eas[i];
771                                 info->all_eas.out.eas[i].name.s = 
772                                         talloc_strdup(info->all_eas.out.eas,
773                                                       info2->generic.out.eas[i].name.s);
774                                 if (!info->all_eas.out.eas[i].name.s) {
775                                         DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
776                                         return NT_STATUS_NO_MEMORY;
777                                 }
778                                 info->all_eas.out.eas[i].value.data = 
779                                         talloc_memdup(info->all_eas.out.eas,
780                                                 info2->generic.out.eas[i].value.data,
781                                                 info2->generic.out.eas[i].value.length);
782                                 if (!info->all_eas.out.eas[i].value.data) {
783                                         DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
784                                         return NT_STATUS_NO_MEMORY;
785                                 }
786                         }
787                 }
788                 return NT_STATUS_OK;
789                 
790         case RAW_FILEINFO_IS_NAME_VALID:
791                 return NT_STATUS_OK;
792                 
793         case RAW_FILEINFO_COMPRESSION_INFO:
794         case RAW_FILEINFO_COMPRESSION_INFORMATION:
795                 info->compression_info.out.compressed_size = info2->generic.out.compressed_size;
796                 info->compression_info.out.format = info2->generic.out.format;
797                 info->compression_info.out.unit_shift = info2->generic.out.unit_shift;
798                 info->compression_info.out.chunk_shift = info2->generic.out.chunk_shift;
799                 info->compression_info.out.cluster_shift = info2->generic.out.cluster_shift;
800                 return NT_STATUS_OK;
801                 
802         case RAW_FILEINFO_ACCESS_INFORMATION:
803                 info->access_information.out.access_flags = info2->generic.out.access_flags;
804                 return NT_STATUS_OK;
805                 
806         case RAW_FILEINFO_MODE_INFORMATION:
807                 info->mode_information.out.mode = info2->generic.out.mode;
808                 return NT_STATUS_OK;
809                 
810         case RAW_FILEINFO_ALIGNMENT_INFORMATION:
811                 info->alignment_information.out.alignment_requirement =
812                         info2->generic.out.alignment_requirement;
813                 return NT_STATUS_OK;
814 #if 0   
815         case RAW_FILEINFO_UNIX_BASIC:
816                 info->unix_basic_info.out.end_of_file = info2->generic.out.end_of_file;
817                 info->unix_basic_info.out.num_bytes = info2->generic.out.size;
818                 info->unix_basic_info.out.status_change_time = info2->generic.out.change_time;
819                 info->unix_basic_info.out.access_time = info2->generic.out.access_time;
820                 info->unix_basic_info.out.change_time = info2->generic.out.change_time;
821                 info->unix_basic_info.out.uid = info2->generic.out.uid;
822                 info->unix_basic_info.out.gid = info2->generic.out.gid;
823                 info->unix_basic_info.out.file_type = info2->generic.out.file_type;
824                 info->unix_basic_info.out.dev_major = info2->generic.out.device;
825                 info->unix_basic_info.out.dev_minor = info2->generic.out.device;
826                 info->unix_basic_info.out.unique_id = info2->generic.out.inode;
827                 info->unix_basic_info.out.permissions = info2->generic.out.permissions;
828                 info->unix_basic_info.out.nlink = info2->generic.out.nlink;
829                 return NT_STATUS_OK;
830                 
831         case RAW_FILEINFO_UNIX_LINK:
832                 info->unix_link_info.out.link_dest = info2->generic.out.link_dest;
833                 return NT_STATUS_OK;
834 #endif
835         }
836
837         return NT_STATUS_INVALID_LEVEL;
838 }
839
840 /* 
841    NTVFS fileinfo generic to any mapper
842 */
843 _PUBLIC_ NTSTATUS ntvfs_map_qfileinfo(struct ntvfs_module_context *ntvfs,
844                                       struct ntvfs_request *req,
845                                       union smb_fileinfo *info)
846 {
847         NTSTATUS status;
848         union smb_fileinfo *info2;
849
850         info2 = talloc(req, union smb_fileinfo);
851         if (info2 == NULL) {
852                 return NT_STATUS_NO_MEMORY;
853         }
854
855         if (info->generic.level == RAW_FILEINFO_GENERIC) {
856                 return NT_STATUS_INVALID_LEVEL;
857         }
858
859         /* ask the backend for the generic info */
860         info2->generic.level = RAW_FILEINFO_GENERIC;
861         info2->generic.in.file.ntvfs= info->generic.in.file.ntvfs;
862
863         /* only used by the simple backend, which doesn't do async */
864         req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
865
866         status = ntvfs->ops->qfileinfo(ntvfs, req, info2);
867         if (!NT_STATUS_IS_OK(status)) {
868                 return status;
869         }
870         return ntvfs_map_fileinfo(req, info, info2);
871 }
872
873 /* 
874    NTVFS pathinfo generic to any mapper
875 */
876 _PUBLIC_ NTSTATUS ntvfs_map_qpathinfo(struct ntvfs_module_context *ntvfs,
877                                       struct ntvfs_request *req,
878                                       union smb_fileinfo *info)
879 {
880         NTSTATUS status;
881         union smb_fileinfo *info2;
882
883         info2 = talloc(req, union smb_fileinfo);
884         if (info2 == NULL) {
885                 return NT_STATUS_NO_MEMORY;
886         }
887
888         if (info->generic.level == RAW_FILEINFO_GENERIC) {
889                 return NT_STATUS_INVALID_LEVEL;
890         }
891
892         /* ask the backend for the generic info */
893         info2->generic.level            = RAW_FILEINFO_GENERIC;
894         info2->generic.in.file.path     = info->generic.in.file.path;
895
896         /* only used by the simple backend, which doesn't do async */
897         req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
898
899         status = ntvfs->ops->qpathinfo(ntvfs, req, info2);
900         if (!NT_STATUS_IS_OK(status)) {
901                 return status;
902         }
903         return ntvfs_map_fileinfo(req, info, info2);
904 }
905
906
907 /* 
908    NTVFS lock generic to any mapper
909 */
910 _PUBLIC_ NTSTATUS ntvfs_map_lock(struct ntvfs_module_context *ntvfs,
911                                  struct ntvfs_request *req,
912                                  union smb_lock *lck)
913 {
914         union smb_lock *lck2;
915         struct smb_lock_entry *locks;
916
917         lck2 = talloc(req, union smb_lock);
918         if (lck2 == NULL) {
919                 return NT_STATUS_NO_MEMORY;
920         }
921
922         locks = talloc_array(lck2, struct smb_lock_entry, 1);
923         if (locks == NULL) {
924                 return NT_STATUS_NO_MEMORY;
925         }
926
927         switch (lck->generic.level) {
928         case RAW_LOCK_LOCKX:
929                 return NT_STATUS_INVALID_LEVEL;
930
931         case RAW_LOCK_LOCK:
932                 lck2->generic.in.ulock_cnt = 0;
933                 lck2->generic.in.lock_cnt = 1;
934                 break;
935
936         case RAW_LOCK_UNLOCK:
937                 lck2->generic.in.ulock_cnt = 1;
938                 lck2->generic.in.lock_cnt = 0;
939                 break;
940         }
941
942         lck2->generic.level = RAW_LOCK_GENERIC;
943         lck2->generic.in.file.ntvfs= lck->lock.in.file.ntvfs;
944         lck2->generic.in.mode = 0;
945         lck2->generic.in.timeout = 0;
946         lck2->generic.in.locks = locks;
947         locks->pid = req->smbpid;
948         locks->offset = lck->lock.in.offset;
949         locks->count = lck->lock.in.count;
950
951         /* 
952          * we don't need to call ntvfs_map_async_setup() here,
953          * as lock() doesn't have any output fields
954          */
955
956         return ntvfs->ops->lock(ntvfs, req, lck2);
957 }
958
959
960 /* 
961    NTVFS write generic to any mapper
962 */
963 static NTSTATUS ntvfs_map_write_finish(struct ntvfs_module_context *ntvfs,
964                                        struct ntvfs_request *req,
965                                        union smb_write *wr, 
966                                        union smb_write *wr2, 
967                                        NTSTATUS status)
968 {
969         union smb_lock *lck;
970         union smb_close *cl;
971         uint_t state;
972
973         if (NT_STATUS_IS_ERR(status)) {
974                 return status;
975         }
976
977         switch (wr->generic.level) {
978         case RAW_WRITE_WRITE:
979                 wr->write.out.nwritten    = wr2->generic.out.nwritten;
980                 break;
981
982         case RAW_WRITE_WRITEUNLOCK:
983                 wr->writeunlock.out.nwritten = wr2->generic.out.nwritten;
984
985                 lck = talloc(wr2, union smb_lock);
986                 if (lck == NULL) {
987                         return NT_STATUS_NO_MEMORY;
988                 }
989
990                 lck->unlock.level               = RAW_LOCK_UNLOCK;
991                 lck->unlock.in.file.ntvfs       = wr->writeunlock.in.file.ntvfs;
992                 lck->unlock.in.count            = wr->writeunlock.in.count;
993                 lck->unlock.in.offset           = wr->writeunlock.in.offset;
994
995                 if (lck->unlock.in.count != 0) {
996                         /* do the lock sync for now */
997                         state = req->async_states->state;
998                         req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
999                         status = ntvfs->ops->lock(ntvfs, req, lck);
1000                         req->async_states->state = state;
1001                 }
1002                 break;
1003
1004         case RAW_WRITE_WRITECLOSE:
1005                 wr->writeclose.out.nwritten    = wr2->generic.out.nwritten;
1006
1007                 cl = talloc(wr2, union smb_close);
1008                 if (cl == NULL) {
1009                         return NT_STATUS_NO_MEMORY;
1010                 }
1011
1012                 cl->close.level         = RAW_CLOSE_CLOSE;
1013                 cl->close.in.file.ntvfs = wr->writeclose.in.file.ntvfs;
1014                 cl->close.in.write_time = wr->writeclose.in.mtime;
1015
1016                 if (wr2->generic.in.count != 0) {
1017                         /* do the close sync for now */
1018                         state = req->async_states->state;
1019                         req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1020                         status = ntvfs->ops->close(ntvfs, req, cl);
1021                         req->async_states->state = state;
1022                 }
1023                 break;
1024
1025         case RAW_WRITE_SPLWRITE:
1026                 break;
1027         default:
1028                 return NT_STATUS_INVALID_LEVEL;
1029         }
1030
1031         return status;
1032 }
1033
1034
1035 /* 
1036    NTVFS write generic to any mapper
1037 */
1038 _PUBLIC_ NTSTATUS ntvfs_map_write(struct ntvfs_module_context *ntvfs,
1039                                   struct ntvfs_request *req,
1040                                   union smb_write *wr)
1041 {
1042         union smb_write *wr2;
1043         NTSTATUS status;
1044
1045         wr2 = talloc(req, union smb_write);
1046         if (wr2 == NULL) {
1047                 return NT_STATUS_NO_MEMORY;
1048         }
1049
1050         status = ntvfs_map_async_setup(ntvfs, req, wr, wr2, 
1051                                        (second_stage_t)ntvfs_map_write_finish);
1052         if (!NT_STATUS_IS_OK(status)) {
1053                 return status;
1054         }
1055
1056         wr2->writex.level = RAW_WRITE_GENERIC;
1057
1058         switch (wr->generic.level) {
1059         case RAW_WRITE_WRITEX:
1060                 status = NT_STATUS_INVALID_LEVEL;
1061                 break;
1062
1063         case RAW_WRITE_WRITE:
1064                 wr2->writex.in.file.ntvfs= wr->write.in.file.ntvfs;
1065                 wr2->writex.in.offset    = wr->write.in.offset;
1066                 wr2->writex.in.wmode     = 0;
1067                 wr2->writex.in.remaining = wr->write.in.remaining;
1068                 wr2->writex.in.count     = wr->write.in.count;
1069                 wr2->writex.in.data      = wr->write.in.data;
1070                 status = ntvfs->ops->write(ntvfs, req, wr2);
1071                 break;
1072
1073         case RAW_WRITE_WRITEUNLOCK:
1074                 wr2->writex.in.file.ntvfs= wr->writeunlock.in.file.ntvfs;
1075                 wr2->writex.in.offset    = wr->writeunlock.in.offset;
1076                 wr2->writex.in.wmode     = 0;
1077                 wr2->writex.in.remaining = wr->writeunlock.in.remaining;
1078                 wr2->writex.in.count     = wr->writeunlock.in.count;
1079                 wr2->writex.in.data      = wr->writeunlock.in.data;
1080                 status = ntvfs->ops->write(ntvfs, req, wr2);
1081                 break;
1082
1083         case RAW_WRITE_WRITECLOSE:
1084                 wr2->writex.in.file.ntvfs= wr->writeclose.in.file.ntvfs;
1085                 wr2->writex.in.offset    = wr->writeclose.in.offset;
1086                 wr2->writex.in.wmode     = 0;
1087                 wr2->writex.in.remaining = 0;
1088                 wr2->writex.in.count     = wr->writeclose.in.count;
1089                 wr2->writex.in.data      = wr->writeclose.in.data;
1090                 status = ntvfs->ops->write(ntvfs, req, wr2);
1091                 break;
1092
1093         case RAW_WRITE_SPLWRITE:
1094                 wr2->writex.in.file.ntvfs= wr->splwrite.in.file.ntvfs;
1095                 wr2->writex.in.offset    = 0;
1096                 wr2->writex.in.wmode     = 0;
1097                 wr2->writex.in.remaining = 0;
1098                 wr2->writex.in.count     = wr->splwrite.in.count;
1099                 wr2->writex.in.data      = wr->splwrite.in.data;
1100                 status = ntvfs->ops->write(ntvfs, req, wr2);
1101                 break;
1102         }
1103
1104         return ntvfs_map_async_finish(req, status);
1105 }
1106
1107
1108 /* 
1109    NTVFS read generic to any mapper - finish the out mapping
1110 */
1111 static NTSTATUS ntvfs_map_read_finish(struct ntvfs_module_context *ntvfs,
1112                                       struct ntvfs_request *req, 
1113                                       union smb_read *rd, 
1114                                       union smb_read *rd2,
1115                                       NTSTATUS status)
1116 {
1117         switch (rd->generic.level) {
1118         case RAW_READ_READ:
1119                 rd->read.out.nread        = rd2->generic.out.nread;
1120                 break;
1121         case RAW_READ_READBRAW:
1122                 rd->readbraw.out.nread    = rd2->generic.out.nread;
1123                 break;
1124         case RAW_READ_LOCKREAD:
1125                 rd->lockread.out.nread = rd2->generic.out.nread;
1126                 break;
1127         default:
1128                 return NT_STATUS_INVALID_LEVEL;
1129         }
1130
1131         return status;
1132 }
1133
1134 /* 
1135    NTVFS read* to readx mapper
1136 */
1137 _PUBLIC_ NTSTATUS ntvfs_map_read(struct ntvfs_module_context *ntvfs,
1138                                  struct ntvfs_request *req,
1139                                  union smb_read *rd)
1140 {
1141         union smb_read *rd2;
1142         union smb_lock *lck;
1143         NTSTATUS status;
1144         uint_t state;
1145
1146         rd2 = talloc(req, union smb_read);
1147         if (rd2 == NULL) {
1148                 return NT_STATUS_NO_MEMORY;
1149         }
1150
1151         status = ntvfs_map_async_setup(ntvfs, req, rd, rd2, 
1152                                        (second_stage_t)ntvfs_map_read_finish);
1153         if (!NT_STATUS_IS_OK(status)) {
1154                 return status;
1155         }
1156
1157         rd2->readx.level = RAW_READ_READX;
1158         rd2->readx.in.read_for_execute = False;
1159
1160         switch (rd->generic.level) {
1161         case RAW_READ_READX:
1162                 status = NT_STATUS_INVALID_LEVEL;
1163                 break;
1164
1165         case RAW_READ_READ:
1166                 rd2->readx.in.file.ntvfs= rd->read.in.file.ntvfs;
1167                 rd2->readx.in.offset    = rd->read.in.offset;
1168                 rd2->readx.in.mincnt    = rd->read.in.count;
1169                 rd2->readx.in.maxcnt    = rd->read.in.count;
1170                 rd2->readx.in.remaining = rd->read.in.remaining;
1171                 rd2->readx.out.data     = rd->read.out.data;
1172                 status = ntvfs->ops->read(ntvfs, req, rd2);
1173                 break;
1174
1175         case RAW_READ_READBRAW:
1176                 rd2->readx.in.file.ntvfs= rd->readbraw.in.file.ntvfs;
1177                 rd2->readx.in.offset    = rd->readbraw.in.offset;
1178                 rd2->readx.in.mincnt    = rd->readbraw.in.mincnt;
1179                 rd2->readx.in.maxcnt    = rd->readbraw.in.maxcnt;
1180                 rd2->readx.in.remaining = 0;
1181                 rd2->readx.out.data     = rd->readbraw.out.data;
1182                 status = ntvfs->ops->read(ntvfs, req, rd2);
1183                 break;
1184
1185         case RAW_READ_LOCKREAD:
1186                 /* do the initial lock sync for now */
1187                 state = req->async_states->state;
1188                 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1189
1190                 lck = talloc(rd2, union smb_lock);
1191                 if (lck == NULL) {
1192                         status = NT_STATUS_NO_MEMORY;
1193                         goto done;
1194                 }
1195                 lck->lock.level         = RAW_LOCK_LOCK;
1196                 lck->lock.in.file.ntvfs = rd->lockread.in.file.ntvfs;
1197                 lck->lock.in.count      = rd->lockread.in.count;
1198                 lck->lock.in.offset     = rd->lockread.in.offset;
1199                 status = ntvfs->ops->lock(ntvfs, req, lck);
1200                 req->async_states->state = state;
1201
1202                 rd2->readx.in.file.ntvfs= rd->lockread.in.file.ntvfs;
1203                 rd2->readx.in.offset    = rd->lockread.in.offset;
1204                 rd2->readx.in.mincnt    = rd->lockread.in.count;
1205                 rd2->readx.in.maxcnt    = rd->lockread.in.count;
1206                 rd2->readx.in.remaining = rd->lockread.in.remaining;
1207                 rd2->readx.out.data     = rd->lockread.out.data;
1208
1209                 if (NT_STATUS_IS_OK(status)) {
1210                         status = ntvfs->ops->read(ntvfs, req, rd2);
1211                 }
1212                 break;
1213         }
1214
1215 done:
1216         return ntvfs_map_async_finish(req, status);
1217 }
1218
1219
1220 /* 
1221    NTVFS close generic to any mapper
1222 */
1223 _PUBLIC_ NTSTATUS ntvfs_map_close(struct ntvfs_module_context *ntvfs,
1224                                   struct ntvfs_request *req,
1225                                   union smb_close *cl)
1226 {
1227         union smb_close *cl2;
1228
1229         cl2 = talloc(req, union smb_close);
1230         if (cl2 == NULL) {
1231                 return NT_STATUS_NO_MEMORY;
1232         }
1233
1234         switch (cl->generic.level) {
1235         case RAW_CLOSE_CLOSE:
1236                 return NT_STATUS_INVALID_LEVEL;
1237
1238         case RAW_CLOSE_SPLCLOSE:
1239                 cl2->close.level        = RAW_CLOSE_CLOSE;
1240                 cl2->close.in.file.ntvfs= cl->splclose.in.file.ntvfs;
1241                 break;
1242         }
1243
1244         /* 
1245          * we don't need to call ntvfs_map_async_setup() here,
1246          * as close() doesn't have any output fields
1247          */
1248
1249         return ntvfs->ops->close(ntvfs, req, cl2);
1250 }