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