s4-pvfs: move the private ntcreatex flags to private_flags
[ira/wip.git] / source4 / ntvfs / ntvfs_generic.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    NTVFS generic level mapping code
5
6    Copyright (C) Andrew Tridgell 2003-2004
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 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, see <http://www.gnu.org/licenses/>.
20 */
21 /*
22   this implements mappings between info levels for NTVFS backend calls
23
24   the idea is that each of these functions implements one of the NTVFS
25   backend calls in terms of the 'generic' call. All backends that use
26   these functions must supply the generic call, but can if it wants to
27   also implement other levels if the need arises
28
29   this allows backend writers to only implement one variant of each
30   call unless they need fine grained control of the calls.
31 */
32
33 #include "includes.h"
34 #include "ntvfs/ntvfs.h"
35 #include "libcli/smb2/smb2.h"
36 #include "libcli/smb2/smb2_calls.h"
37
38 /* a second stage function converts from the out parameters of the generic
39    call onto the out parameters of the specific call made */
40 typedef NTSTATUS (*second_stage_t)(struct ntvfs_module_context *,
41                                    struct ntvfs_request *,
42                                    void *, void *, NTSTATUS);
43
44 /* 
45    this structure holds the async state for pending mapped async calls
46 */
47 struct ntvfs_map_async {
48         struct ntvfs_module_context *ntvfs;
49         void *io, *io2;
50         second_stage_t fn;
51 };
52
53 /*
54   this is a async wrapper, called from the backend when it has completed
55   a function that it has decided to reply to in an async fashion
56 */
57 static void ntvfs_map_async_send(struct ntvfs_request *req)
58 {
59         struct ntvfs_map_async *m = talloc_get_type(req->async_states->private_data,
60                                     struct ntvfs_map_async);
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 = talloc_get_type(req->async_states->private_data,
110                             struct ntvfs_map_async);
111
112         ntvfs_async_state_pop(req);
113
114         return m->fn(m->ntvfs, req, m->io, m->io2, status);
115 }
116
117 /*
118   see if a filename ends in EXE COM DLL or SYM. This is needed for the
119   DENY_DOS mapping for OpenX
120 */
121 bool is_exe_filename(const char *fname)
122 {
123         char *p;
124         p = strrchr(fname, '.');
125         if (!p) {
126                 return false;
127         }
128         p++;
129         if (strcasecmp(p, "EXE") == 0 ||
130             strcasecmp(p, "COM") == 0 ||
131             strcasecmp(p, "DLL") == 0 ||
132             strcasecmp(p, "SYM") == 0) {
133                 return true;
134         }
135         return false;
136 }
137
138
139 /* 
140    NTVFS openx to ntcreatex mapper
141 */
142 static NTSTATUS ntvfs_map_open_finish(struct ntvfs_module_context *ntvfs,
143                                       struct ntvfs_request *req, 
144                                       union smb_open *io, 
145                                       union smb_open *io2, 
146                                       NTSTATUS status)
147 {
148         time_t write_time = 0;
149         uint32_t set_size = 0;
150         union smb_setfileinfo *sf;
151         unsigned int state;
152
153         if (!NT_STATUS_IS_OK(status)) {
154                 return status;
155         }
156
157         switch (io->generic.level) {
158         case RAW_OPEN_OPEN:
159                 io->openold.out.file.ntvfs = io2->generic.out.file.ntvfs;
160                 io->openold.out.attrib     = io2->generic.out.attrib;
161                 io->openold.out.write_time = nt_time_to_unix(io2->generic.out.write_time);
162                 io->openold.out.size       = io2->generic.out.size;
163                 io->openold.out.rmode      = io->openold.in.open_mode;
164                 break;
165
166         case RAW_OPEN_OPENX:
167                 io->openx.out.file.ntvfs  = io2->generic.out.file.ntvfs;
168                 io->openx.out.attrib      = io2->generic.out.attrib;
169                 io->openx.out.write_time  = nt_time_to_unix(io2->generic.out.write_time);
170                 io->openx.out.size        = io2->generic.out.size;
171                 io->openx.out.access      = (io->openx.in.open_mode & OPENX_MODE_ACCESS_MASK);
172                 io->openx.out.ftype       = 0;
173                 io->openx.out.devstate    = 0;
174                 io->openx.out.action      = io2->generic.out.create_action;
175                 io->openx.out.unique_fid  = 0;
176                 io->openx.out.access_mask = SEC_STD_ALL;
177                 io->openx.out.unknown     = 0;
178                 
179                 /* we need to extend the file to the requested size if
180                    it was newly created */
181                 if (io2->generic.out.create_action == NTCREATEX_ACTION_CREATED) {
182                         set_size = io->openx.in.size;
183                 }
184                 break;
185
186         case RAW_OPEN_T2OPEN:
187                 io->t2open.out.file.ntvfs  = io2->generic.out.file.ntvfs;
188                 io->t2open.out.attrib      = io2->generic.out.attrib;
189                 io->t2open.out.write_time  = nt_time_to_unix(io2->generic.out.write_time);
190                 io->t2open.out.size        = io2->generic.out.size;
191                 io->t2open.out.access      = io->t2open.in.open_mode;
192                 io->t2open.out.ftype       = 0;
193                 io->t2open.out.devstate    = 0;
194                 io->t2open.out.action      = io2->generic.out.create_action;
195                 io->t2open.out.file_id      = 0;
196                 break;
197
198         case RAW_OPEN_MKNEW:
199         case RAW_OPEN_CREATE:
200                 io->mknew.out.file.ntvfs= io2->generic.out.file.ntvfs;
201                 write_time              = io->mknew.in.write_time;
202                 break;
203
204         case RAW_OPEN_CTEMP:
205                 io->ctemp.out.file.ntvfs= io2->generic.out.file.ntvfs;
206                 io->ctemp.out.name      = talloc_strdup(req, io2->generic.in.fname + 
207                                                         strlen(io->ctemp.in.directory) + 1);
208                 NT_STATUS_HAVE_NO_MEMORY(io->ctemp.out.name);
209                 break;
210
211         case RAW_OPEN_SMB2:
212                 ZERO_STRUCT(io->smb2.out);
213                 io->smb2.out.file.ntvfs         = io2->generic.out.file.ntvfs;
214                 switch (io2->generic.out.oplock_level) {
215                 case BATCH_OPLOCK_RETURN:
216                         io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
217                         break;
218                 case EXCLUSIVE_OPLOCK_RETURN:
219                         io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
220                         break;
221                 case LEVEL_II_OPLOCK_RETURN:
222                         io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_II;
223                         break;
224                 default:
225                         io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_NONE;
226                         break;
227                 }
228                 io->smb2.out.reserved           = 0;
229                 io->smb2.out.create_action      = io2->generic.out.create_action;
230                 io->smb2.out.create_time        = io2->generic.out.create_time;
231                 io->smb2.out.access_time        = io2->generic.out.access_time;
232                 io->smb2.out.write_time         = io2->generic.out.write_time;
233                 io->smb2.out.change_time        = io2->generic.out.change_time;
234                 io->smb2.out.alloc_size         = io2->generic.out.alloc_size;
235                 io->smb2.out.size               = io2->generic.out.size;
236                 io->smb2.out.file_attr          = io2->generic.out.attrib;
237                 io->smb2.out.reserved2          = 0;
238                 io->smb2.out.maximal_access     = io2->generic.out.maximal_access;
239                 break;
240
241         default:
242                 return NT_STATUS_INVALID_LEVEL;
243         }
244
245         /* doing a secondary request async is more trouble than its
246            worth */
247         state = req->async_states->state;
248         req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
249
250         if (write_time != 0) {
251                 sf = talloc(req, union smb_setfileinfo);
252                 NT_STATUS_HAVE_NO_MEMORY(sf);
253                 sf->generic.level           = RAW_SFILEINFO_STANDARD;
254                 sf->generic.in.file.ntvfs   = io2->generic.out.file.ntvfs;
255                 sf->standard.in.create_time = 0;
256                 sf->standard.in.write_time  = write_time;
257                 sf->standard.in.access_time = 0;
258                 status = ntvfs->ops->setfileinfo(ntvfs, req, sf);
259         }
260
261         if (set_size != 0) {
262                 sf = talloc(req, union smb_setfileinfo);                        
263                 NT_STATUS_HAVE_NO_MEMORY(sf);
264                 sf->generic.level            = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
265                 sf->generic.in.file.ntvfs    = io2->generic.out.file.ntvfs;
266                 sf->end_of_file_info.in.size = set_size;
267                 status = ntvfs->ops->setfileinfo(ntvfs, req, sf);
268                 if (NT_STATUS_IS_OK(status)) {
269                         io->openx.out.size = io->openx.in.size;
270                 }
271         }
272
273         req->async_states->state = state;
274
275         return NT_STATUS_OK;
276 }
277
278 /*
279   the core of the mapping between openx style parameters and ntcreatex 
280   parameters
281 */
282 static NTSTATUS map_openx_open(uint16_t flags, uint16_t open_mode, 
283                                uint16_t open_func, const char *fname,
284                                union smb_open *io2)
285 {
286         io2->generic.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
287         io2->generic.in.private_flags = 0;
288
289         if (flags & OPENX_FLAGS_REQUEST_OPLOCK) {
290                 io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_OPLOCK;
291         }
292         if (flags & OPENX_FLAGS_REQUEST_BATCH_OPLOCK) {
293                 io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
294         }
295
296         switch (open_mode & OPENX_MODE_ACCESS_MASK) {
297         case OPENX_MODE_ACCESS_READ:
298         case OPENX_MODE_ACCESS_EXEC:
299                 io2->generic.in.access_mask = SEC_RIGHTS_FILE_READ;
300                 break;
301         case OPENX_MODE_ACCESS_WRITE:
302                 io2->generic.in.access_mask = SEC_RIGHTS_FILE_WRITE;
303                 break;
304         case OPENX_MODE_ACCESS_RDWR:
305         case OPENX_MODE_ACCESS_FCB:
306                 io2->generic.in.access_mask = 
307                         SEC_RIGHTS_FILE_READ | 
308                         SEC_RIGHTS_FILE_WRITE;
309                 break;
310         default:
311                 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
312         }
313
314         switch (open_mode & OPENX_MODE_DENY_MASK) {
315         case OPENX_MODE_DENY_READ:
316                 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_WRITE;
317                 break;
318         case OPENX_MODE_DENY_WRITE:
319                 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
320                 break;
321         case OPENX_MODE_DENY_ALL:
322                 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
323                 break;
324         case OPENX_MODE_DENY_NONE:
325                 io2->generic.in.share_access = 
326                         NTCREATEX_SHARE_ACCESS_READ | 
327                         NTCREATEX_SHARE_ACCESS_WRITE;
328                 break;
329         case OPENX_MODE_DENY_DOS:
330                 /* DENY_DOS is quite strange - it depends on the filename! */
331                 io2->generic.in.private_flags |=
332                         NTCREATEX_OPTIONS_PRIVATE_DENY_DOS;
333                 if (is_exe_filename(fname)) {
334                         io2->generic.in.share_access = 
335                                 NTCREATEX_SHARE_ACCESS_READ | 
336                                 NTCREATEX_SHARE_ACCESS_WRITE;
337                 } else {
338                         if ((open_mode & OPENX_MODE_ACCESS_MASK) == OPENX_MODE_ACCESS_READ) {
339                                 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
340                         } else {
341                                 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
342                         }
343                 }
344                 break;
345         case OPENX_MODE_DENY_FCB:
346                 io2->generic.in.private_flags |= NTCREATEX_OPTIONS_PRIVATE_DENY_FCB;
347                 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
348                 break;
349         default:
350                 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
351         }
352
353         switch (open_func) {
354         case (OPENX_OPEN_FUNC_OPEN):
355                 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN;
356                 break;
357         case (OPENX_OPEN_FUNC_TRUNC):
358                 io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
359                 break;
360         case (OPENX_OPEN_FUNC_FAIL | OPENX_OPEN_FUNC_CREATE):
361                 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
362                 break;
363         case (OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE):
364                 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
365                 break;
366         case (OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE):
367                 io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
368                 break;                  
369         default:
370                 /* this one is very strange */
371                 if ((open_mode & OPENX_MODE_ACCESS_MASK) == OPENX_MODE_ACCESS_EXEC) {
372                         io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
373                         break;
374                 }
375                 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
376         }
377
378         return NT_STATUS_OK;
379 }
380
381 /* 
382    NTVFS open generic to any mapper
383 */
384 NTSTATUS ntvfs_map_open(struct ntvfs_module_context *ntvfs,
385                                  struct ntvfs_request *req,
386                                  union smb_open *io)
387 {
388         NTSTATUS status;
389         union smb_open *io2;
390
391         io2 = talloc_zero(req, union smb_open);
392         if (io2 == NULL) {
393                 return NT_STATUS_NO_MEMORY;
394         }
395
396         status = ntvfs_map_async_setup(ntvfs, req,
397                                        io, io2, 
398                                        (second_stage_t)ntvfs_map_open_finish);
399         if (!NT_STATUS_IS_OK(status)) {
400                 return status;
401         }
402
403         io2->generic.level = RAW_OPEN_GENERIC;
404                 
405         switch (io->generic.level) {
406         case RAW_OPEN_OPENX:
407                 status = map_openx_open(io->openx.in.flags,
408                                         io->openx.in.open_mode, 
409                                         io->openx.in.open_func, 
410                                         io->openx.in.fname,
411                                         io2);
412                 if (!NT_STATUS_IS_OK(status)) {
413                         goto done;
414                 }
415                 
416                 io2->generic.in.file_attr = io->openx.in.file_attrs;
417                 io2->generic.in.fname = io->openx.in.fname;
418                 
419                 status = ntvfs->ops->open(ntvfs, req, io2);
420                 break;
421                 
422                 
423         case RAW_OPEN_OPEN:
424                 status = map_openx_open(0,
425                                         io->openold.in.open_mode, 
426                                         OPENX_OPEN_FUNC_OPEN, 
427                                         io->openold.in.fname,
428                                         io2);
429                 if (!NT_STATUS_IS_OK(status)) {
430                         goto done;
431                 }
432
433                 io2->generic.in.file_attr = io->openold.in.search_attrs;
434                 io2->generic.in.fname = io->openold.in.fname;
435
436                 status = ntvfs->ops->open(ntvfs, req, io2);
437                 break;
438
439         case RAW_OPEN_T2OPEN:
440                 io2->generic.level         = RAW_OPEN_NTTRANS_CREATE;
441
442                 if (io->t2open.in.open_func == 0) {
443                         status = NT_STATUS_OBJECT_NAME_COLLISION;
444                         goto done;
445                 }
446
447                 status = map_openx_open(io->t2open.in.flags,
448                                         io->t2open.in.open_mode, 
449                                         io->t2open.in.open_func, 
450                                         io->t2open.in.fname,
451                                         io2);
452                 if (!NT_STATUS_IS_OK(status)) {
453                         goto done;
454                 }
455
456                 io2->generic.in.file_attr        = io->t2open.in.file_attrs;
457                 io2->generic.in.fname            = io->t2open.in.fname;
458                 io2->generic.in.ea_list          = talloc(io2, struct smb_ea_list);
459                 io2->generic.in.ea_list->num_eas = io->t2open.in.num_eas;
460                 io2->generic.in.ea_list->eas     = io->t2open.in.eas;
461
462                 status = ntvfs->ops->open(ntvfs, req, io2);
463                 break;
464
465         case RAW_OPEN_MKNEW:
466                 io2->generic.in.file_attr = io->mknew.in.attrib;
467                 io2->generic.in.fname = io->mknew.in.fname;
468                 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
469                 io2->generic.in.access_mask = 
470                         SEC_RIGHTS_FILE_READ |
471                         SEC_RIGHTS_FILE_WRITE;
472                 io2->generic.in.share_access = 
473                         NTCREATEX_SHARE_ACCESS_READ | 
474                         NTCREATEX_SHARE_ACCESS_WRITE;
475                 status = ntvfs->ops->open(ntvfs, req, io2);
476                 break;
477
478         case RAW_OPEN_CREATE:
479                 io2->generic.in.file_attr = io->mknew.in.attrib;
480                 io2->generic.in.fname = io->mknew.in.fname;
481                 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
482                 io2->generic.in.access_mask = 
483                         SEC_RIGHTS_FILE_READ |
484                         SEC_RIGHTS_FILE_WRITE;
485                 io2->generic.in.share_access = 
486                         NTCREATEX_SHARE_ACCESS_READ | 
487                         NTCREATEX_SHARE_ACCESS_WRITE;
488                 status = ntvfs->ops->open(ntvfs, req, io2);
489                 break;
490
491         case RAW_OPEN_CTEMP:
492                 io2->generic.in.file_attr = io->ctemp.in.attrib;
493                 io2->generic.in.fname = 
494                         talloc_asprintf(io2, "%s\\SRV%s", 
495                                         io->ctemp.in.directory,
496                                         generate_random_str_list(io2, 5, "0123456789"));
497                 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
498                 io2->generic.in.access_mask = 
499                         SEC_RIGHTS_FILE_READ |
500                         SEC_RIGHTS_FILE_WRITE;
501                 io2->generic.in.share_access = 
502                         NTCREATEX_SHARE_ACCESS_READ | 
503                         NTCREATEX_SHARE_ACCESS_WRITE;
504                 status = ntvfs->ops->open(ntvfs, req, io2);
505                 break;
506         case RAW_OPEN_SMB2:
507                 switch (io->smb2.in.oplock_level) {
508                 case SMB2_OPLOCK_LEVEL_BATCH:
509                         io2->generic.in.flags = NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK |
510                                                 NTCREATEX_FLAGS_REQUEST_OPLOCK;
511                         break;
512                 case SMB2_OPLOCK_LEVEL_EXCLUSIVE:
513                         io2->generic.in.flags = NTCREATEX_FLAGS_REQUEST_OPLOCK;
514                         break;
515                 default:
516                         io2->generic.in.flags = 0;
517                         break;
518                 }
519                 io2->generic.in.root_fid.fnum   = 0;
520                 io2->generic.in.access_mask     = io->smb2.in.desired_access;
521                 io2->generic.in.alloc_size      = io->smb2.in.alloc_size;
522                 io2->generic.in.file_attr       = io->smb2.in.file_attributes;
523                 io2->generic.in.share_access    = io->smb2.in.share_access;
524                 io2->generic.in.open_disposition= io->smb2.in.create_disposition;
525                 io2->generic.in.create_options  = io->smb2.in.create_options;
526                 io2->generic.in.impersonation   = io->smb2.in.impersonation_level;
527                 io2->generic.in.security_flags  = 0;
528                 io2->generic.in.fname           = io->smb2.in.fname;
529                 io2->generic.in.sec_desc        = io->smb2.in.sec_desc;
530                 io2->generic.in.ea_list         = &io->smb2.in.eas;
531                 io2->generic.in.query_maximal_access = io->smb2.in.query_maximal_access; 
532                 io2->generic.in.private_flags   = 0;
533
534                 /* we don't support timewarp yet */
535                 if (io->smb2.in.timewarp != 0) {
536                         status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
537                         break;
538                 }
539
540                 /* we need to check these bits before we check the private mask */
541                 if (io2->generic.in.create_options & SMB2_CREATE_OPTIONS_NOT_SUPPORTED_MASK) {
542                         DEBUG(2,(__location__ " create_options 0x%x not supported\n",
543                                  io2->generic.in.create_options));
544                         status = NT_STATUS_NOT_SUPPORTED;
545                         break;
546                 }
547
548                 /* TODO: find out why only SMB2 ignores these */
549                 io2->generic.in.create_options &= ~NTCREATEX_OPTIONS_SYNC_ALERT;
550                 io2->generic.in.create_options &= ~NTCREATEX_OPTIONS_ASYNC_ALERT;
551
552                 status = ntvfs->ops->open(ntvfs, req, io2);             
553                 break;
554
555         default:
556                 status = NT_STATUS_INVALID_LEVEL;
557                 break;
558         }
559 done:
560         return ntvfs_map_async_finish(req, status);
561 }
562
563
564 /* 
565    NTVFS any to fsinfo mapper
566 */
567 static NTSTATUS ntvfs_map_fsinfo_finish(struct ntvfs_module_context *ntvfs,
568                                       struct ntvfs_request *req,
569                                       union smb_fsinfo *fs,
570                                       union smb_fsinfo *fs2,
571                                       NTSTATUS status)
572 {
573         if (!NT_STATUS_IS_OK(status)) {
574                 return status;
575         }
576
577         /* and convert it to the required level */
578         switch (fs->generic.level) {
579         case RAW_QFS_GENERIC:
580                 return NT_STATUS_INVALID_LEVEL;
581
582         case RAW_QFS_DSKATTR: {
583                 /* map from generic to DSKATTR */
584                 unsigned int bpunit = 64;
585
586                 /* we need to scale the sizes to fit */
587                 for (bpunit=64; bpunit<0x10000; bpunit *= 2) {
588                         if (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size < bpunit * 512 * 65535.0) {
589                                 break;
590                         }
591                 }
592
593                 fs->dskattr.out.blocks_per_unit = bpunit;
594                 fs->dskattr.out.block_size = 512;
595                 fs->dskattr.out.units_total = 
596                         (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size) / (bpunit * 512);
597                 fs->dskattr.out.units_free  = 
598                         (fs2->generic.out.blocks_free  * (double)fs2->generic.out.block_size) / (bpunit * 512);
599
600                 /* we must return a maximum of 2G to old DOS systems, or they get very confused */
601                 if (bpunit > 64 && req->ctx->protocol <= PROTOCOL_LANMAN2) {
602                         fs->dskattr.out.blocks_per_unit = 64;
603                         fs->dskattr.out.units_total = 0xFFFF;
604                         fs->dskattr.out.units_free = 0xFFFF;
605                 }
606                 return NT_STATUS_OK;
607         }
608
609         case RAW_QFS_ALLOCATION:
610                 fs->allocation.out.fs_id = fs2->generic.out.fs_id;
611                 fs->allocation.out.total_alloc_units = fs2->generic.out.blocks_total;
612                 fs->allocation.out.avail_alloc_units = fs2->generic.out.blocks_free;
613                 fs->allocation.out.sectors_per_unit = 1;
614                 fs->allocation.out.bytes_per_sector = fs2->generic.out.block_size;
615                 return NT_STATUS_OK;
616
617         case RAW_QFS_VOLUME:
618                 fs->volume.out.serial_number = fs2->generic.out.serial_number;
619                 fs->volume.out.volume_name.s = fs2->generic.out.volume_name;
620                 return NT_STATUS_OK;
621
622         case RAW_QFS_VOLUME_INFO:
623         case RAW_QFS_VOLUME_INFORMATION:
624                 fs->volume_info.out.create_time = fs2->generic.out.create_time;
625                 fs->volume_info.out.serial_number = fs2->generic.out.serial_number;
626                 fs->volume_info.out.volume_name.s = fs2->generic.out.volume_name;
627                 return NT_STATUS_OK;
628
629         case RAW_QFS_SIZE_INFO:
630         case RAW_QFS_SIZE_INFORMATION:
631                 fs->size_info.out.total_alloc_units = fs2->generic.out.blocks_total;
632                 fs->size_info.out.avail_alloc_units = fs2->generic.out.blocks_free;
633                 fs->size_info.out.sectors_per_unit = 1;
634                 fs->size_info.out.bytes_per_sector = fs2->generic.out.block_size;
635                 return NT_STATUS_OK;
636
637         case RAW_QFS_DEVICE_INFO:
638         case RAW_QFS_DEVICE_INFORMATION:
639                 fs->device_info.out.device_type = fs2->generic.out.device_type;
640                 fs->device_info.out.characteristics = fs2->generic.out.device_characteristics;
641                 return NT_STATUS_OK;
642
643         case RAW_QFS_ATTRIBUTE_INFO:
644         case RAW_QFS_ATTRIBUTE_INFORMATION:
645                 fs->attribute_info.out.fs_attr = fs2->generic.out.fs_attr;
646                 fs->attribute_info.out.max_file_component_length = fs2->generic.out.max_file_component_length;
647                 fs->attribute_info.out.fs_type.s = fs2->generic.out.fs_type;
648                 return NT_STATUS_OK;
649
650         case RAW_QFS_QUOTA_INFORMATION:
651                 ZERO_STRUCT(fs->quota_information.out.unknown);
652                 fs->quota_information.out.quota_soft = fs2->generic.out.quota_soft;
653                 fs->quota_information.out.quota_hard = fs2->generic.out.quota_hard;
654                 fs->quota_information.out.quota_flags = fs2->generic.out.quota_flags;
655                 return NT_STATUS_OK;
656
657         case RAW_QFS_FULL_SIZE_INFORMATION:
658                 fs->full_size_information.out.total_alloc_units = fs2->generic.out.blocks_total;
659                 fs->full_size_information.out.call_avail_alloc_units = fs2->generic.out.blocks_free;
660                 fs->full_size_information.out.actual_avail_alloc_units = fs2->generic.out.blocks_free;
661                 fs->full_size_information.out.sectors_per_unit = 1;
662                 fs->full_size_information.out.bytes_per_sector = fs2->generic.out.block_size;
663                 return NT_STATUS_OK;
664
665         case RAW_QFS_OBJECTID_INFORMATION:
666                 fs->objectid_information.out.guid = fs2->generic.out.guid;
667                 ZERO_STRUCT(fs->objectid_information.out.unknown);
668                 return NT_STATUS_OK;
669         }
670
671
672         return NT_STATUS_INVALID_LEVEL;
673 }
674
675 /*
676    NTVFS fsinfo any to generic mapper
677 */
678 NTSTATUS ntvfs_map_fsinfo(struct ntvfs_module_context *ntvfs,
679                           struct ntvfs_request *req,
680                           union smb_fsinfo *fs)
681 {
682         NTSTATUS status;
683         union smb_fsinfo *fs2;
684
685         fs2 = talloc(req, union smb_fsinfo);
686         if (fs2 == NULL) {
687                 return NT_STATUS_NO_MEMORY;
688         }
689
690         if (fs->generic.level == RAW_QFS_GENERIC) {
691                 return NT_STATUS_INVALID_LEVEL;
692         }
693
694         status = ntvfs_map_async_setup(ntvfs, req, fs, fs2,
695                                        (second_stage_t)ntvfs_map_fsinfo_finish);
696         if (!NT_STATUS_IS_OK(status)) {
697                 return status;
698         }
699
700         /* ask the backend for the generic info */
701         fs2->generic.level = RAW_QFS_GENERIC;
702
703         status = ntvfs->ops->fsinfo(ntvfs, req, fs2);
704         return ntvfs_map_async_finish(req, status);
705 }
706
707
708 /* 
709    NTVFS fileinfo generic to any mapper
710 */
711 NTSTATUS ntvfs_map_fileinfo(TALLOC_CTX *mem_ctx,
712                                      union smb_fileinfo *info, 
713                                      union smb_fileinfo *info2)
714 {
715         int i;
716         /* and convert it to the required level using results in info2 */
717         switch (info->generic.level) {
718                 case RAW_FILEINFO_GENERIC:
719                 return NT_STATUS_INVALID_LEVEL;
720         case RAW_FILEINFO_GETATTR:
721                 info->getattr.out.attrib = info2->generic.out.attrib & 0xff;
722                 info->getattr.out.size = info2->generic.out.size;
723                 info->getattr.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
724                 return NT_STATUS_OK;
725                 
726         case RAW_FILEINFO_GETATTRE:
727                 info->getattre.out.attrib = info2->generic.out.attrib;
728                 info->getattre.out.size = info2->generic.out.size;
729                 info->getattre.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
730                 info->getattre.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
731                 info->getattre.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
732                 info->getattre.out.alloc_size = info2->generic.out.alloc_size;
733                 return NT_STATUS_OK;
734                 
735         case RAW_FILEINFO_NETWORK_OPEN_INFORMATION:
736                 info->network_open_information.out.create_time = info2->generic.out.create_time;
737                 info->network_open_information.out.access_time = info2->generic.out.access_time;
738                 info->network_open_information.out.write_time =  info2->generic.out.write_time;
739                 info->network_open_information.out.change_time = info2->generic.out.change_time;
740                 info->network_open_information.out.alloc_size = info2->generic.out.alloc_size;
741                 info->network_open_information.out.size = info2->generic.out.size;
742                 info->network_open_information.out.attrib = info2->generic.out.attrib;
743                 return NT_STATUS_OK;
744
745         case RAW_FILEINFO_ALL_INFO:
746         case RAW_FILEINFO_ALL_INFORMATION:
747                 info->all_info.out.create_time = info2->generic.out.create_time;
748                 info->all_info.out.access_time = info2->generic.out.access_time;
749                 info->all_info.out.write_time =  info2->generic.out.write_time;
750                 info->all_info.out.change_time = info2->generic.out.change_time;
751                 info->all_info.out.attrib = info2->generic.out.attrib;
752                 info->all_info.out.alloc_size = info2->generic.out.alloc_size;
753                 info->all_info.out.size = info2->generic.out.size;
754                 info->all_info.out.nlink = info2->generic.out.nlink;
755                 info->all_info.out.delete_pending = info2->generic.out.delete_pending;
756                 info->all_info.out.directory = info2->generic.out.directory;
757                 info->all_info.out.ea_size = info2->generic.out.ea_size;
758                 info->all_info.out.fname.s = info2->generic.out.fname.s;
759                 info->all_info.out.fname.private_length = info2->generic.out.fname.private_length;
760                 return NT_STATUS_OK;
761
762         case RAW_FILEINFO_BASIC_INFO:
763         case RAW_FILEINFO_BASIC_INFORMATION:
764                 info->basic_info.out.create_time = info2->generic.out.create_time;
765                 info->basic_info.out.access_time = info2->generic.out.access_time;
766                 info->basic_info.out.write_time = info2->generic.out.write_time;
767                 info->basic_info.out.change_time = info2->generic.out.change_time;
768                 info->basic_info.out.attrib = info2->generic.out.attrib;
769                 return NT_STATUS_OK;
770
771         case RAW_FILEINFO_STANDARD:
772                 info->standard.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
773                 info->standard.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
774                 info->standard.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
775                 info->standard.out.size = info2->generic.out.size;
776                 info->standard.out.alloc_size = info2->generic.out.alloc_size;
777                 info->standard.out.attrib = info2->generic.out.attrib;
778                 return NT_STATUS_OK;
779
780         case RAW_FILEINFO_EA_SIZE:
781                 info->ea_size.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
782                 info->ea_size.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
783                 info->ea_size.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
784                 info->ea_size.out.size = info2->generic.out.size;
785                 info->ea_size.out.alloc_size = info2->generic.out.alloc_size;
786                 info->ea_size.out.attrib = info2->generic.out.attrib;
787                 info->ea_size.out.ea_size = info2->generic.out.ea_size;
788                 return NT_STATUS_OK;
789
790         case RAW_FILEINFO_STANDARD_INFO:
791         case RAW_FILEINFO_STANDARD_INFORMATION:
792                 info->standard_info.out.alloc_size = info2->generic.out.alloc_size;
793                 info->standard_info.out.size = info2->generic.out.size;
794                 info->standard_info.out.nlink = info2->generic.out.nlink;
795                 info->standard_info.out.delete_pending = info2->generic.out.delete_pending;
796                 info->standard_info.out.directory = info2->generic.out.directory;
797                 return NT_STATUS_OK;
798
799         case RAW_FILEINFO_INTERNAL_INFORMATION:
800                 info->internal_information.out.file_id = info2->generic.out.file_id;
801                 return NT_STATUS_OK;
802
803         case RAW_FILEINFO_EA_INFO:
804         case RAW_FILEINFO_EA_INFORMATION:
805                 info->ea_info.out.ea_size = info2->generic.out.ea_size;
806                 return NT_STATUS_OK;
807
808         case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION:
809                 info->attribute_tag_information.out.attrib = info2->generic.out.attrib;
810                 info->attribute_tag_information.out.reparse_tag = info2->generic.out.reparse_tag;
811                 return NT_STATUS_OK;
812
813         case RAW_FILEINFO_STREAM_INFO:
814         case RAW_FILEINFO_STREAM_INFORMATION:
815                 info->stream_info.out.num_streams = info2->generic.out.num_streams;
816                 if (info->stream_info.out.num_streams > 0) {
817                         info->stream_info.out.streams = 
818                                 talloc_array(mem_ctx, 
819                                                struct stream_struct,
820                                                info->stream_info.out.num_streams);
821                         if (!info->stream_info.out.streams) {
822                                 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d streams\n",
823                                         info->stream_info.out.num_streams));
824                                 return NT_STATUS_NO_MEMORY;
825                         }
826                         for (i=0; i < info->stream_info.out.num_streams; i++) {
827                                 info->stream_info.out.streams[i] = info2->generic.out.streams[i];
828                                 info->stream_info.out.streams[i].stream_name.s = 
829                                         talloc_strdup(info->stream_info.out.streams,
830                                                       info2->generic.out.streams[i].stream_name.s);
831                                 if (!info->stream_info.out.streams[i].stream_name.s) {
832                                         DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
833                                         return NT_STATUS_NO_MEMORY;
834                                 }
835                         }
836                 }
837                 return NT_STATUS_OK;
838
839         case RAW_FILEINFO_NAME_INFO:
840         case RAW_FILEINFO_NAME_INFORMATION:
841                 info->name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.fname.s);
842                 NT_STATUS_HAVE_NO_MEMORY(info->name_info.out.fname.s);
843                 info->name_info.out.fname.private_length = info2->generic.out.fname.private_length;
844                 return NT_STATUS_OK;
845                 
846         case RAW_FILEINFO_ALT_NAME_INFO:
847         case RAW_FILEINFO_ALT_NAME_INFORMATION:
848                 info->alt_name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.alt_fname.s);
849                 NT_STATUS_HAVE_NO_MEMORY(info->alt_name_info.out.fname.s);
850                 info->alt_name_info.out.fname.private_length = info2->generic.out.alt_fname.private_length;
851                 return NT_STATUS_OK;
852         
853         case RAW_FILEINFO_POSITION_INFORMATION:
854                 info->position_information.out.position = info2->generic.out.position;
855                 return NT_STATUS_OK;
856         
857         case RAW_FILEINFO_ALL_EAS:
858                 info->all_eas.out.num_eas = info2->generic.out.num_eas;
859                 if (info->all_eas.out.num_eas > 0) {
860                         info->all_eas.out.eas = talloc_array(mem_ctx, 
861                                                                struct ea_struct,
862                                                                info->all_eas.out.num_eas);
863                         if (!info->all_eas.out.eas) {
864                                 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d eas\n",
865                                         info->all_eas.out.num_eas));
866                                 return NT_STATUS_NO_MEMORY;
867                         }
868                         for (i = 0; i < info->all_eas.out.num_eas; i++) {
869                                 info->all_eas.out.eas[i] = info2->generic.out.eas[i];
870                                 info->all_eas.out.eas[i].name.s = 
871                                         talloc_strdup(info->all_eas.out.eas,
872                                                       info2->generic.out.eas[i].name.s);
873                                 if (!info->all_eas.out.eas[i].name.s) {
874                                         DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
875                                         return NT_STATUS_NO_MEMORY;
876                                 }
877                                 info->all_eas.out.eas[i].value.data = 
878                                         (uint8_t *)talloc_memdup(info->all_eas.out.eas,
879                                                 info2->generic.out.eas[i].value.data,
880                                                 info2->generic.out.eas[i].value.length);
881                                 if (!info->all_eas.out.eas[i].value.data) {
882                                         DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
883                                         return NT_STATUS_NO_MEMORY;
884                                 }
885                         }
886                 }
887                 return NT_STATUS_OK;
888                 
889         case RAW_FILEINFO_IS_NAME_VALID:
890                 return NT_STATUS_OK;
891                 
892         case RAW_FILEINFO_COMPRESSION_INFO:
893         case RAW_FILEINFO_COMPRESSION_INFORMATION:
894                 info->compression_info.out.compressed_size = info2->generic.out.compressed_size;
895                 info->compression_info.out.format = info2->generic.out.format;
896                 info->compression_info.out.unit_shift = info2->generic.out.unit_shift;
897                 info->compression_info.out.chunk_shift = info2->generic.out.chunk_shift;
898                 info->compression_info.out.cluster_shift = info2->generic.out.cluster_shift;
899                 return NT_STATUS_OK;
900                 
901         case RAW_FILEINFO_ACCESS_INFORMATION:
902                 info->access_information.out.access_flags = info2->generic.out.access_flags;
903                 return NT_STATUS_OK;
904                 
905         case RAW_FILEINFO_MODE_INFORMATION:
906                 info->mode_information.out.mode = info2->generic.out.mode;
907                 return NT_STATUS_OK;
908                 
909         case RAW_FILEINFO_ALIGNMENT_INFORMATION:
910                 info->alignment_information.out.alignment_requirement =
911                         info2->generic.out.alignment_requirement;
912                 return NT_STATUS_OK;
913 #if 0   
914         case RAW_FILEINFO_UNIX_BASIC:
915                 info->unix_basic_info.out.end_of_file = info2->generic.out.end_of_file;
916                 info->unix_basic_info.out.num_bytes = info2->generic.out.size;
917                 info->unix_basic_info.out.status_change_time = info2->generic.out.change_time;
918                 info->unix_basic_info.out.access_time = info2->generic.out.access_time;
919                 info->unix_basic_info.out.change_time = info2->generic.out.change_time;
920                 info->unix_basic_info.out.uid = info2->generic.out.uid;
921                 info->unix_basic_info.out.gid = info2->generic.out.gid;
922                 info->unix_basic_info.out.file_type = info2->generic.out.file_type;
923                 info->unix_basic_info.out.dev_major = info2->generic.out.device;
924                 info->unix_basic_info.out.dev_minor = info2->generic.out.device;
925                 info->unix_basic_info.out.unique_id = info2->generic.out.inode;
926                 info->unix_basic_info.out.permissions = info2->generic.out.permissions;
927                 info->unix_basic_info.out.nlink = info2->generic.out.nlink;
928                 return NT_STATUS_OK;
929                 
930         case RAW_FILEINFO_UNIX_LINK:
931                 info->unix_link_info.out.link_dest = info2->generic.out.link_dest;
932                 return NT_STATUS_OK;
933 #endif
934         }
935
936         return NT_STATUS_INVALID_LEVEL;
937 }
938
939 /* 
940    NTVFS any to fileinfo mapper
941 */
942 static NTSTATUS ntvfs_map_qfileinfo_finish(struct ntvfs_module_context *ntvfs,
943                                       struct ntvfs_request *req,
944                                       union smb_fileinfo *info,
945                                       union smb_fileinfo *info2,
946                                       NTSTATUS status)
947 {
948         if (!NT_STATUS_IS_OK(status)) {
949                 return status;
950         }
951
952         return ntvfs_map_fileinfo(req, info, info2);
953 }
954
955 /*
956    NTVFS fileinfo generic to any mapper
957 */
958 NTSTATUS ntvfs_map_qfileinfo(struct ntvfs_module_context *ntvfs,
959                                       struct ntvfs_request *req,
960                                       union smb_fileinfo *info)
961 {
962         NTSTATUS status;
963         union smb_fileinfo *info2;
964
965         info2 = talloc(req, union smb_fileinfo);
966         if (info2 == NULL) {
967                 return NT_STATUS_NO_MEMORY;
968         }
969
970         if (info->generic.level == RAW_FILEINFO_GENERIC) {
971                 return NT_STATUS_INVALID_LEVEL;
972         }
973
974         status = ntvfs_map_async_setup(ntvfs, req, info, info2,
975                                        (second_stage_t)ntvfs_map_qfileinfo_finish);
976         if (!NT_STATUS_IS_OK(status)) {
977                 return status;
978         }
979
980         /* ask the backend for the generic info */
981         info2->generic.level = RAW_FILEINFO_GENERIC;
982         info2->generic.in.file.ntvfs= info->generic.in.file.ntvfs;
983
984         status = ntvfs->ops->qfileinfo(ntvfs, req, info2);
985         return ntvfs_map_async_finish(req, status);
986 }
987
988 /*
989    NTVFS any to fileinfo mapper
990 */
991 static NTSTATUS ntvfs_map_qpathinfo_finish(struct ntvfs_module_context *ntvfs,
992                                       struct ntvfs_request *req,
993                                       union smb_fileinfo *info,
994                                       union smb_fileinfo *info2,
995                                       NTSTATUS status)
996 {
997         if (!NT_STATUS_IS_OK(status)) {
998                 return status;
999         }
1000
1001         return ntvfs_map_fileinfo(req, info, info2);
1002 }
1003
1004 /* 
1005    NTVFS pathinfo generic to any mapper
1006 */
1007 NTSTATUS ntvfs_map_qpathinfo(struct ntvfs_module_context *ntvfs,
1008                                       struct ntvfs_request *req,
1009                                       union smb_fileinfo *info)
1010 {
1011         NTSTATUS status;
1012         union smb_fileinfo *info2;
1013
1014         info2 = talloc(req, union smb_fileinfo);
1015         if (info2 == NULL) {
1016                 return NT_STATUS_NO_MEMORY;
1017         }
1018
1019         if (info->generic.level == RAW_FILEINFO_GENERIC) {
1020                 return NT_STATUS_INVALID_LEVEL;
1021         }
1022
1023         status = ntvfs_map_async_setup(ntvfs, req, info, info2,
1024                                        (second_stage_t)ntvfs_map_qpathinfo_finish);
1025         if (!NT_STATUS_IS_OK(status)) {
1026                 return status;
1027         }
1028
1029         /* ask the backend for the generic info */
1030         info2->generic.level            = RAW_FILEINFO_GENERIC;
1031         info2->generic.in.file.path     = info->generic.in.file.path;
1032
1033         status = ntvfs->ops->qpathinfo(ntvfs, req, info2);
1034         return ntvfs_map_async_finish(req, status);
1035 }
1036
1037
1038 /* 
1039    NTVFS lock generic to any mapper
1040 */
1041 NTSTATUS ntvfs_map_lock(struct ntvfs_module_context *ntvfs,
1042                         struct ntvfs_request *req,
1043                         union smb_lock *lck)
1044 {
1045         union smb_lock *lck2;
1046         struct smb_lock_entry *locks;
1047
1048         lck2 = talloc(req, union smb_lock);
1049         if (lck2 == NULL) {
1050                 return NT_STATUS_NO_MEMORY;
1051         }
1052
1053         locks = talloc_array(lck2, struct smb_lock_entry, 1);
1054         if (locks == NULL) {
1055                 return NT_STATUS_NO_MEMORY;
1056         }
1057
1058         switch (lck->generic.level) {
1059         case RAW_LOCK_LOCKX:
1060                 return NT_STATUS_INVALID_LEVEL;
1061
1062         case RAW_LOCK_LOCK:
1063                 lck2->generic.level = RAW_LOCK_GENERIC;
1064                 lck2->generic.in.file.ntvfs= lck->lock.in.file.ntvfs;
1065                 lck2->generic.in.mode = 0;
1066                 lck2->generic.in.timeout = 0;
1067                 lck2->generic.in.ulock_cnt = 0;
1068                 lck2->generic.in.lock_cnt = 1;
1069                 lck2->generic.in.locks = locks;
1070                 locks->pid = req->smbpid;
1071                 locks->offset = lck->lock.in.offset;
1072                 locks->count = lck->lock.in.count;
1073                 break;
1074
1075         case RAW_LOCK_UNLOCK:
1076                 lck2->generic.level = RAW_LOCK_GENERIC;
1077                 lck2->generic.in.file.ntvfs= lck->unlock.in.file.ntvfs;
1078                 lck2->generic.in.mode = 0;
1079                 lck2->generic.in.timeout = 0;
1080                 lck2->generic.in.ulock_cnt = 1;
1081                 lck2->generic.in.lock_cnt = 0;
1082                 lck2->generic.in.locks = locks;
1083                 locks->pid = req->smbpid;
1084                 locks->offset = lck->unlock.in.offset;
1085                 locks->count = lck->unlock.in.count;
1086                 break;
1087
1088         case RAW_LOCK_SMB2: {
1089                 /* this is only approximate! We need to change the
1090                    generic structure to fix this properly */
1091                 int i;
1092                 bool isunlock;
1093                 if (lck->smb2.in.lock_count < 1) {
1094                         return NT_STATUS_INVALID_PARAMETER;
1095                 }
1096
1097                 lck2->generic.level = RAW_LOCK_GENERIC;
1098                 lck2->generic.in.file.ntvfs= lck->smb2.in.file.ntvfs;
1099                 lck2->generic.in.timeout = UINT32_MAX;
1100                 lck2->generic.in.mode = 0;
1101                 lck2->generic.in.lock_cnt = 0;
1102                 lck2->generic.in.ulock_cnt = 0;
1103                 lck2->generic.in.locks = talloc_zero_array(lck2, struct smb_lock_entry, 
1104                                                            lck->smb2.in.lock_count);
1105                 if (lck2->generic.in.locks == NULL) {
1106                         return NT_STATUS_NO_MEMORY;
1107                 }
1108                 /* only the first lock gives the UNLOCK bit - see
1109                    MS-SMB2 3.3.5.14 */
1110                 if (lck->smb2.in.locks[0].flags & SMB2_LOCK_FLAG_UNLOCK) {
1111                         if (lck->smb2.in.locks[0].flags & SMB2_LOCK_FLAG_FAIL_IMMEDIATELY) {
1112                                 return NT_STATUS_INVALID_PARAMETER;
1113                         }
1114                         lck2->generic.in.ulock_cnt = lck->smb2.in.lock_count;
1115                         isunlock = true;
1116                 } else {
1117                         lck2->generic.in.lock_cnt = lck->smb2.in.lock_count;
1118                         isunlock = false;
1119                 }
1120                 for (i=0;i<lck->smb2.in.lock_count;i++) {
1121                         if (!isunlock &&
1122                             lck->smb2.in.locks[i].flags == SMB2_LOCK_FLAG_NONE) {
1123                                 return NT_STATUS_INVALID_PARAMETER;
1124                         }
1125
1126                         if (lck->smb2.in.locks[i].flags & ~SMB2_LOCK_FLAG_ALL_MASK) {
1127                                 return NT_STATUS_INVALID_PARAMETER;
1128                         }
1129
1130                         if (isunlock && 
1131                             (lck->smb2.in.locks[i].flags & 
1132                              (SMB2_LOCK_FLAG_SHARED|SMB2_LOCK_FLAG_EXCLUSIVE))) {
1133                                 return NT_STATUS_INVALID_PARAMETER;
1134                         }
1135                         if (!isunlock && 
1136                             (lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_UNLOCK)) {
1137                                 return NT_STATUS_INVALID_PARAMETER;
1138                         }
1139                         lck2->generic.in.locks[i].pid    = req->smbpid;
1140                         lck2->generic.in.locks[i].offset = lck->smb2.in.locks[i].offset;
1141                         lck2->generic.in.locks[i].count  = lck->smb2.in.locks[i].length;
1142                         if (!(lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_EXCLUSIVE)) {
1143                                 lck2->generic.in.mode = LOCKING_ANDX_SHARED_LOCK;
1144                         }
1145                         if (lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_FAIL_IMMEDIATELY) {
1146                                 lck2->generic.in.timeout = 0;
1147                         }
1148                 }
1149                 /* initialize output value */
1150                 lck->smb2.out.reserved = 0;
1151                 break;
1152         }
1153
1154         case RAW_LOCK_SMB2_BREAK:
1155                 lck2->generic.level             = RAW_LOCK_GENERIC;
1156                 lck2->generic.in.file.ntvfs     = lck->smb2_break.in.file.ntvfs;
1157                 lck2->generic.in.mode           = LOCKING_ANDX_OPLOCK_RELEASE |
1158                                                   ((lck->smb2_break.in.oplock_level << 8) & 0xFF00);
1159                 lck2->generic.in.timeout        = 0;
1160                 lck2->generic.in.ulock_cnt      = 0;
1161                 lck2->generic.in.lock_cnt       = 0;
1162                 lck2->generic.in.locks          = NULL;
1163
1164                 /* initialize output value */
1165                 lck->smb2_break.out.oplock_level= lck->smb2_break.in.oplock_level;
1166                 lck->smb2_break.out.reserved    = lck->smb2_break.in.reserved;
1167                 lck->smb2_break.out.reserved2   = lck->smb2_break.in.reserved2;
1168                 lck->smb2_break.out.file        = lck->smb2_break.in.file;
1169                 break;
1170         }
1171
1172         /* 
1173          * we don't need to call ntvfs_map_async_setup() here,
1174          * as lock() doesn't have any output fields
1175          */
1176
1177         return ntvfs->ops->lock(ntvfs, req, lck2);
1178 }
1179
1180
1181 /* 
1182    NTVFS write generic to any mapper
1183 */
1184 static NTSTATUS ntvfs_map_write_finish(struct ntvfs_module_context *ntvfs,
1185                                        struct ntvfs_request *req,
1186                                        union smb_write *wr, 
1187                                        union smb_write *wr2, 
1188                                        NTSTATUS status)
1189 {
1190         union smb_lock *lck;
1191         union smb_close *cl;
1192         unsigned int state;
1193
1194         if (NT_STATUS_IS_ERR(status)) {
1195                 return status;
1196         }
1197
1198         switch (wr->generic.level) {
1199         case RAW_WRITE_WRITE:
1200                 wr->write.out.nwritten    = wr2->generic.out.nwritten;
1201                 break;
1202
1203         case RAW_WRITE_WRITEUNLOCK:
1204                 wr->writeunlock.out.nwritten = wr2->generic.out.nwritten;
1205
1206                 lck = talloc(wr2, union smb_lock);
1207                 if (lck == NULL) {
1208                         return NT_STATUS_NO_MEMORY;
1209                 }
1210
1211                 lck->unlock.level               = RAW_LOCK_UNLOCK;
1212                 lck->unlock.in.file.ntvfs       = wr->writeunlock.in.file.ntvfs;
1213                 lck->unlock.in.count            = wr->writeunlock.in.count;
1214                 lck->unlock.in.offset           = wr->writeunlock.in.offset;
1215
1216                 if (lck->unlock.in.count != 0) {
1217                         /* do the lock sync for now */
1218                         state = req->async_states->state;
1219                         req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1220                         status = ntvfs->ops->lock(ntvfs, req, lck);
1221                         req->async_states->state = state;
1222                 }
1223                 break;
1224
1225         case RAW_WRITE_WRITECLOSE:
1226                 wr->writeclose.out.nwritten    = wr2->generic.out.nwritten;
1227
1228                 cl = talloc(wr2, union smb_close);
1229                 if (cl == NULL) {
1230                         return NT_STATUS_NO_MEMORY;
1231                 }
1232
1233                 cl->close.level         = RAW_CLOSE_CLOSE;
1234                 cl->close.in.file.ntvfs = wr->writeclose.in.file.ntvfs;
1235                 cl->close.in.write_time = wr->writeclose.in.mtime;
1236
1237                 if (wr2->generic.in.count != 0) {
1238                         /* do the close sync for now */
1239                         state = req->async_states->state;
1240                         req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1241                         status = ntvfs->ops->close(ntvfs, req, cl);
1242                         req->async_states->state = state;
1243                 }
1244                 break;
1245
1246         case RAW_WRITE_SPLWRITE:
1247                 break;
1248
1249         case RAW_WRITE_SMB2:
1250                 wr->smb2.out._pad       = 0;
1251                 wr->smb2.out.nwritten   = wr2->generic.out.nwritten;
1252                 wr->smb2.out.unknown1   = 0;
1253                 break;
1254
1255         default:
1256                 return NT_STATUS_INVALID_LEVEL;
1257         }
1258
1259         return status;
1260 }
1261
1262
1263 /* 
1264    NTVFS write generic to any mapper
1265 */
1266 NTSTATUS ntvfs_map_write(struct ntvfs_module_context *ntvfs,
1267                                   struct ntvfs_request *req,
1268                                   union smb_write *wr)
1269 {
1270         union smb_write *wr2;
1271         NTSTATUS status;
1272
1273         wr2 = talloc(req, union smb_write);
1274         if (wr2 == NULL) {
1275                 return NT_STATUS_NO_MEMORY;
1276         }
1277
1278         status = ntvfs_map_async_setup(ntvfs, req, wr, wr2, 
1279                                        (second_stage_t)ntvfs_map_write_finish);
1280         if (!NT_STATUS_IS_OK(status)) {
1281                 return status;
1282         }
1283
1284         wr2->writex.level = RAW_WRITE_GENERIC;
1285
1286         switch (wr->generic.level) {
1287         case RAW_WRITE_WRITEX:
1288                 status = NT_STATUS_INVALID_LEVEL;
1289                 break;
1290
1291         case RAW_WRITE_WRITE:
1292                 wr2->writex.in.file.ntvfs= wr->write.in.file.ntvfs;
1293                 wr2->writex.in.offset    = wr->write.in.offset;
1294                 wr2->writex.in.wmode     = 0;
1295                 wr2->writex.in.remaining = wr->write.in.remaining;
1296                 wr2->writex.in.count     = wr->write.in.count;
1297                 wr2->writex.in.data      = wr->write.in.data;
1298                 status = ntvfs->ops->write(ntvfs, req, wr2);
1299                 break;
1300
1301         case RAW_WRITE_WRITEUNLOCK:
1302                 wr2->writex.in.file.ntvfs= wr->writeunlock.in.file.ntvfs;
1303                 wr2->writex.in.offset    = wr->writeunlock.in.offset;
1304                 wr2->writex.in.wmode     = 0;
1305                 wr2->writex.in.remaining = wr->writeunlock.in.remaining;
1306                 wr2->writex.in.count     = wr->writeunlock.in.count;
1307                 wr2->writex.in.data      = wr->writeunlock.in.data;
1308                 status = ntvfs->ops->write(ntvfs, req, wr2);
1309                 break;
1310
1311         case RAW_WRITE_WRITECLOSE:
1312                 wr2->writex.in.file.ntvfs= wr->writeclose.in.file.ntvfs;
1313                 wr2->writex.in.offset    = wr->writeclose.in.offset;
1314                 wr2->writex.in.wmode     = 0;
1315                 wr2->writex.in.remaining = 0;
1316                 wr2->writex.in.count     = wr->writeclose.in.count;
1317                 wr2->writex.in.data      = wr->writeclose.in.data;
1318                 status = ntvfs->ops->write(ntvfs, req, wr2);
1319                 break;
1320
1321         case RAW_WRITE_SPLWRITE:
1322                 wr2->writex.in.file.ntvfs= wr->splwrite.in.file.ntvfs;
1323                 wr2->writex.in.offset    = 0;
1324                 wr2->writex.in.wmode     = 0;
1325                 wr2->writex.in.remaining = 0;
1326                 wr2->writex.in.count     = wr->splwrite.in.count;
1327                 wr2->writex.in.data      = wr->splwrite.in.data;
1328                 status = ntvfs->ops->write(ntvfs, req, wr2);
1329                 break;
1330
1331         case RAW_WRITE_SMB2:
1332                 wr2->writex.in.file.ntvfs= wr->smb2.in.file.ntvfs;
1333                 wr2->writex.in.offset    = wr->smb2.in.offset;
1334                 wr2->writex.in.wmode     = 0;
1335                 wr2->writex.in.remaining = 0;
1336                 wr2->writex.in.count     = wr->smb2.in.data.length;
1337                 wr2->writex.in.data      = wr->smb2.in.data.data;
1338                 status = ntvfs->ops->write(ntvfs, req, wr2);
1339         }
1340
1341         return ntvfs_map_async_finish(req, status);
1342 }
1343
1344
1345 /* 
1346    NTVFS read generic to any mapper - finish the out mapping
1347 */
1348 static NTSTATUS ntvfs_map_read_finish(struct ntvfs_module_context *ntvfs,
1349                                       struct ntvfs_request *req, 
1350                                       union smb_read *rd, 
1351                                       union smb_read *rd2,
1352                                       NTSTATUS status)
1353 {
1354         switch (rd->generic.level) {
1355         case RAW_READ_READ:
1356                 rd->read.out.nread      = rd2->generic.out.nread;
1357                 break;
1358         case RAW_READ_READBRAW:
1359                 rd->readbraw.out.nread  = rd2->generic.out.nread;
1360                 break;
1361         case RAW_READ_LOCKREAD:
1362                 rd->lockread.out.nread  = rd2->generic.out.nread;
1363                 break;
1364         case RAW_READ_SMB2:
1365                 rd->smb2.out.data.length= rd2->generic.out.nread;
1366                 rd->smb2.out.remaining  = 0;
1367                 rd->smb2.out.reserved   = 0;
1368                 break;
1369         default:
1370                 return NT_STATUS_INVALID_LEVEL;
1371         }
1372
1373         return status;
1374 }
1375
1376 /* 
1377    NTVFS read* to readx mapper
1378 */
1379 NTSTATUS ntvfs_map_read(struct ntvfs_module_context *ntvfs,
1380                                  struct ntvfs_request *req,
1381                                  union smb_read *rd)
1382 {
1383         union smb_read *rd2;
1384         union smb_lock *lck;
1385         NTSTATUS status;
1386         unsigned int state;
1387
1388         rd2 = talloc(req, union smb_read);
1389         if (rd2 == NULL) {
1390                 return NT_STATUS_NO_MEMORY;
1391         }
1392
1393         status = ntvfs_map_async_setup(ntvfs, req, rd, rd2, 
1394                                        (second_stage_t)ntvfs_map_read_finish);
1395         if (!NT_STATUS_IS_OK(status)) {
1396                 return status;
1397         }
1398
1399         rd2->readx.level = RAW_READ_READX;
1400         rd2->readx.in.read_for_execute = false;
1401
1402         switch (rd->generic.level) {
1403         case RAW_READ_READX:
1404                 status = NT_STATUS_INVALID_LEVEL;
1405                 break;
1406
1407         case RAW_READ_READ:
1408                 rd2->readx.in.file.ntvfs= rd->read.in.file.ntvfs;
1409                 rd2->readx.in.offset    = rd->read.in.offset;
1410                 rd2->readx.in.mincnt    = rd->read.in.count;
1411                 rd2->readx.in.maxcnt    = rd->read.in.count;
1412                 rd2->readx.in.remaining = rd->read.in.remaining;
1413                 rd2->readx.out.data     = rd->read.out.data;
1414                 status = ntvfs->ops->read(ntvfs, req, rd2);
1415                 break;
1416
1417         case RAW_READ_READBRAW:
1418                 rd2->readx.in.file.ntvfs= rd->readbraw.in.file.ntvfs;
1419                 rd2->readx.in.offset    = rd->readbraw.in.offset;
1420                 rd2->readx.in.mincnt    = rd->readbraw.in.mincnt;
1421                 rd2->readx.in.maxcnt    = rd->readbraw.in.maxcnt;
1422                 rd2->readx.in.remaining = 0;
1423                 rd2->readx.out.data     = rd->readbraw.out.data;
1424                 status = ntvfs->ops->read(ntvfs, req, rd2);
1425                 break;
1426
1427         case RAW_READ_LOCKREAD:
1428                 /* do the initial lock sync for now */
1429                 state = req->async_states->state;
1430                 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1431
1432                 lck = talloc(rd2, union smb_lock);
1433                 if (lck == NULL) {
1434                         status = NT_STATUS_NO_MEMORY;
1435                         goto done;
1436                 }
1437                 lck->lock.level         = RAW_LOCK_LOCK;
1438                 lck->lock.in.file.ntvfs = rd->lockread.in.file.ntvfs;
1439                 lck->lock.in.count      = rd->lockread.in.count;
1440                 lck->lock.in.offset     = rd->lockread.in.offset;
1441                 status = ntvfs->ops->lock(ntvfs, req, lck);
1442                 req->async_states->state = state;
1443
1444                 rd2->readx.in.file.ntvfs= rd->lockread.in.file.ntvfs;
1445                 rd2->readx.in.offset    = rd->lockread.in.offset;
1446                 rd2->readx.in.mincnt    = rd->lockread.in.count;
1447                 rd2->readx.in.maxcnt    = rd->lockread.in.count;
1448                 rd2->readx.in.remaining = rd->lockread.in.remaining;
1449                 rd2->readx.out.data     = rd->lockread.out.data;
1450
1451                 if (NT_STATUS_IS_OK(status)) {
1452                         status = ntvfs->ops->read(ntvfs, req, rd2);
1453                 }
1454                 break;
1455
1456         case RAW_READ_SMB2:
1457                 rd2->readx.in.file.ntvfs= rd->smb2.in.file.ntvfs;
1458                 rd2->readx.in.offset    = rd->smb2.in.offset;
1459                 rd2->readx.in.mincnt    = rd->smb2.in.min_count;
1460                 rd2->readx.in.maxcnt    = rd->smb2.in.length;
1461                 rd2->readx.in.remaining = 0;
1462                 rd2->readx.out.data     = rd->smb2.out.data.data;
1463                 status = ntvfs->ops->read(ntvfs, req, rd2);
1464                 break;
1465         }
1466
1467 done:
1468         return ntvfs_map_async_finish(req, status);
1469 }
1470
1471
1472 /* 
1473    NTVFS close generic to any mapper
1474 */
1475 static NTSTATUS ntvfs_map_close_finish(struct ntvfs_module_context *ntvfs,
1476                                         struct ntvfs_request *req,
1477                                         union smb_close *cl, 
1478                                         union smb_close *cl2, 
1479                                         NTSTATUS status)
1480 {
1481         NT_STATUS_NOT_OK_RETURN(status);
1482
1483         switch (cl->generic.level) {
1484         case RAW_CLOSE_SMB2:
1485                 cl->smb2.out.flags        = cl2->generic.out.flags;
1486                 cl->smb2.out._pad         = 0;
1487                 cl->smb2.out.create_time  = cl2->generic.out.create_time;
1488                 cl->smb2.out.access_time  = cl2->generic.out.access_time;
1489                 cl->smb2.out.write_time   = cl2->generic.out.write_time;
1490                 cl->smb2.out.change_time  = cl2->generic.out.change_time;
1491                 cl->smb2.out.alloc_size   = cl2->generic.out.alloc_size;
1492                 cl->smb2.out.size         = cl2->generic.out.size;
1493                 cl->smb2.out.file_attr    = cl2->generic.out.file_attr;
1494                 break;
1495         default:
1496                 break;
1497         }
1498
1499         return status;
1500 }
1501
1502 /* 
1503    NTVFS close generic to any mapper
1504 */
1505 NTSTATUS ntvfs_map_close(struct ntvfs_module_context *ntvfs,
1506                                   struct ntvfs_request *req,
1507                                   union smb_close *cl)
1508 {
1509         union smb_close *cl2;
1510         NTSTATUS status;
1511
1512         cl2 = talloc(req, union smb_close);
1513         if (cl2 == NULL) {
1514                 return NT_STATUS_NO_MEMORY;
1515         }
1516
1517         switch (cl->generic.level) {
1518         case RAW_CLOSE_GENERIC:
1519                 return NT_STATUS_INVALID_LEVEL;
1520
1521         case RAW_CLOSE_CLOSE:
1522                 cl2->generic.level              = RAW_CLOSE_GENERIC;
1523                 cl2->generic.in.file            = cl->close.in.file;
1524                 cl2->generic.in.write_time      = cl->close.in.write_time;
1525                 cl2->generic.in.flags           = 0;
1526                 break;
1527
1528         case RAW_CLOSE_SPLCLOSE:
1529                 cl2->generic.level              = RAW_CLOSE_GENERIC;
1530                 cl2->generic.in.file            = cl->splclose.in.file;
1531                 cl2->generic.in.write_time      = 0;
1532                 cl2->generic.in.flags           = 0;
1533                 break;
1534
1535         case RAW_CLOSE_SMB2:
1536                 cl2->generic.level              = RAW_CLOSE_GENERIC;
1537                 cl2->generic.in.file            = cl->smb2.in.file;
1538                 cl2->generic.in.write_time      = 0;
1539                 cl2->generic.in.flags           = cl->smb2.in.flags;
1540                 break;
1541         }
1542
1543         status = ntvfs_map_async_setup(ntvfs, req, cl, cl2, 
1544                                        (second_stage_t)ntvfs_map_close_finish);
1545         NT_STATUS_NOT_OK_RETURN(status);
1546
1547         status = ntvfs->ops->close(ntvfs, req, cl2);
1548
1549         return ntvfs_map_async_finish(req, status);
1550 }
1551
1552 /* 
1553    NTVFS notify generic to any mapper
1554 */
1555 static NTSTATUS ntvfs_map_notify_finish(struct ntvfs_module_context *ntvfs,
1556                                         struct ntvfs_request *req,
1557                                         union smb_notify *nt, 
1558                                         union smb_notify *nt2, 
1559                                         NTSTATUS status)
1560 {
1561         NT_STATUS_NOT_OK_RETURN(status);
1562
1563         switch (nt->nttrans.level) {
1564         case RAW_NOTIFY_SMB2:
1565                 if (nt2->nttrans.out.num_changes == 0) {
1566                         return STATUS_NOTIFY_ENUM_DIR;
1567                 }
1568                 nt->smb2.out.num_changes        = nt2->nttrans.out.num_changes;
1569                 nt->smb2.out.changes            = talloc_steal(req, nt2->nttrans.out.changes);
1570                 break;
1571
1572         default:
1573                 return NT_STATUS_INVALID_LEVEL;
1574         }
1575
1576         return status;
1577 }
1578
1579
1580 /* 
1581    NTVFS notify generic to any mapper
1582 */
1583 NTSTATUS ntvfs_map_notify(struct ntvfs_module_context *ntvfs,
1584                                    struct ntvfs_request *req,
1585                                    union smb_notify *nt)
1586 {
1587         union smb_notify *nt2;
1588         NTSTATUS status;
1589
1590         nt2 = talloc(req, union smb_notify);
1591         NT_STATUS_HAVE_NO_MEMORY(nt2);
1592
1593         status = ntvfs_map_async_setup(ntvfs, req, nt, nt2, 
1594                                        (second_stage_t)ntvfs_map_notify_finish);
1595         NT_STATUS_NOT_OK_RETURN(status);
1596
1597         nt2->nttrans.level = RAW_NOTIFY_NTTRANS;
1598
1599         switch (nt->nttrans.level) {
1600         case RAW_NOTIFY_NTTRANS:
1601                 status = NT_STATUS_INVALID_LEVEL;
1602                 break;
1603
1604         case RAW_NOTIFY_SMB2:
1605                 nt2->nttrans.in.file.ntvfs              = nt->smb2.in.file.ntvfs;
1606                 nt2->nttrans.in.buffer_size             = nt->smb2.in.buffer_size;
1607                 nt2->nttrans.in.completion_filter       = nt->smb2.in.completion_filter;
1608                 nt2->nttrans.in.recursive               = nt->smb2.in.recursive;
1609                 status = ntvfs->ops->notify(ntvfs, req, nt2);
1610                 break;
1611         }
1612
1613         return ntvfs_map_async_finish(req, status);
1614 }