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