s4:ntvfs: explicitly handle RAW_FILEINFO_UNIX_{BASIC,LINK} in ntvfs_map_fileinfo()
[samba.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_fn(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_fn(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_fn(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_fn(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_fn(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_fn(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_fn(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_fn(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_fn(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_DSKATTR: {
580                 /* map from generic to DSKATTR */
581                 unsigned int bpunit = 64;
582
583                 /* we need to scale the sizes to fit */
584                 for (bpunit=64; bpunit<0x10000; bpunit *= 2) {
585                         if (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size < bpunit * 512 * 65535.0) {
586                                 break;
587                         }
588                 }
589
590                 fs->dskattr.out.blocks_per_unit = bpunit;
591                 fs->dskattr.out.block_size = 512;
592                 fs->dskattr.out.units_total = 
593                         (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size) / (bpunit * 512);
594                 fs->dskattr.out.units_free  = 
595                         (fs2->generic.out.blocks_free  * (double)fs2->generic.out.block_size) / (bpunit * 512);
596
597                 /* we must return a maximum of 2G to old DOS systems, or they get very confused */
598                 if (bpunit > 64 && req->ctx->protocol <= PROTOCOL_LANMAN2) {
599                         fs->dskattr.out.blocks_per_unit = 64;
600                         fs->dskattr.out.units_total = 0xFFFF;
601                         fs->dskattr.out.units_free = 0xFFFF;
602                 }
603                 return NT_STATUS_OK;
604         }
605
606         case RAW_QFS_ALLOCATION:
607                 fs->allocation.out.fs_id = fs2->generic.out.fs_id;
608                 fs->allocation.out.total_alloc_units = fs2->generic.out.blocks_total;
609                 fs->allocation.out.avail_alloc_units = fs2->generic.out.blocks_free;
610                 fs->allocation.out.sectors_per_unit = 1;
611                 fs->allocation.out.bytes_per_sector = fs2->generic.out.block_size;
612                 return NT_STATUS_OK;
613
614         case RAW_QFS_VOLUME:
615                 fs->volume.out.serial_number = fs2->generic.out.serial_number;
616                 fs->volume.out.volume_name.s = fs2->generic.out.volume_name;
617                 return NT_STATUS_OK;
618
619         case RAW_QFS_VOLUME_INFO:
620         case RAW_QFS_VOLUME_INFORMATION:
621                 fs->volume_info.out.create_time = fs2->generic.out.create_time;
622                 fs->volume_info.out.serial_number = fs2->generic.out.serial_number;
623                 fs->volume_info.out.volume_name.s = fs2->generic.out.volume_name;
624                 return NT_STATUS_OK;
625
626         case RAW_QFS_SIZE_INFO:
627         case RAW_QFS_SIZE_INFORMATION:
628                 fs->size_info.out.total_alloc_units = fs2->generic.out.blocks_total;
629                 fs->size_info.out.avail_alloc_units = fs2->generic.out.blocks_free;
630                 fs->size_info.out.sectors_per_unit = 1;
631                 fs->size_info.out.bytes_per_sector = fs2->generic.out.block_size;
632                 return NT_STATUS_OK;
633
634         case RAW_QFS_DEVICE_INFO:
635         case RAW_QFS_DEVICE_INFORMATION:
636                 fs->device_info.out.device_type = fs2->generic.out.device_type;
637                 fs->device_info.out.characteristics = fs2->generic.out.device_characteristics;
638                 return NT_STATUS_OK;
639
640         case RAW_QFS_ATTRIBUTE_INFO:
641         case RAW_QFS_ATTRIBUTE_INFORMATION:
642                 fs->attribute_info.out.fs_attr = fs2->generic.out.fs_attr;
643                 fs->attribute_info.out.max_file_component_length = fs2->generic.out.max_file_component_length;
644                 fs->attribute_info.out.fs_type.s = fs2->generic.out.fs_type;
645                 return NT_STATUS_OK;
646
647         case RAW_QFS_QUOTA_INFORMATION:
648                 ZERO_STRUCT(fs->quota_information.out.unknown);
649                 fs->quota_information.out.quota_soft = fs2->generic.out.quota_soft;
650                 fs->quota_information.out.quota_hard = fs2->generic.out.quota_hard;
651                 fs->quota_information.out.quota_flags = fs2->generic.out.quota_flags;
652                 return NT_STATUS_OK;
653
654         case RAW_QFS_FULL_SIZE_INFORMATION:
655                 fs->full_size_information.out.total_alloc_units = fs2->generic.out.blocks_total;
656                 fs->full_size_information.out.call_avail_alloc_units = fs2->generic.out.blocks_free;
657                 fs->full_size_information.out.actual_avail_alloc_units = fs2->generic.out.blocks_free;
658                 fs->full_size_information.out.sectors_per_unit = 1;
659                 fs->full_size_information.out.bytes_per_sector = fs2->generic.out.block_size;
660                 return NT_STATUS_OK;
661
662         case RAW_QFS_OBJECTID_INFORMATION:
663                 fs->objectid_information.out.guid = fs2->generic.out.guid;
664                 ZERO_STRUCT(fs->objectid_information.out.unknown);
665                 return NT_STATUS_OK;
666
667         case RAW_QFS_GENERIC:
668         case RAW_QFS_UNIX_INFO:
669                 return NT_STATUS_INVALID_LEVEL;
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_fn(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_GETATTR:
719                 info->getattr.out.attrib = info2->generic.out.attrib & 0xff;
720                 info->getattr.out.size = info2->generic.out.size;
721                 info->getattr.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
722                 return NT_STATUS_OK;
723                 
724         case RAW_FILEINFO_GETATTRE:
725                 info->getattre.out.attrib = info2->generic.out.attrib;
726                 info->getattre.out.size = info2->generic.out.size;
727                 info->getattre.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
728                 info->getattre.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
729                 info->getattre.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
730                 info->getattre.out.alloc_size = info2->generic.out.alloc_size;
731                 return NT_STATUS_OK;
732                 
733         case RAW_FILEINFO_NETWORK_OPEN_INFORMATION:
734                 info->network_open_information.out.create_time = info2->generic.out.create_time;
735                 info->network_open_information.out.access_time = info2->generic.out.access_time;
736                 info->network_open_information.out.write_time =  info2->generic.out.write_time;
737                 info->network_open_information.out.change_time = info2->generic.out.change_time;
738                 info->network_open_information.out.alloc_size = info2->generic.out.alloc_size;
739                 info->network_open_information.out.size = info2->generic.out.size;
740                 info->network_open_information.out.attrib = info2->generic.out.attrib;
741                 return NT_STATUS_OK;
742
743         case RAW_FILEINFO_ALL_INFO:
744         case RAW_FILEINFO_ALL_INFORMATION:
745                 info->all_info.out.create_time = info2->generic.out.create_time;
746                 info->all_info.out.access_time = info2->generic.out.access_time;
747                 info->all_info.out.write_time =  info2->generic.out.write_time;
748                 info->all_info.out.change_time = info2->generic.out.change_time;
749                 info->all_info.out.attrib = info2->generic.out.attrib;
750                 info->all_info.out.alloc_size = info2->generic.out.alloc_size;
751                 info->all_info.out.size = info2->generic.out.size;
752                 info->all_info.out.nlink = info2->generic.out.nlink;
753                 info->all_info.out.delete_pending = info2->generic.out.delete_pending;
754                 info->all_info.out.directory = info2->generic.out.directory;
755                 info->all_info.out.ea_size = info2->generic.out.ea_size;
756                 info->all_info.out.fname.s = info2->generic.out.fname.s;
757                 info->all_info.out.fname.private_length = info2->generic.out.fname.private_length;
758                 return NT_STATUS_OK;
759
760         case RAW_FILEINFO_BASIC_INFO:
761         case RAW_FILEINFO_BASIC_INFORMATION:
762                 info->basic_info.out.create_time = info2->generic.out.create_time;
763                 info->basic_info.out.access_time = info2->generic.out.access_time;
764                 info->basic_info.out.write_time = info2->generic.out.write_time;
765                 info->basic_info.out.change_time = info2->generic.out.change_time;
766                 info->basic_info.out.attrib = info2->generic.out.attrib;
767                 return NT_STATUS_OK;
768
769         case RAW_FILEINFO_STANDARD:
770                 info->standard.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
771                 info->standard.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
772                 info->standard.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
773                 info->standard.out.size = info2->generic.out.size;
774                 info->standard.out.alloc_size = info2->generic.out.alloc_size;
775                 info->standard.out.attrib = info2->generic.out.attrib;
776                 return NT_STATUS_OK;
777
778         case RAW_FILEINFO_EA_SIZE:
779                 info->ea_size.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
780                 info->ea_size.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
781                 info->ea_size.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
782                 info->ea_size.out.size = info2->generic.out.size;
783                 info->ea_size.out.alloc_size = info2->generic.out.alloc_size;
784                 info->ea_size.out.attrib = info2->generic.out.attrib;
785                 info->ea_size.out.ea_size = info2->generic.out.ea_size;
786                 return NT_STATUS_OK;
787
788         case RAW_FILEINFO_STANDARD_INFO:
789         case RAW_FILEINFO_STANDARD_INFORMATION:
790                 info->standard_info.out.alloc_size = info2->generic.out.alloc_size;
791                 info->standard_info.out.size = info2->generic.out.size;
792                 info->standard_info.out.nlink = info2->generic.out.nlink;
793                 info->standard_info.out.delete_pending = info2->generic.out.delete_pending;
794                 info->standard_info.out.directory = info2->generic.out.directory;
795                 return NT_STATUS_OK;
796
797         case RAW_FILEINFO_INTERNAL_INFORMATION:
798                 info->internal_information.out.file_id = info2->generic.out.file_id;
799                 return NT_STATUS_OK;
800
801         case RAW_FILEINFO_EA_INFO:
802         case RAW_FILEINFO_EA_INFORMATION:
803                 info->ea_info.out.ea_size = info2->generic.out.ea_size;
804                 return NT_STATUS_OK;
805
806         case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION:
807                 info->attribute_tag_information.out.attrib = info2->generic.out.attrib;
808                 info->attribute_tag_information.out.reparse_tag = info2->generic.out.reparse_tag;
809                 return NT_STATUS_OK;
810
811         case RAW_FILEINFO_STREAM_INFO:
812         case RAW_FILEINFO_STREAM_INFORMATION:
813                 info->stream_info.out.num_streams = info2->generic.out.num_streams;
814                 if (info->stream_info.out.num_streams > 0) {
815                         info->stream_info.out.streams = 
816                                 talloc_array(mem_ctx, 
817                                                struct stream_struct,
818                                                info->stream_info.out.num_streams);
819                         if (!info->stream_info.out.streams) {
820                                 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d streams\n",
821                                         info->stream_info.out.num_streams));
822                                 return NT_STATUS_NO_MEMORY;
823                         }
824                         for (i=0; i < info->stream_info.out.num_streams; i++) {
825                                 info->stream_info.out.streams[i] = info2->generic.out.streams[i];
826                                 info->stream_info.out.streams[i].stream_name.s = 
827                                         talloc_strdup(info->stream_info.out.streams,
828                                                       info2->generic.out.streams[i].stream_name.s);
829                                 if (!info->stream_info.out.streams[i].stream_name.s) {
830                                         DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
831                                         return NT_STATUS_NO_MEMORY;
832                                 }
833                         }
834                 }
835                 return NT_STATUS_OK;
836
837         case RAW_FILEINFO_NAME_INFO:
838         case RAW_FILEINFO_NAME_INFORMATION:
839                 info->name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.fname.s);
840                 NT_STATUS_HAVE_NO_MEMORY(info->name_info.out.fname.s);
841                 info->name_info.out.fname.private_length = info2->generic.out.fname.private_length;
842                 return NT_STATUS_OK;
843                 
844         case RAW_FILEINFO_ALT_NAME_INFO:
845         case RAW_FILEINFO_ALT_NAME_INFORMATION:
846                 info->alt_name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.alt_fname.s);
847                 NT_STATUS_HAVE_NO_MEMORY(info->alt_name_info.out.fname.s);
848                 info->alt_name_info.out.fname.private_length = info2->generic.out.alt_fname.private_length;
849                 return NT_STATUS_OK;
850         
851         case RAW_FILEINFO_POSITION_INFORMATION:
852                 info->position_information.out.position = info2->generic.out.position;
853                 return NT_STATUS_OK;
854         
855         case RAW_FILEINFO_ALL_EAS:
856                 info->all_eas.out.num_eas = info2->generic.out.num_eas;
857                 if (info->all_eas.out.num_eas > 0) {
858                         info->all_eas.out.eas = talloc_array(mem_ctx, 
859                                                                struct ea_struct,
860                                                                info->all_eas.out.num_eas);
861                         if (!info->all_eas.out.eas) {
862                                 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d eas\n",
863                                         info->all_eas.out.num_eas));
864                                 return NT_STATUS_NO_MEMORY;
865                         }
866                         for (i = 0; i < info->all_eas.out.num_eas; i++) {
867                                 info->all_eas.out.eas[i] = info2->generic.out.eas[i];
868                                 info->all_eas.out.eas[i].name.s = 
869                                         talloc_strdup(info->all_eas.out.eas,
870                                                       info2->generic.out.eas[i].name.s);
871                                 if (!info->all_eas.out.eas[i].name.s) {
872                                         DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
873                                         return NT_STATUS_NO_MEMORY;
874                                 }
875                                 info->all_eas.out.eas[i].value.data = 
876                                         (uint8_t *)talloc_memdup(info->all_eas.out.eas,
877                                                 info2->generic.out.eas[i].value.data,
878                                                 info2->generic.out.eas[i].value.length);
879                                 if (!info->all_eas.out.eas[i].value.data) {
880                                         DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
881                                         return NT_STATUS_NO_MEMORY;
882                                 }
883                         }
884                 }
885                 return NT_STATUS_OK;
886                 
887         case RAW_FILEINFO_IS_NAME_VALID:
888                 return NT_STATUS_OK;
889                 
890         case RAW_FILEINFO_COMPRESSION_INFO:
891         case RAW_FILEINFO_COMPRESSION_INFORMATION:
892                 info->compression_info.out.compressed_size = info2->generic.out.compressed_size;
893                 info->compression_info.out.format = info2->generic.out.format;
894                 info->compression_info.out.unit_shift = info2->generic.out.unit_shift;
895                 info->compression_info.out.chunk_shift = info2->generic.out.chunk_shift;
896                 info->compression_info.out.cluster_shift = info2->generic.out.cluster_shift;
897                 return NT_STATUS_OK;
898                 
899         case RAW_FILEINFO_ACCESS_INFORMATION:
900                 info->access_information.out.access_flags = info2->generic.out.access_flags;
901                 return NT_STATUS_OK;
902                 
903         case RAW_FILEINFO_MODE_INFORMATION:
904                 info->mode_information.out.mode = info2->generic.out.mode;
905                 return NT_STATUS_OK;
906                 
907         case RAW_FILEINFO_ALIGNMENT_INFORMATION:
908                 info->alignment_information.out.alignment_requirement =
909                         info2->generic.out.alignment_requirement;
910                 return NT_STATUS_OK;
911         case RAW_FILEINFO_UNIX_BASIC:
912 #if 1
913                 return NT_STATUS_INVALID_LEVEL;
914 #else
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 #endif
930         case RAW_FILEINFO_UNIX_LINK:
931 #if 1
932                 return NT_STATUS_INVALID_LEVEL;
933 #else
934                 info->unix_link_info.out.link_dest = info2->generic.out.link_dest;
935                 return NT_STATUS_OK;
936 #endif
937         case RAW_FILEINFO_GENERIC:
938         case RAW_FILEINFO_SEC_DESC:
939         case RAW_FILEINFO_EA_LIST:
940         case RAW_FILEINFO_UNIX_INFO2:
941         case RAW_FILEINFO_SMB2_ALL_EAS:
942         case RAW_FILEINFO_SMB2_ALL_INFORMATION:
943                 return NT_STATUS_INVALID_LEVEL;
944         }
945
946         return NT_STATUS_INVALID_LEVEL;
947 }
948
949 /* 
950    NTVFS any to fileinfo mapper
951 */
952 static NTSTATUS ntvfs_map_qfileinfo_finish(struct ntvfs_module_context *ntvfs,
953                                       struct ntvfs_request *req,
954                                       union smb_fileinfo *info,
955                                       union smb_fileinfo *info2,
956                                       NTSTATUS status)
957 {
958         if (!NT_STATUS_IS_OK(status)) {
959                 return status;
960         }
961
962         return ntvfs_map_fileinfo(req, info, info2);
963 }
964
965 /*
966    NTVFS fileinfo generic to any mapper
967 */
968 NTSTATUS ntvfs_map_qfileinfo(struct ntvfs_module_context *ntvfs,
969                                       struct ntvfs_request *req,
970                                       union smb_fileinfo *info)
971 {
972         NTSTATUS status;
973         union smb_fileinfo *info2;
974
975         info2 = talloc(req, union smb_fileinfo);
976         if (info2 == NULL) {
977                 return NT_STATUS_NO_MEMORY;
978         }
979
980         if (info->generic.level == RAW_FILEINFO_GENERIC) {
981                 return NT_STATUS_INVALID_LEVEL;
982         }
983
984         status = ntvfs_map_async_setup(ntvfs, req, info, info2,
985                                        (second_stage_t)ntvfs_map_qfileinfo_finish);
986         if (!NT_STATUS_IS_OK(status)) {
987                 return status;
988         }
989
990         /* ask the backend for the generic info */
991         info2->generic.level = RAW_FILEINFO_GENERIC;
992         info2->generic.in.file.ntvfs= info->generic.in.file.ntvfs;
993
994         status = ntvfs->ops->qfileinfo_fn(ntvfs, req, info2);
995         return ntvfs_map_async_finish(req, status);
996 }
997
998 /*
999    NTVFS any to fileinfo mapper
1000 */
1001 static NTSTATUS ntvfs_map_qpathinfo_finish(struct ntvfs_module_context *ntvfs,
1002                                       struct ntvfs_request *req,
1003                                       union smb_fileinfo *info,
1004                                       union smb_fileinfo *info2,
1005                                       NTSTATUS status)
1006 {
1007         if (!NT_STATUS_IS_OK(status)) {
1008                 return status;
1009         }
1010
1011         return ntvfs_map_fileinfo(req, info, info2);
1012 }
1013
1014 /* 
1015    NTVFS pathinfo generic to any mapper
1016 */
1017 NTSTATUS ntvfs_map_qpathinfo(struct ntvfs_module_context *ntvfs,
1018                                       struct ntvfs_request *req,
1019                                       union smb_fileinfo *info)
1020 {
1021         NTSTATUS status;
1022         union smb_fileinfo *info2;
1023
1024         info2 = talloc(req, union smb_fileinfo);
1025         if (info2 == NULL) {
1026                 return NT_STATUS_NO_MEMORY;
1027         }
1028
1029         if (info->generic.level == RAW_FILEINFO_GENERIC) {
1030                 return NT_STATUS_INVALID_LEVEL;
1031         }
1032
1033         status = ntvfs_map_async_setup(ntvfs, req, info, info2,
1034                                        (second_stage_t)ntvfs_map_qpathinfo_finish);
1035         if (!NT_STATUS_IS_OK(status)) {
1036                 return status;
1037         }
1038
1039         /* ask the backend for the generic info */
1040         info2->generic.level            = RAW_FILEINFO_GENERIC;
1041         info2->generic.in.file.path     = info->generic.in.file.path;
1042
1043         status = ntvfs->ops->qpathinfo_fn(ntvfs, req, info2);
1044         return ntvfs_map_async_finish(req, status);
1045 }
1046
1047
1048 /* 
1049    NTVFS lock generic to any mapper
1050 */
1051 NTSTATUS ntvfs_map_lock(struct ntvfs_module_context *ntvfs,
1052                         struct ntvfs_request *req,
1053                         union smb_lock *lck)
1054 {
1055         union smb_lock *lck2;
1056         struct smb_lock_entry *locks;
1057
1058         lck2 = talloc(req, union smb_lock);
1059         if (lck2 == NULL) {
1060                 return NT_STATUS_NO_MEMORY;
1061         }
1062
1063         locks = talloc_array(lck2, struct smb_lock_entry, 1);
1064         if (locks == NULL) {
1065                 return NT_STATUS_NO_MEMORY;
1066         }
1067
1068         switch (lck->generic.level) {
1069         case RAW_LOCK_LOCKX:
1070                 return NT_STATUS_INVALID_LEVEL;
1071
1072         case RAW_LOCK_LOCK:
1073                 lck2->generic.level = RAW_LOCK_GENERIC;
1074                 lck2->generic.in.file.ntvfs= lck->lock.in.file.ntvfs;
1075                 lck2->generic.in.mode = 0;
1076                 lck2->generic.in.timeout = 0;
1077                 lck2->generic.in.ulock_cnt = 0;
1078                 lck2->generic.in.lock_cnt = 1;
1079                 lck2->generic.in.locks = locks;
1080                 locks->pid = req->smbpid;
1081                 locks->offset = lck->lock.in.offset;
1082                 locks->count = lck->lock.in.count;
1083                 break;
1084
1085         case RAW_LOCK_UNLOCK:
1086                 lck2->generic.level = RAW_LOCK_GENERIC;
1087                 lck2->generic.in.file.ntvfs= lck->unlock.in.file.ntvfs;
1088                 lck2->generic.in.mode = 0;
1089                 lck2->generic.in.timeout = 0;
1090                 lck2->generic.in.ulock_cnt = 1;
1091                 lck2->generic.in.lock_cnt = 0;
1092                 lck2->generic.in.locks = locks;
1093                 locks->pid = req->smbpid;
1094                 locks->offset = lck->unlock.in.offset;
1095                 locks->count = lck->unlock.in.count;
1096                 break;
1097
1098         case RAW_LOCK_SMB2: {
1099                 /* this is only approximate! We need to change the
1100                    generic structure to fix this properly */
1101                 int i;
1102                 bool isunlock;
1103                 if (lck->smb2.in.lock_count < 1) {
1104                         return NT_STATUS_INVALID_PARAMETER;
1105                 }
1106
1107                 lck2->generic.level = RAW_LOCK_GENERIC;
1108                 lck2->generic.in.file.ntvfs= lck->smb2.in.file.ntvfs;
1109                 lck2->generic.in.timeout = UINT32_MAX;
1110                 lck2->generic.in.mode = 0;
1111                 lck2->generic.in.lock_cnt = 0;
1112                 lck2->generic.in.ulock_cnt = 0;
1113                 lck2->generic.in.locks = talloc_zero_array(lck2, struct smb_lock_entry, 
1114                                                            lck->smb2.in.lock_count);
1115                 if (lck2->generic.in.locks == NULL) {
1116                         return NT_STATUS_NO_MEMORY;
1117                 }
1118                 /* only the first lock gives the UNLOCK bit - see
1119                    MS-SMB2 3.3.5.14 */
1120                 if (lck->smb2.in.locks[0].flags & SMB2_LOCK_FLAG_UNLOCK) {
1121                         if (lck->smb2.in.locks[0].flags & SMB2_LOCK_FLAG_FAIL_IMMEDIATELY) {
1122                                 return NT_STATUS_INVALID_PARAMETER;
1123                         }
1124                         lck2->generic.in.ulock_cnt = lck->smb2.in.lock_count;
1125                         isunlock = true;
1126                 } else {
1127                         lck2->generic.in.lock_cnt = lck->smb2.in.lock_count;
1128                         isunlock = false;
1129                 }
1130                 for (i=0;i<lck->smb2.in.lock_count;i++) {
1131                         if (!isunlock &&
1132                             lck->smb2.in.locks[i].flags == SMB2_LOCK_FLAG_NONE) {
1133                                 return NT_STATUS_INVALID_PARAMETER;
1134                         }
1135
1136                         if (lck->smb2.in.locks[i].flags & ~SMB2_LOCK_FLAG_ALL_MASK) {
1137                                 return NT_STATUS_INVALID_PARAMETER;
1138                         }
1139
1140                         if (isunlock && 
1141                             (lck->smb2.in.locks[i].flags & 
1142                              (SMB2_LOCK_FLAG_SHARED|SMB2_LOCK_FLAG_EXCLUSIVE))) {
1143                                 return NT_STATUS_INVALID_PARAMETER;
1144                         }
1145                         if (!isunlock && 
1146                             (lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_UNLOCK)) {
1147                                 return NT_STATUS_INVALID_PARAMETER;
1148                         }
1149                         lck2->generic.in.locks[i].pid    = req->smbpid;
1150                         lck2->generic.in.locks[i].offset = lck->smb2.in.locks[i].offset;
1151                         lck2->generic.in.locks[i].count  = lck->smb2.in.locks[i].length;
1152                         if (!(lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_EXCLUSIVE)) {
1153                                 lck2->generic.in.mode = LOCKING_ANDX_SHARED_LOCK;
1154                         }
1155                         if (lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_FAIL_IMMEDIATELY) {
1156                                 lck2->generic.in.timeout = 0;
1157                         }
1158                 }
1159                 /* initialize output value */
1160                 lck->smb2.out.reserved = 0;
1161                 break;
1162         }
1163
1164         case RAW_LOCK_SMB2_BREAK:
1165                 lck2->generic.level             = RAW_LOCK_GENERIC;
1166                 lck2->generic.in.file.ntvfs     = lck->smb2_break.in.file.ntvfs;
1167                 lck2->generic.in.mode           = LOCKING_ANDX_OPLOCK_RELEASE |
1168                                                   ((lck->smb2_break.in.oplock_level << 8) & 0xFF00);
1169                 lck2->generic.in.timeout        = 0;
1170                 lck2->generic.in.ulock_cnt      = 0;
1171                 lck2->generic.in.lock_cnt       = 0;
1172                 lck2->generic.in.locks          = NULL;
1173
1174                 /* initialize output value */
1175                 lck->smb2_break.out.oplock_level= lck->smb2_break.in.oplock_level;
1176                 lck->smb2_break.out.reserved    = lck->smb2_break.in.reserved;
1177                 lck->smb2_break.out.reserved2   = lck->smb2_break.in.reserved2;
1178                 lck->smb2_break.out.file        = lck->smb2_break.in.file;
1179                 break;
1180         }
1181
1182         /* 
1183          * we don't need to call ntvfs_map_async_setup() here,
1184          * as lock() doesn't have any output fields
1185          */
1186
1187         return ntvfs->ops->lock_fn(ntvfs, req, lck2);
1188 }
1189
1190
1191 /* 
1192    NTVFS write generic to any mapper
1193 */
1194 static NTSTATUS ntvfs_map_write_finish(struct ntvfs_module_context *ntvfs,
1195                                        struct ntvfs_request *req,
1196                                        union smb_write *wr, 
1197                                        union smb_write *wr2, 
1198                                        NTSTATUS status)
1199 {
1200         union smb_lock *lck;
1201         union smb_close *cl;
1202         unsigned int state;
1203
1204         if (NT_STATUS_IS_ERR(status)) {
1205                 return status;
1206         }
1207
1208         switch (wr->generic.level) {
1209         case RAW_WRITE_WRITE:
1210                 wr->write.out.nwritten    = wr2->generic.out.nwritten;
1211                 break;
1212
1213         case RAW_WRITE_WRITEUNLOCK:
1214                 wr->writeunlock.out.nwritten = wr2->generic.out.nwritten;
1215
1216                 lck = talloc(wr2, union smb_lock);
1217                 if (lck == NULL) {
1218                         return NT_STATUS_NO_MEMORY;
1219                 }
1220
1221                 lck->unlock.level               = RAW_LOCK_UNLOCK;
1222                 lck->unlock.in.file.ntvfs       = wr->writeunlock.in.file.ntvfs;
1223                 lck->unlock.in.count            = wr->writeunlock.in.count;
1224                 lck->unlock.in.offset           = wr->writeunlock.in.offset;
1225
1226                 if (lck->unlock.in.count != 0) {
1227                         /* do the lock sync for now */
1228                         state = req->async_states->state;
1229                         req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1230                         status = ntvfs->ops->lock_fn(ntvfs, req, lck);
1231                         req->async_states->state = state;
1232                 }
1233                 break;
1234
1235         case RAW_WRITE_WRITECLOSE:
1236                 wr->writeclose.out.nwritten    = wr2->generic.out.nwritten;
1237
1238                 cl = talloc(wr2, union smb_close);
1239                 if (cl == NULL) {
1240                         return NT_STATUS_NO_MEMORY;
1241                 }
1242
1243                 cl->close.level         = RAW_CLOSE_CLOSE;
1244                 cl->close.in.file.ntvfs = wr->writeclose.in.file.ntvfs;
1245                 cl->close.in.write_time = wr->writeclose.in.mtime;
1246
1247                 if (wr2->generic.in.count != 0) {
1248                         /* do the close sync for now */
1249                         state = req->async_states->state;
1250                         req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1251                         status = ntvfs->ops->close_fn(ntvfs, req, cl);
1252                         req->async_states->state = state;
1253                 }
1254                 break;
1255
1256         case RAW_WRITE_SPLWRITE:
1257                 break;
1258
1259         case RAW_WRITE_SMB2:
1260                 wr->smb2.out._pad       = 0;
1261                 wr->smb2.out.nwritten   = wr2->generic.out.nwritten;
1262                 wr->smb2.out.unknown1   = 0;
1263                 break;
1264
1265         default:
1266                 return NT_STATUS_INVALID_LEVEL;
1267         }
1268
1269         return status;
1270 }
1271
1272
1273 /* 
1274    NTVFS write generic to any mapper
1275 */
1276 NTSTATUS ntvfs_map_write(struct ntvfs_module_context *ntvfs,
1277                                   struct ntvfs_request *req,
1278                                   union smb_write *wr)
1279 {
1280         union smb_write *wr2;
1281         NTSTATUS status;
1282
1283         wr2 = talloc(req, union smb_write);
1284         if (wr2 == NULL) {
1285                 return NT_STATUS_NO_MEMORY;
1286         }
1287
1288         status = ntvfs_map_async_setup(ntvfs, req, wr, wr2, 
1289                                        (second_stage_t)ntvfs_map_write_finish);
1290         if (!NT_STATUS_IS_OK(status)) {
1291                 return status;
1292         }
1293
1294         wr2->writex.level = RAW_WRITE_GENERIC;
1295
1296         switch (wr->generic.level) {
1297         case RAW_WRITE_WRITEX:
1298                 status = NT_STATUS_INVALID_LEVEL;
1299                 break;
1300
1301         case RAW_WRITE_WRITE:
1302                 wr2->writex.in.file.ntvfs= wr->write.in.file.ntvfs;
1303                 wr2->writex.in.offset    = wr->write.in.offset;
1304                 wr2->writex.in.wmode     = 0;
1305                 wr2->writex.in.remaining = wr->write.in.remaining;
1306                 wr2->writex.in.count     = wr->write.in.count;
1307                 wr2->writex.in.data      = wr->write.in.data;
1308                 status = ntvfs->ops->write_fn(ntvfs, req, wr2);
1309                 break;
1310
1311         case RAW_WRITE_WRITEUNLOCK:
1312                 wr2->writex.in.file.ntvfs= wr->writeunlock.in.file.ntvfs;
1313                 wr2->writex.in.offset    = wr->writeunlock.in.offset;
1314                 wr2->writex.in.wmode     = 0;
1315                 wr2->writex.in.remaining = wr->writeunlock.in.remaining;
1316                 wr2->writex.in.count     = wr->writeunlock.in.count;
1317                 wr2->writex.in.data      = wr->writeunlock.in.data;
1318                 status = ntvfs->ops->write_fn(ntvfs, req, wr2);
1319                 break;
1320
1321         case RAW_WRITE_WRITECLOSE:
1322                 wr2->writex.in.file.ntvfs= wr->writeclose.in.file.ntvfs;
1323                 wr2->writex.in.offset    = wr->writeclose.in.offset;
1324                 wr2->writex.in.wmode     = 0;
1325                 wr2->writex.in.remaining = 0;
1326                 wr2->writex.in.count     = wr->writeclose.in.count;
1327                 wr2->writex.in.data      = wr->writeclose.in.data;
1328                 status = ntvfs->ops->write_fn(ntvfs, req, wr2);
1329                 break;
1330
1331         case RAW_WRITE_SPLWRITE:
1332                 wr2->writex.in.file.ntvfs= wr->splwrite.in.file.ntvfs;
1333                 wr2->writex.in.offset    = 0;
1334                 wr2->writex.in.wmode     = 0;
1335                 wr2->writex.in.remaining = 0;
1336                 wr2->writex.in.count     = wr->splwrite.in.count;
1337                 wr2->writex.in.data      = wr->splwrite.in.data;
1338                 status = ntvfs->ops->write_fn(ntvfs, req, wr2);
1339                 break;
1340
1341         case RAW_WRITE_SMB2:
1342                 wr2->writex.in.file.ntvfs= wr->smb2.in.file.ntvfs;
1343                 wr2->writex.in.offset    = wr->smb2.in.offset;
1344                 wr2->writex.in.wmode     = 0;
1345                 wr2->writex.in.remaining = 0;
1346                 wr2->writex.in.count     = wr->smb2.in.data.length;
1347                 wr2->writex.in.data      = wr->smb2.in.data.data;
1348                 status = ntvfs->ops->write_fn(ntvfs, req, wr2);
1349         }
1350
1351         return ntvfs_map_async_finish(req, status);
1352 }
1353
1354
1355 /* 
1356    NTVFS read generic to any mapper - finish the out mapping
1357 */
1358 static NTSTATUS ntvfs_map_read_finish(struct ntvfs_module_context *ntvfs,
1359                                       struct ntvfs_request *req, 
1360                                       union smb_read *rd, 
1361                                       union smb_read *rd2,
1362                                       NTSTATUS status)
1363 {
1364         switch (rd->generic.level) {
1365         case RAW_READ_READ:
1366                 rd->read.out.nread      = rd2->generic.out.nread;
1367                 break;
1368         case RAW_READ_READBRAW:
1369                 rd->readbraw.out.nread  = rd2->generic.out.nread;
1370                 break;
1371         case RAW_READ_LOCKREAD:
1372                 rd->lockread.out.nread  = rd2->generic.out.nread;
1373                 break;
1374         case RAW_READ_SMB2:
1375                 rd->smb2.out.data.length= rd2->generic.out.nread;
1376                 rd->smb2.out.remaining  = 0;
1377                 rd->smb2.out.reserved   = 0;
1378                 break;
1379         default:
1380                 return NT_STATUS_INVALID_LEVEL;
1381         }
1382
1383         return status;
1384 }
1385
1386 /* 
1387    NTVFS read* to readx mapper
1388 */
1389 NTSTATUS ntvfs_map_read(struct ntvfs_module_context *ntvfs,
1390                                  struct ntvfs_request *req,
1391                                  union smb_read *rd)
1392 {
1393         union smb_read *rd2;
1394         union smb_lock *lck;
1395         NTSTATUS status;
1396         unsigned int state;
1397
1398         rd2 = talloc(req, union smb_read);
1399         if (rd2 == NULL) {
1400                 return NT_STATUS_NO_MEMORY;
1401         }
1402
1403         status = ntvfs_map_async_setup(ntvfs, req, rd, rd2, 
1404                                        (second_stage_t)ntvfs_map_read_finish);
1405         if (!NT_STATUS_IS_OK(status)) {
1406                 return status;
1407         }
1408
1409         rd2->readx.level = RAW_READ_READX;
1410         rd2->readx.in.read_for_execute = false;
1411
1412         switch (rd->generic.level) {
1413         case RAW_READ_READX:
1414                 status = NT_STATUS_INVALID_LEVEL;
1415                 break;
1416
1417         case RAW_READ_READ:
1418                 rd2->readx.in.file.ntvfs= rd->read.in.file.ntvfs;
1419                 rd2->readx.in.offset    = rd->read.in.offset;
1420                 rd2->readx.in.mincnt    = rd->read.in.count;
1421                 rd2->readx.in.maxcnt    = rd->read.in.count;
1422                 rd2->readx.in.remaining = rd->read.in.remaining;
1423                 rd2->readx.out.data     = rd->read.out.data;
1424                 status = ntvfs->ops->read_fn(ntvfs, req, rd2);
1425                 break;
1426
1427         case RAW_READ_READBRAW:
1428                 rd2->readx.in.file.ntvfs= rd->readbraw.in.file.ntvfs;
1429                 rd2->readx.in.offset    = rd->readbraw.in.offset;
1430                 rd2->readx.in.mincnt    = rd->readbraw.in.mincnt;
1431                 rd2->readx.in.maxcnt    = rd->readbraw.in.maxcnt;
1432                 rd2->readx.in.remaining = 0;
1433                 rd2->readx.out.data     = rd->readbraw.out.data;
1434                 status = ntvfs->ops->read_fn(ntvfs, req, rd2);
1435                 break;
1436
1437         case RAW_READ_LOCKREAD:
1438                 /* do the initial lock sync for now */
1439                 state = req->async_states->state;
1440                 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1441
1442                 lck = talloc(rd2, union smb_lock);
1443                 if (lck == NULL) {
1444                         status = NT_STATUS_NO_MEMORY;
1445                         goto done;
1446                 }
1447                 lck->lock.level         = RAW_LOCK_LOCK;
1448                 lck->lock.in.file.ntvfs = rd->lockread.in.file.ntvfs;
1449                 lck->lock.in.count      = rd->lockread.in.count;
1450                 lck->lock.in.offset     = rd->lockread.in.offset;
1451                 status = ntvfs->ops->lock_fn(ntvfs, req, lck);
1452                 req->async_states->state = state;
1453
1454                 rd2->readx.in.file.ntvfs= rd->lockread.in.file.ntvfs;
1455                 rd2->readx.in.offset    = rd->lockread.in.offset;
1456                 rd2->readx.in.mincnt    = rd->lockread.in.count;
1457                 rd2->readx.in.maxcnt    = rd->lockread.in.count;
1458                 rd2->readx.in.remaining = rd->lockread.in.remaining;
1459                 rd2->readx.out.data     = rd->lockread.out.data;
1460
1461                 if (NT_STATUS_IS_OK(status)) {
1462                         status = ntvfs->ops->read_fn(ntvfs, req, rd2);
1463                 }
1464                 break;
1465
1466         case RAW_READ_SMB2:
1467                 rd2->readx.in.file.ntvfs= rd->smb2.in.file.ntvfs;
1468                 rd2->readx.in.offset    = rd->smb2.in.offset;
1469                 rd2->readx.in.mincnt    = rd->smb2.in.min_count;
1470                 rd2->readx.in.maxcnt    = rd->smb2.in.length;
1471                 rd2->readx.in.remaining = 0;
1472                 rd2->readx.out.data     = rd->smb2.out.data.data;
1473                 status = ntvfs->ops->read_fn(ntvfs, req, rd2);
1474                 break;
1475         }
1476
1477 done:
1478         return ntvfs_map_async_finish(req, status);
1479 }
1480
1481
1482 /* 
1483    NTVFS close generic to any mapper
1484 */
1485 static NTSTATUS ntvfs_map_close_finish(struct ntvfs_module_context *ntvfs,
1486                                         struct ntvfs_request *req,
1487                                         union smb_close *cl, 
1488                                         union smb_close *cl2, 
1489                                         NTSTATUS status)
1490 {
1491         NT_STATUS_NOT_OK_RETURN(status);
1492
1493         switch (cl->generic.level) {
1494         case RAW_CLOSE_SMB2:
1495                 cl->smb2.out.flags        = cl2->generic.out.flags;
1496                 cl->smb2.out._pad         = 0;
1497                 cl->smb2.out.create_time  = cl2->generic.out.create_time;
1498                 cl->smb2.out.access_time  = cl2->generic.out.access_time;
1499                 cl->smb2.out.write_time   = cl2->generic.out.write_time;
1500                 cl->smb2.out.change_time  = cl2->generic.out.change_time;
1501                 cl->smb2.out.alloc_size   = cl2->generic.out.alloc_size;
1502                 cl->smb2.out.size         = cl2->generic.out.size;
1503                 cl->smb2.out.file_attr    = cl2->generic.out.file_attr;
1504                 break;
1505         default:
1506                 break;
1507         }
1508
1509         return status;
1510 }
1511
1512 /* 
1513    NTVFS close generic to any mapper
1514 */
1515 NTSTATUS ntvfs_map_close(struct ntvfs_module_context *ntvfs,
1516                                   struct ntvfs_request *req,
1517                                   union smb_close *cl)
1518 {
1519         union smb_close *cl2;
1520         NTSTATUS status;
1521
1522         cl2 = talloc(req, union smb_close);
1523         if (cl2 == NULL) {
1524                 return NT_STATUS_NO_MEMORY;
1525         }
1526
1527         switch (cl->generic.level) {
1528         case RAW_CLOSE_GENERIC:
1529                 return NT_STATUS_INVALID_LEVEL;
1530
1531         case RAW_CLOSE_CLOSE:
1532                 cl2->generic.level              = RAW_CLOSE_GENERIC;
1533                 cl2->generic.in.file            = cl->close.in.file;
1534                 cl2->generic.in.write_time      = cl->close.in.write_time;
1535                 cl2->generic.in.flags           = 0;
1536                 break;
1537
1538         case RAW_CLOSE_SPLCLOSE:
1539                 cl2->generic.level              = RAW_CLOSE_GENERIC;
1540                 cl2->generic.in.file            = cl->splclose.in.file;
1541                 cl2->generic.in.write_time      = 0;
1542                 cl2->generic.in.flags           = 0;
1543                 break;
1544
1545         case RAW_CLOSE_SMB2:
1546                 cl2->generic.level              = RAW_CLOSE_GENERIC;
1547                 cl2->generic.in.file            = cl->smb2.in.file;
1548                 cl2->generic.in.write_time      = 0;
1549                 cl2->generic.in.flags           = cl->smb2.in.flags;
1550                 break;
1551         }
1552
1553         status = ntvfs_map_async_setup(ntvfs, req, cl, cl2, 
1554                                        (second_stage_t)ntvfs_map_close_finish);
1555         NT_STATUS_NOT_OK_RETURN(status);
1556
1557         status = ntvfs->ops->close_fn(ntvfs, req, cl2);
1558
1559         return ntvfs_map_async_finish(req, status);
1560 }
1561
1562 /* 
1563    NTVFS notify generic to any mapper
1564 */
1565 static NTSTATUS ntvfs_map_notify_finish(struct ntvfs_module_context *ntvfs,
1566                                         struct ntvfs_request *req,
1567                                         union smb_notify *nt, 
1568                                         union smb_notify *nt2, 
1569                                         NTSTATUS status)
1570 {
1571         NT_STATUS_NOT_OK_RETURN(status);
1572
1573         switch (nt->nttrans.level) {
1574         case RAW_NOTIFY_SMB2:
1575                 if (nt2->nttrans.out.num_changes == 0) {
1576                         return STATUS_NOTIFY_ENUM_DIR;
1577                 }
1578                 nt->smb2.out.num_changes        = nt2->nttrans.out.num_changes;
1579                 nt->smb2.out.changes            = talloc_steal(req, nt2->nttrans.out.changes);
1580                 break;
1581
1582         default:
1583                 return NT_STATUS_INVALID_LEVEL;
1584         }
1585
1586         return status;
1587 }
1588
1589
1590 /* 
1591    NTVFS notify generic to any mapper
1592 */
1593 NTSTATUS ntvfs_map_notify(struct ntvfs_module_context *ntvfs,
1594                                    struct ntvfs_request *req,
1595                                    union smb_notify *nt)
1596 {
1597         union smb_notify *nt2;
1598         NTSTATUS status;
1599
1600         nt2 = talloc(req, union smb_notify);
1601         NT_STATUS_HAVE_NO_MEMORY(nt2);
1602
1603         status = ntvfs_map_async_setup(ntvfs, req, nt, nt2, 
1604                                        (second_stage_t)ntvfs_map_notify_finish);
1605         NT_STATUS_NOT_OK_RETURN(status);
1606
1607         nt2->nttrans.level = RAW_NOTIFY_NTTRANS;
1608
1609         switch (nt->nttrans.level) {
1610         case RAW_NOTIFY_NTTRANS:
1611                 status = NT_STATUS_INVALID_LEVEL;
1612                 break;
1613
1614         case RAW_NOTIFY_SMB2:
1615                 nt2->nttrans.in.file.ntvfs              = nt->smb2.in.file.ntvfs;
1616                 nt2->nttrans.in.buffer_size             = nt->smb2.in.buffer_size;
1617                 nt2->nttrans.in.completion_filter       = nt->smb2.in.completion_filter;
1618                 nt2->nttrans.in.recursive               = nt->smb2.in.recursive;
1619                 status = ntvfs->ops->notify_fn(ntvfs, req, nt2);
1620                 break;
1621         }
1622
1623         return ntvfs_map_async_finish(req, status);
1624 }