s4:ntvfs_generic: use talloc_get_type() to remote compiler warnings
[jra/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         uint_t 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
288         if (flags & OPENX_FLAGS_REQUEST_OPLOCK) {
289                 io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_OPLOCK;
290         }
291         if (flags & OPENX_FLAGS_REQUEST_BATCH_OPLOCK) {
292                 io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
293         }
294
295         switch (open_mode & OPENX_MODE_ACCESS_MASK) {
296         case OPENX_MODE_ACCESS_READ:
297         case OPENX_MODE_ACCESS_EXEC:
298                 io2->generic.in.access_mask = SEC_RIGHTS_FILE_READ;
299                 break;
300         case OPENX_MODE_ACCESS_WRITE:
301                 io2->generic.in.access_mask = SEC_RIGHTS_FILE_WRITE;
302                 break;
303         case OPENX_MODE_ACCESS_RDWR:
304         case OPENX_MODE_ACCESS_FCB:
305                 io2->generic.in.access_mask = 
306                         SEC_RIGHTS_FILE_READ | 
307                         SEC_RIGHTS_FILE_WRITE;
308                 break;
309         default:
310                 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
311         }
312
313         switch (open_mode & OPENX_MODE_DENY_MASK) {
314         case OPENX_MODE_DENY_READ:
315                 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_WRITE;
316                 break;
317         case OPENX_MODE_DENY_WRITE:
318                 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
319                 break;
320         case OPENX_MODE_DENY_ALL:
321                 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
322                 break;
323         case OPENX_MODE_DENY_NONE:
324                 io2->generic.in.share_access = 
325                         NTCREATEX_SHARE_ACCESS_READ | 
326                         NTCREATEX_SHARE_ACCESS_WRITE;
327                 break;
328         case OPENX_MODE_DENY_DOS:
329                 /* DENY_DOS is quite strange - it depends on the filename! */
330                 io2->generic.in.create_options |= 
331                         NTCREATEX_OPTIONS_PRIVATE_DENY_DOS;
332                 if (is_exe_filename(fname)) {
333                         io2->generic.in.share_access = 
334                                 NTCREATEX_SHARE_ACCESS_READ | 
335                                 NTCREATEX_SHARE_ACCESS_WRITE;
336                 } else {
337                         if ((open_mode & OPENX_MODE_ACCESS_MASK) == OPENX_MODE_ACCESS_READ) {
338                                 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
339                         } else {
340                                 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
341                         }
342                 }
343                 break;
344         case OPENX_MODE_DENY_FCB:
345                 io2->generic.in.create_options |= NTCREATEX_OPTIONS_PRIVATE_DENY_FCB;
346                 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
347                 break;
348         default:
349                 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
350         }
351
352         switch (open_func) {
353         case (OPENX_OPEN_FUNC_OPEN):
354                 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN;
355                 break;
356         case (OPENX_OPEN_FUNC_TRUNC):
357                 io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
358                 break;
359         case (OPENX_OPEN_FUNC_FAIL | OPENX_OPEN_FUNC_CREATE):
360                 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
361                 break;
362         case (OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE):
363                 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
364                 break;
365         case (OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE):
366                 io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
367                 break;                  
368         default:
369                 /* this one is very strange */
370                 if ((open_mode & OPENX_MODE_ACCESS_MASK) == OPENX_MODE_ACCESS_EXEC) {
371                         io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
372                         break;
373                 }
374                 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
375         }
376
377         return NT_STATUS_OK;
378 }
379
380 /* 
381    NTVFS open generic to any mapper
382 */
383 NTSTATUS ntvfs_map_open(struct ntvfs_module_context *ntvfs,
384                                  struct ntvfs_request *req,
385                                  union smb_open *io)
386 {
387         NTSTATUS status;
388         union smb_open *io2;
389
390         io2 = talloc_zero(req, union smb_open);
391         if (io2 == NULL) {
392                 return NT_STATUS_NO_MEMORY;
393         }
394
395         status = ntvfs_map_async_setup(ntvfs, req,
396                                        io, io2, 
397                                        (second_stage_t)ntvfs_map_open_finish);
398         if (!NT_STATUS_IS_OK(status)) {
399                 return status;
400         }
401
402         io2->generic.level = RAW_OPEN_GENERIC;
403                 
404         switch (io->generic.level) {
405         case RAW_OPEN_OPENX:
406                 status = map_openx_open(io->openx.in.flags,
407                                         io->openx.in.open_mode, 
408                                         io->openx.in.open_func, 
409                                         io->openx.in.fname,
410                                         io2);
411                 if (!NT_STATUS_IS_OK(status)) {
412                         goto done;
413                 }
414                 
415                 io2->generic.in.file_attr = io->openx.in.file_attrs;
416                 io2->generic.in.fname = io->openx.in.fname;
417                 
418                 status = ntvfs->ops->open(ntvfs, req, io2);
419                 break;
420                 
421                 
422         case RAW_OPEN_OPEN:
423                 status = map_openx_open(0,
424                                         io->openold.in.open_mode, 
425                                         OPENX_OPEN_FUNC_OPEN, 
426                                         io->openold.in.fname,
427                                         io2);
428                 if (!NT_STATUS_IS_OK(status)) {
429                         goto done;
430                 }
431
432                 io2->generic.in.file_attr = io->openold.in.search_attrs;
433                 io2->generic.in.fname = io->openold.in.fname;
434
435                 status = ntvfs->ops->open(ntvfs, req, io2);
436                 break;
437
438         case RAW_OPEN_T2OPEN:
439                 io2->generic.level         = RAW_OPEN_NTTRANS_CREATE;
440
441                 if (io->t2open.in.open_func == 0) {
442                         status = NT_STATUS_OBJECT_NAME_COLLISION;
443                         goto done;
444                 }
445
446                 status = map_openx_open(io->t2open.in.flags,
447                                         io->t2open.in.open_mode, 
448                                         io->t2open.in.open_func, 
449                                         io->t2open.in.fname,
450                                         io2);
451                 if (!NT_STATUS_IS_OK(status)) {
452                         goto done;
453                 }
454
455                 io2->generic.in.file_attr        = io->t2open.in.file_attrs;
456                 io2->generic.in.fname            = io->t2open.in.fname;
457                 io2->generic.in.ea_list          = talloc(io2, struct smb_ea_list);
458                 io2->generic.in.ea_list->num_eas = io->t2open.in.num_eas;
459                 io2->generic.in.ea_list->eas     = io->t2open.in.eas;
460
461                 status = ntvfs->ops->open(ntvfs, req, io2);
462                 break;
463
464         case RAW_OPEN_MKNEW:
465                 io2->generic.in.file_attr = io->mknew.in.attrib;
466                 io2->generic.in.fname = io->mknew.in.fname;
467                 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
468                 io2->generic.in.access_mask = 
469                         SEC_RIGHTS_FILE_READ |
470                         SEC_RIGHTS_FILE_WRITE;
471                 io2->generic.in.share_access = 
472                         NTCREATEX_SHARE_ACCESS_READ | 
473                         NTCREATEX_SHARE_ACCESS_WRITE;
474                 status = ntvfs->ops->open(ntvfs, req, io2);
475                 break;
476
477         case RAW_OPEN_CREATE:
478                 io2->generic.in.file_attr = io->mknew.in.attrib;
479                 io2->generic.in.fname = io->mknew.in.fname;
480                 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
481                 io2->generic.in.access_mask = 
482                         SEC_RIGHTS_FILE_READ |
483                         SEC_RIGHTS_FILE_WRITE;
484                 io2->generic.in.share_access = 
485                         NTCREATEX_SHARE_ACCESS_READ | 
486                         NTCREATEX_SHARE_ACCESS_WRITE;
487                 status = ntvfs->ops->open(ntvfs, req, io2);
488                 break;
489
490         case RAW_OPEN_CTEMP:
491                 io2->generic.in.file_attr = io->ctemp.in.attrib;
492                 io2->generic.in.fname = 
493                         talloc_asprintf(io2, "%s\\SRV%s", 
494                                         io->ctemp.in.directory,
495                                         generate_random_str_list(io2, 5, "0123456789"));
496                 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
497                 io2->generic.in.access_mask = 
498                         SEC_RIGHTS_FILE_READ |
499                         SEC_RIGHTS_FILE_WRITE;
500                 io2->generic.in.share_access = 
501                         NTCREATEX_SHARE_ACCESS_READ | 
502                         NTCREATEX_SHARE_ACCESS_WRITE;
503                 status = ntvfs->ops->open(ntvfs, req, io2);
504                 break;
505         case RAW_OPEN_SMB2:
506                 switch (io->smb2.in.oplock_level) {
507                 case SMB2_OPLOCK_LEVEL_BATCH:
508                         io2->generic.in.flags = NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK |
509                                                 NTCREATEX_FLAGS_REQUEST_OPLOCK;
510                         break;
511                 case SMB2_OPLOCK_LEVEL_EXCLUSIVE:
512                         io2->generic.in.flags = NTCREATEX_FLAGS_REQUEST_OPLOCK;
513                         break;
514                 default:
515                         io2->generic.in.flags = 0;
516                         break;
517                 }
518                 io2->generic.in.root_fid        = 0;
519                 io2->generic.in.access_mask     = io->smb2.in.desired_access;
520                 io2->generic.in.alloc_size      = io->smb2.in.alloc_size;
521                 io2->generic.in.file_attr       = io->smb2.in.file_attributes;
522                 io2->generic.in.share_access    = io->smb2.in.share_access;
523                 io2->generic.in.open_disposition= io->smb2.in.create_disposition;
524                 io2->generic.in.create_options  = io->smb2.in.create_options;
525                 io2->generic.in.impersonation   = io->smb2.in.impersonation_level;
526                 io2->generic.in.security_flags  = 0;
527                 io2->generic.in.fname           = io->smb2.in.fname;
528                 io2->generic.in.sec_desc        = io->smb2.in.sec_desc;
529                 io2->generic.in.ea_list         = &io->smb2.in.eas;
530                 io2->generic.in.query_maximal_access = io->smb2.in.query_maximal_access; 
531
532                 /* we don't support timewarp yet */
533                 if (io->smb2.in.timewarp != 0) {
534                         status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
535                         break;
536                 }
537
538                 /* we need to check these bits before we check the private mask */
539                 if (io2->generic.in.create_options & SMB2_CREATE_OPTIONS_NOT_SUPPORTED_MASK) {
540                         DEBUG(2,(__location__ " create_options 0x%x not supported\n",
541                                  io2->generic.in.create_options));
542                         status = NT_STATUS_NOT_SUPPORTED;
543                         break;
544                 }
545
546                 /* TODO: find out why only SMB2 ignores these */
547                 io2->generic.in.create_options &= ~NTCREATEX_OPTIONS_SYNC_ALERT;
548                 io2->generic.in.create_options &= ~NTCREATEX_OPTIONS_ASYNC_ALERT;
549
550                 status = ntvfs->ops->open(ntvfs, req, io2);             
551                 break;
552
553         default:
554                 status = NT_STATUS_INVALID_LEVEL;
555                 break;
556         }
557 done:
558         return ntvfs_map_async_finish(req, status);
559 }
560
561
562 /* 
563    NTVFS fsinfo generic to any mapper
564 */
565 NTSTATUS ntvfs_map_fsinfo(struct ntvfs_module_context *ntvfs,
566                                    struct ntvfs_request *req,
567                                    union smb_fsinfo *fs)
568 {
569         NTSTATUS status;
570         union smb_fsinfo *fs2;
571
572         fs2 = talloc(req, union smb_fsinfo);
573         if (fs2 == NULL) {
574                 return NT_STATUS_NO_MEMORY;
575         }
576
577         if (fs->generic.level == RAW_QFS_GENERIC) {
578                 return NT_STATUS_INVALID_LEVEL;
579         }
580         
581         /* only used by the simple backend, which doesn't do async */
582         req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
583
584         /* ask the backend for the generic info */
585         fs2->generic.level = RAW_QFS_GENERIC;
586
587         status = ntvfs->ops->fsinfo(ntvfs, req, fs2);
588         if (!NT_STATUS_IS_OK(status)) {
589                 return status;
590         }
591
592         /* and convert it to the required level */
593         switch (fs->generic.level) {
594         case RAW_QFS_GENERIC:
595                 return NT_STATUS_INVALID_LEVEL;
596
597         case RAW_QFS_DSKATTR: {
598                 /* map from generic to DSKATTR */
599                 uint_t bpunit = 64;
600
601                 /* we need to scale the sizes to fit */
602                 for (bpunit=64; bpunit<0x10000; bpunit *= 2) {
603                         if (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size < bpunit * 512 * 65535.0) {
604                                 break;
605                         }
606                 }
607
608                 fs->dskattr.out.blocks_per_unit = bpunit;
609                 fs->dskattr.out.block_size = 512;
610                 fs->dskattr.out.units_total = 
611                         (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size) / (bpunit * 512);
612                 fs->dskattr.out.units_free  = 
613                         (fs2->generic.out.blocks_free  * (double)fs2->generic.out.block_size) / (bpunit * 512);
614
615                 /* we must return a maximum of 2G to old DOS systems, or they get very confused */
616                 if (bpunit > 64 && req->ctx->protocol <= PROTOCOL_LANMAN2) {
617                         fs->dskattr.out.blocks_per_unit = 64;
618                         fs->dskattr.out.units_total = 0xFFFF;
619                         fs->dskattr.out.units_free = 0xFFFF;
620                 }
621                 return NT_STATUS_OK;
622         }
623
624         case RAW_QFS_ALLOCATION:
625                 fs->allocation.out.fs_id = fs2->generic.out.fs_id;
626                 fs->allocation.out.total_alloc_units = fs2->generic.out.blocks_total;
627                 fs->allocation.out.avail_alloc_units = fs2->generic.out.blocks_free;
628                 fs->allocation.out.sectors_per_unit = 1;
629                 fs->allocation.out.bytes_per_sector = fs2->generic.out.block_size;
630                 return NT_STATUS_OK;
631
632         case RAW_QFS_VOLUME:
633                 fs->volume.out.serial_number = fs2->generic.out.serial_number;
634                 fs->volume.out.volume_name.s = fs2->generic.out.volume_name;
635                 return NT_STATUS_OK;
636
637         case RAW_QFS_VOLUME_INFO:
638         case RAW_QFS_VOLUME_INFORMATION:
639                 fs->volume_info.out.create_time = fs2->generic.out.create_time;
640                 fs->volume_info.out.serial_number = fs2->generic.out.serial_number;
641                 fs->volume_info.out.volume_name.s = fs2->generic.out.volume_name;
642                 return NT_STATUS_OK;
643
644         case RAW_QFS_SIZE_INFO:
645         case RAW_QFS_SIZE_INFORMATION:
646                 fs->size_info.out.total_alloc_units = fs2->generic.out.blocks_total;
647                 fs->size_info.out.avail_alloc_units = fs2->generic.out.blocks_free;
648                 fs->size_info.out.sectors_per_unit = 1;
649                 fs->size_info.out.bytes_per_sector = fs2->generic.out.block_size;
650                 return NT_STATUS_OK;
651
652         case RAW_QFS_DEVICE_INFO:
653         case RAW_QFS_DEVICE_INFORMATION:
654                 fs->device_info.out.device_type = fs2->generic.out.device_type;
655                 fs->device_info.out.characteristics = fs2->generic.out.device_characteristics;
656                 return NT_STATUS_OK;
657
658         case RAW_QFS_ATTRIBUTE_INFO:
659         case RAW_QFS_ATTRIBUTE_INFORMATION:
660                 fs->attribute_info.out.fs_attr = fs2->generic.out.fs_attr;
661                 fs->attribute_info.out.max_file_component_length = fs2->generic.out.max_file_component_length;
662                 fs->attribute_info.out.fs_type.s = fs2->generic.out.fs_type;
663                 return NT_STATUS_OK;
664
665         case RAW_QFS_QUOTA_INFORMATION:
666                 ZERO_STRUCT(fs->quota_information.out.unknown);
667                 fs->quota_information.out.quota_soft = fs2->generic.out.quota_soft;
668                 fs->quota_information.out.quota_hard = fs2->generic.out.quota_hard;
669                 fs->quota_information.out.quota_flags = fs2->generic.out.quota_flags;
670                 return NT_STATUS_OK;
671
672         case RAW_QFS_FULL_SIZE_INFORMATION:
673                 fs->full_size_information.out.total_alloc_units = fs2->generic.out.blocks_total;
674                 fs->full_size_information.out.call_avail_alloc_units = fs2->generic.out.blocks_free;
675                 fs->full_size_information.out.actual_avail_alloc_units = fs2->generic.out.blocks_free;
676                 fs->full_size_information.out.sectors_per_unit = 1;
677                 fs->full_size_information.out.bytes_per_sector = fs2->generic.out.block_size;
678                 return NT_STATUS_OK;
679
680         case RAW_QFS_OBJECTID_INFORMATION:
681                 fs->objectid_information.out.guid = fs2->generic.out.guid;
682                 ZERO_STRUCT(fs->objectid_information.out.unknown);
683                 return NT_STATUS_OK;
684         }
685
686
687         return NT_STATUS_INVALID_LEVEL;
688 }
689
690
691 /* 
692    NTVFS fileinfo generic to any mapper
693 */
694 NTSTATUS ntvfs_map_fileinfo(TALLOC_CTX *mem_ctx,
695                                      union smb_fileinfo *info, 
696                                      union smb_fileinfo *info2)
697 {
698         int i;
699         /* and convert it to the required level using results in info2 */
700         switch (info->generic.level) {
701                 case RAW_FILEINFO_GENERIC:
702                 return NT_STATUS_INVALID_LEVEL;
703         case RAW_FILEINFO_GETATTR:
704                 info->getattr.out.attrib = info2->generic.out.attrib & 0xff;
705                 info->getattr.out.size = info2->generic.out.size;
706                 info->getattr.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
707                 return NT_STATUS_OK;
708                 
709         case RAW_FILEINFO_GETATTRE:
710                 info->getattre.out.attrib = info2->generic.out.attrib;
711                 info->getattre.out.size = info2->generic.out.size;
712                 info->getattre.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
713                 info->getattre.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
714                 info->getattre.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
715                 info->getattre.out.alloc_size = info2->generic.out.alloc_size;
716                 return NT_STATUS_OK;
717                 
718         case RAW_FILEINFO_NETWORK_OPEN_INFORMATION:
719                 info->network_open_information.out.create_time = info2->generic.out.create_time;
720                 info->network_open_information.out.access_time = info2->generic.out.access_time;
721                 info->network_open_information.out.write_time =  info2->generic.out.write_time;
722                 info->network_open_information.out.change_time = info2->generic.out.change_time;
723                 info->network_open_information.out.alloc_size = info2->generic.out.alloc_size;
724                 info->network_open_information.out.size = info2->generic.out.size;
725                 info->network_open_information.out.attrib = info2->generic.out.attrib;
726                 return NT_STATUS_OK;
727
728         case RAW_FILEINFO_ALL_INFO:
729         case RAW_FILEINFO_ALL_INFORMATION:
730                 info->all_info.out.create_time = info2->generic.out.create_time;
731                 info->all_info.out.access_time = info2->generic.out.access_time;
732                 info->all_info.out.write_time =  info2->generic.out.write_time;
733                 info->all_info.out.change_time = info2->generic.out.change_time;
734                 info->all_info.out.attrib = info2->generic.out.attrib;
735                 info->all_info.out.alloc_size = info2->generic.out.alloc_size;
736                 info->all_info.out.size = info2->generic.out.size;
737                 info->all_info.out.nlink = info2->generic.out.nlink;
738                 info->all_info.out.delete_pending = info2->generic.out.delete_pending;
739                 info->all_info.out.directory = info2->generic.out.directory;
740                 info->all_info.out.ea_size = info2->generic.out.ea_size;
741                 info->all_info.out.fname.s = info2->generic.out.fname.s;
742                 info->all_info.out.fname.private_length = info2->generic.out.fname.private_length;
743                 return NT_STATUS_OK;
744
745         case RAW_FILEINFO_BASIC_INFO:
746         case RAW_FILEINFO_BASIC_INFORMATION:
747                 info->basic_info.out.create_time = info2->generic.out.create_time;
748                 info->basic_info.out.access_time = info2->generic.out.access_time;
749                 info->basic_info.out.write_time = info2->generic.out.write_time;
750                 info->basic_info.out.change_time = info2->generic.out.change_time;
751                 info->basic_info.out.attrib = info2->generic.out.attrib;
752                 return NT_STATUS_OK;
753
754         case RAW_FILEINFO_STANDARD:
755                 info->standard.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
756                 info->standard.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
757                 info->standard.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
758                 info->standard.out.size = info2->generic.out.size;
759                 info->standard.out.alloc_size = info2->generic.out.alloc_size;
760                 info->standard.out.attrib = info2->generic.out.attrib;
761                 return NT_STATUS_OK;
762
763         case RAW_FILEINFO_EA_SIZE:
764                 info->ea_size.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
765                 info->ea_size.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
766                 info->ea_size.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
767                 info->ea_size.out.size = info2->generic.out.size;
768                 info->ea_size.out.alloc_size = info2->generic.out.alloc_size;
769                 info->ea_size.out.attrib = info2->generic.out.attrib;
770                 info->ea_size.out.ea_size = info2->generic.out.ea_size;
771                 return NT_STATUS_OK;
772
773         case RAW_FILEINFO_STANDARD_INFO:
774         case RAW_FILEINFO_STANDARD_INFORMATION:
775                 info->standard_info.out.alloc_size = info2->generic.out.alloc_size;
776                 info->standard_info.out.size = info2->generic.out.size;
777                 info->standard_info.out.nlink = info2->generic.out.nlink;
778                 info->standard_info.out.delete_pending = info2->generic.out.delete_pending;
779                 info->standard_info.out.directory = info2->generic.out.directory;
780                 return NT_STATUS_OK;
781
782         case RAW_FILEINFO_INTERNAL_INFORMATION:
783                 info->internal_information.out.file_id = info2->generic.out.file_id;
784                 return NT_STATUS_OK;
785
786         case RAW_FILEINFO_EA_INFO:
787         case RAW_FILEINFO_EA_INFORMATION:
788                 info->ea_info.out.ea_size = info2->generic.out.ea_size;
789                 return NT_STATUS_OK;
790
791         case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION:
792                 info->attribute_tag_information.out.attrib = info2->generic.out.attrib;
793                 info->attribute_tag_information.out.reparse_tag = info2->generic.out.reparse_tag;
794                 return NT_STATUS_OK;
795
796         case RAW_FILEINFO_STREAM_INFO:
797         case RAW_FILEINFO_STREAM_INFORMATION:
798                 info->stream_info.out.num_streams = info2->generic.out.num_streams;
799                 if (info->stream_info.out.num_streams > 0) {
800                         info->stream_info.out.streams = 
801                                 talloc_array(mem_ctx, 
802                                                struct stream_struct,
803                                                info->stream_info.out.num_streams);
804                         if (!info->stream_info.out.streams) {
805                                 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d streams\n",
806                                         info->stream_info.out.num_streams));
807                                 return NT_STATUS_NO_MEMORY;
808                         }
809                         for (i=0; i < info->stream_info.out.num_streams; i++) {
810                                 info->stream_info.out.streams[i] = info2->generic.out.streams[i];
811                                 info->stream_info.out.streams[i].stream_name.s = 
812                                         talloc_strdup(info->stream_info.out.streams,
813                                                       info2->generic.out.streams[i].stream_name.s);
814                                 if (!info->stream_info.out.streams[i].stream_name.s) {
815                                         DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
816                                         return NT_STATUS_NO_MEMORY;
817                                 }
818                         }
819                 }
820                 return NT_STATUS_OK;
821
822         case RAW_FILEINFO_NAME_INFO:
823         case RAW_FILEINFO_NAME_INFORMATION:
824                 info->name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.fname.s);
825                 NT_STATUS_HAVE_NO_MEMORY(info->name_info.out.fname.s);
826                 info->name_info.out.fname.private_length = info2->generic.out.fname.private_length;
827                 return NT_STATUS_OK;
828                 
829         case RAW_FILEINFO_ALT_NAME_INFO:
830         case RAW_FILEINFO_ALT_NAME_INFORMATION:
831                 info->alt_name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.alt_fname.s);
832                 NT_STATUS_HAVE_NO_MEMORY(info->alt_name_info.out.fname.s);
833                 info->alt_name_info.out.fname.private_length = info2->generic.out.alt_fname.private_length;
834                 return NT_STATUS_OK;
835         
836         case RAW_FILEINFO_POSITION_INFORMATION:
837                 info->position_information.out.position = info2->generic.out.position;
838                 return NT_STATUS_OK;
839         
840         case RAW_FILEINFO_ALL_EAS:
841                 info->all_eas.out.num_eas = info2->generic.out.num_eas;
842                 if (info->all_eas.out.num_eas > 0) {
843                         info->all_eas.out.eas = talloc_array(mem_ctx, 
844                                                                struct ea_struct,
845                                                                info->all_eas.out.num_eas);
846                         if (!info->all_eas.out.eas) {
847                                 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d eas\n",
848                                         info->all_eas.out.num_eas));
849                                 return NT_STATUS_NO_MEMORY;
850                         }
851                         for (i = 0; i < info->all_eas.out.num_eas; i++) {
852                                 info->all_eas.out.eas[i] = info2->generic.out.eas[i];
853                                 info->all_eas.out.eas[i].name.s = 
854                                         talloc_strdup(info->all_eas.out.eas,
855                                                       info2->generic.out.eas[i].name.s);
856                                 if (!info->all_eas.out.eas[i].name.s) {
857                                         DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
858                                         return NT_STATUS_NO_MEMORY;
859                                 }
860                                 info->all_eas.out.eas[i].value.data = 
861                                         (uint8_t *)talloc_memdup(info->all_eas.out.eas,
862                                                 info2->generic.out.eas[i].value.data,
863                                                 info2->generic.out.eas[i].value.length);
864                                 if (!info->all_eas.out.eas[i].value.data) {
865                                         DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
866                                         return NT_STATUS_NO_MEMORY;
867                                 }
868                         }
869                 }
870                 return NT_STATUS_OK;
871                 
872         case RAW_FILEINFO_IS_NAME_VALID:
873                 return NT_STATUS_OK;
874                 
875         case RAW_FILEINFO_COMPRESSION_INFO:
876         case RAW_FILEINFO_COMPRESSION_INFORMATION:
877                 info->compression_info.out.compressed_size = info2->generic.out.compressed_size;
878                 info->compression_info.out.format = info2->generic.out.format;
879                 info->compression_info.out.unit_shift = info2->generic.out.unit_shift;
880                 info->compression_info.out.chunk_shift = info2->generic.out.chunk_shift;
881                 info->compression_info.out.cluster_shift = info2->generic.out.cluster_shift;
882                 return NT_STATUS_OK;
883                 
884         case RAW_FILEINFO_ACCESS_INFORMATION:
885                 info->access_information.out.access_flags = info2->generic.out.access_flags;
886                 return NT_STATUS_OK;
887                 
888         case RAW_FILEINFO_MODE_INFORMATION:
889                 info->mode_information.out.mode = info2->generic.out.mode;
890                 return NT_STATUS_OK;
891                 
892         case RAW_FILEINFO_ALIGNMENT_INFORMATION:
893                 info->alignment_information.out.alignment_requirement =
894                         info2->generic.out.alignment_requirement;
895                 return NT_STATUS_OK;
896 #if 0   
897         case RAW_FILEINFO_UNIX_BASIC:
898                 info->unix_basic_info.out.end_of_file = info2->generic.out.end_of_file;
899                 info->unix_basic_info.out.num_bytes = info2->generic.out.size;
900                 info->unix_basic_info.out.status_change_time = info2->generic.out.change_time;
901                 info->unix_basic_info.out.access_time = info2->generic.out.access_time;
902                 info->unix_basic_info.out.change_time = info2->generic.out.change_time;
903                 info->unix_basic_info.out.uid = info2->generic.out.uid;
904                 info->unix_basic_info.out.gid = info2->generic.out.gid;
905                 info->unix_basic_info.out.file_type = info2->generic.out.file_type;
906                 info->unix_basic_info.out.dev_major = info2->generic.out.device;
907                 info->unix_basic_info.out.dev_minor = info2->generic.out.device;
908                 info->unix_basic_info.out.unique_id = info2->generic.out.inode;
909                 info->unix_basic_info.out.permissions = info2->generic.out.permissions;
910                 info->unix_basic_info.out.nlink = info2->generic.out.nlink;
911                 return NT_STATUS_OK;
912                 
913         case RAW_FILEINFO_UNIX_LINK:
914                 info->unix_link_info.out.link_dest = info2->generic.out.link_dest;
915                 return NT_STATUS_OK;
916 #endif
917         }
918
919         return NT_STATUS_INVALID_LEVEL;
920 }
921
922 /* 
923    NTVFS fileinfo generic to any mapper
924 */
925 NTSTATUS ntvfs_map_qfileinfo(struct ntvfs_module_context *ntvfs,
926                                       struct ntvfs_request *req,
927                                       union smb_fileinfo *info)
928 {
929         NTSTATUS status;
930         union smb_fileinfo *info2;
931
932         info2 = talloc(req, union smb_fileinfo);
933         if (info2 == NULL) {
934                 return NT_STATUS_NO_MEMORY;
935         }
936
937         if (info->generic.level == RAW_FILEINFO_GENERIC) {
938                 return NT_STATUS_INVALID_LEVEL;
939         }
940
941         /* ask the backend for the generic info */
942         info2->generic.level = RAW_FILEINFO_GENERIC;
943         info2->generic.in.file.ntvfs= info->generic.in.file.ntvfs;
944
945         /* only used by the simple backend, which doesn't do async */
946         req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
947
948         status = ntvfs->ops->qfileinfo(ntvfs, req, info2);
949         if (!NT_STATUS_IS_OK(status)) {
950                 return status;
951         }
952         return ntvfs_map_fileinfo(req, info, info2);
953 }
954
955 /* 
956    NTVFS pathinfo generic to any mapper
957 */
958 NTSTATUS ntvfs_map_qpathinfo(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         /* ask the backend for the generic info */
975         info2->generic.level            = RAW_FILEINFO_GENERIC;
976         info2->generic.in.file.path     = info->generic.in.file.path;
977
978         /* only used by the simple backend, which doesn't do async */
979         req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
980
981         status = ntvfs->ops->qpathinfo(ntvfs, req, info2);
982         if (!NT_STATUS_IS_OK(status)) {
983                 return status;
984         }
985         return ntvfs_map_fileinfo(req, info, info2);
986 }
987
988
989 /* 
990    NTVFS lock generic to any mapper
991 */
992 NTSTATUS ntvfs_map_lock(struct ntvfs_module_context *ntvfs,
993                         struct ntvfs_request *req,
994                         union smb_lock *lck)
995 {
996         union smb_lock *lck2;
997         struct smb_lock_entry *locks;
998
999         lck2 = talloc(req, union smb_lock);
1000         if (lck2 == NULL) {
1001                 return NT_STATUS_NO_MEMORY;
1002         }
1003
1004         locks = talloc_array(lck2, struct smb_lock_entry, 1);
1005         if (locks == NULL) {
1006                 return NT_STATUS_NO_MEMORY;
1007         }
1008
1009         switch (lck->generic.level) {
1010         case RAW_LOCK_LOCKX:
1011                 return NT_STATUS_INVALID_LEVEL;
1012
1013         case RAW_LOCK_LOCK:
1014                 lck2->generic.level = RAW_LOCK_GENERIC;
1015                 lck2->generic.in.file.ntvfs= lck->lock.in.file.ntvfs;
1016                 lck2->generic.in.mode = 0;
1017                 lck2->generic.in.timeout = 0;
1018                 lck2->generic.in.ulock_cnt = 0;
1019                 lck2->generic.in.lock_cnt = 1;
1020                 lck2->generic.in.locks = locks;
1021                 locks->pid = req->smbpid;
1022                 locks->offset = lck->lock.in.offset;
1023                 locks->count = lck->lock.in.count;
1024                 break;
1025
1026         case RAW_LOCK_UNLOCK:
1027                 lck2->generic.level = RAW_LOCK_GENERIC;
1028                 lck2->generic.in.file.ntvfs= lck->unlock.in.file.ntvfs;
1029                 lck2->generic.in.mode = 0;
1030                 lck2->generic.in.timeout = 0;
1031                 lck2->generic.in.ulock_cnt = 1;
1032                 lck2->generic.in.lock_cnt = 0;
1033                 lck2->generic.in.locks = locks;
1034                 locks->pid = req->smbpid;
1035                 locks->offset = lck->unlock.in.offset;
1036                 locks->count = lck->unlock.in.count;
1037                 break;
1038
1039         case RAW_LOCK_SMB2: {
1040                 /* this is only approximate! We need to change the
1041                    generic structure to fix this properly */
1042                 int i;
1043                 bool isunlock;
1044                 if (lck->smb2.in.lock_count < 1) {
1045                         return NT_STATUS_INVALID_PARAMETER;
1046                 }
1047
1048                 lck2->generic.level = RAW_LOCK_GENERIC;
1049                 lck2->generic.in.file.ntvfs= lck->smb2.in.file.ntvfs;
1050                 lck2->generic.in.timeout = UINT32_MAX;
1051                 lck2->generic.in.mode = 0;
1052                 lck2->generic.in.lock_cnt = 0;
1053                 lck2->generic.in.ulock_cnt = 0;
1054                 lck2->generic.in.locks = talloc_zero_array(lck2, struct smb_lock_entry, 
1055                                                            lck->smb2.in.lock_count);
1056                 if (lck2->generic.in.locks == NULL) {
1057                         return NT_STATUS_NO_MEMORY;
1058                 }
1059                 /* only the first lock gives the UNLOCK bit - see
1060                    MS-SMB2 3.3.5.14 */
1061                 if (lck->smb2.in.locks[0].flags & SMB2_LOCK_FLAG_UNLOCK) {
1062                         lck2->generic.in.ulock_cnt = lck->smb2.in.lock_count;
1063                         isunlock = true;
1064                 } else {
1065                         lck2->generic.in.lock_cnt = lck->smb2.in.lock_count;
1066                         isunlock = false;
1067                 }
1068                 for (i=0;i<lck->smb2.in.lock_count;i++) {
1069                         if (isunlock && 
1070                             (lck->smb2.in.locks[i].flags & 
1071                              (SMB2_LOCK_FLAG_SHARED|SMB2_LOCK_FLAG_EXCLUSIVE))) {
1072                                 return NT_STATUS_INVALID_PARAMETER;
1073                         }
1074                         if (!isunlock && 
1075                             (lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_UNLOCK)) {
1076                                 return NT_STATUS_INVALID_PARAMETER;
1077                         }
1078                         lck2->generic.in.locks[i].pid    = req->smbpid;
1079                         lck2->generic.in.locks[i].offset = lck->smb2.in.locks[i].offset;
1080                         lck2->generic.in.locks[i].count  = lck->smb2.in.locks[i].length;
1081                         if (!(lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_EXCLUSIVE)) {
1082                                 lck2->generic.in.mode = LOCKING_ANDX_SHARED_LOCK;
1083                         }
1084                         if (lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_FAIL_IMMEDIATELY) {
1085                                 lck2->generic.in.timeout = 0;
1086                         }
1087                 }
1088                 /* initialize output value */
1089                 lck->smb2.out.reserved = 0;
1090                 break;
1091         }
1092
1093         case RAW_LOCK_SMB2_BREAK:
1094                 lck2->generic.level             = RAW_LOCK_GENERIC;
1095                 lck2->generic.in.file.ntvfs     = lck->smb2_break.in.file.ntvfs;
1096                 lck2->generic.in.mode           = LOCKING_ANDX_OPLOCK_RELEASE |
1097                                                   ((lck->smb2_break.in.oplock_level << 8) & 0xFF00);
1098                 lck2->generic.in.timeout        = 0;
1099                 lck2->generic.in.ulock_cnt      = 0;
1100                 lck2->generic.in.lock_cnt       = 0;
1101                 lck2->generic.in.locks          = NULL;
1102
1103                 /* initialize output value */
1104                 lck->smb2_break.out.oplock_level= lck->smb2_break.in.oplock_level;
1105                 lck->smb2_break.out.reserved    = lck->smb2_break.in.reserved;
1106                 lck->smb2_break.out.reserved2   = lck->smb2_break.in.reserved2;
1107                 lck->smb2_break.out.file        = lck->smb2_break.in.file;
1108                 break;
1109         }
1110
1111         /* 
1112          * we don't need to call ntvfs_map_async_setup() here,
1113          * as lock() doesn't have any output fields
1114          */
1115
1116         return ntvfs->ops->lock(ntvfs, req, lck2);
1117 }
1118
1119
1120 /* 
1121    NTVFS write generic to any mapper
1122 */
1123 static NTSTATUS ntvfs_map_write_finish(struct ntvfs_module_context *ntvfs,
1124                                        struct ntvfs_request *req,
1125                                        union smb_write *wr, 
1126                                        union smb_write *wr2, 
1127                                        NTSTATUS status)
1128 {
1129         union smb_lock *lck;
1130         union smb_close *cl;
1131         uint_t state;
1132
1133         if (NT_STATUS_IS_ERR(status)) {
1134                 return status;
1135         }
1136
1137         switch (wr->generic.level) {
1138         case RAW_WRITE_WRITE:
1139                 wr->write.out.nwritten    = wr2->generic.out.nwritten;
1140                 break;
1141
1142         case RAW_WRITE_WRITEUNLOCK:
1143                 wr->writeunlock.out.nwritten = wr2->generic.out.nwritten;
1144
1145                 lck = talloc(wr2, union smb_lock);
1146                 if (lck == NULL) {
1147                         return NT_STATUS_NO_MEMORY;
1148                 }
1149
1150                 lck->unlock.level               = RAW_LOCK_UNLOCK;
1151                 lck->unlock.in.file.ntvfs       = wr->writeunlock.in.file.ntvfs;
1152                 lck->unlock.in.count            = wr->writeunlock.in.count;
1153                 lck->unlock.in.offset           = wr->writeunlock.in.offset;
1154
1155                 if (lck->unlock.in.count != 0) {
1156                         /* do the lock sync for now */
1157                         state = req->async_states->state;
1158                         req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1159                         status = ntvfs->ops->lock(ntvfs, req, lck);
1160                         req->async_states->state = state;
1161                 }
1162                 break;
1163
1164         case RAW_WRITE_WRITECLOSE:
1165                 wr->writeclose.out.nwritten    = wr2->generic.out.nwritten;
1166
1167                 cl = talloc(wr2, union smb_close);
1168                 if (cl == NULL) {
1169                         return NT_STATUS_NO_MEMORY;
1170                 }
1171
1172                 cl->close.level         = RAW_CLOSE_CLOSE;
1173                 cl->close.in.file.ntvfs = wr->writeclose.in.file.ntvfs;
1174                 cl->close.in.write_time = wr->writeclose.in.mtime;
1175
1176                 if (wr2->generic.in.count != 0) {
1177                         /* do the close sync for now */
1178                         state = req->async_states->state;
1179                         req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1180                         status = ntvfs->ops->close(ntvfs, req, cl);
1181                         req->async_states->state = state;
1182                 }
1183                 break;
1184
1185         case RAW_WRITE_SPLWRITE:
1186                 break;
1187
1188         case RAW_WRITE_SMB2:
1189                 wr->smb2.out._pad       = 0;
1190                 wr->smb2.out.nwritten   = wr2->generic.out.nwritten;
1191                 wr->smb2.out.unknown1   = 0;
1192                 break;
1193
1194         default:
1195                 return NT_STATUS_INVALID_LEVEL;
1196         }
1197
1198         return status;
1199 }
1200
1201
1202 /* 
1203    NTVFS write generic to any mapper
1204 */
1205 NTSTATUS ntvfs_map_write(struct ntvfs_module_context *ntvfs,
1206                                   struct ntvfs_request *req,
1207                                   union smb_write *wr)
1208 {
1209         union smb_write *wr2;
1210         NTSTATUS status;
1211
1212         wr2 = talloc(req, union smb_write);
1213         if (wr2 == NULL) {
1214                 return NT_STATUS_NO_MEMORY;
1215         }
1216
1217         status = ntvfs_map_async_setup(ntvfs, req, wr, wr2, 
1218                                        (second_stage_t)ntvfs_map_write_finish);
1219         if (!NT_STATUS_IS_OK(status)) {
1220                 return status;
1221         }
1222
1223         wr2->writex.level = RAW_WRITE_GENERIC;
1224
1225         switch (wr->generic.level) {
1226         case RAW_WRITE_WRITEX:
1227                 status = NT_STATUS_INVALID_LEVEL;
1228                 break;
1229
1230         case RAW_WRITE_WRITE:
1231                 wr2->writex.in.file.ntvfs= wr->write.in.file.ntvfs;
1232                 wr2->writex.in.offset    = wr->write.in.offset;
1233                 wr2->writex.in.wmode     = 0;
1234                 wr2->writex.in.remaining = wr->write.in.remaining;
1235                 wr2->writex.in.count     = wr->write.in.count;
1236                 wr2->writex.in.data      = wr->write.in.data;
1237                 status = ntvfs->ops->write(ntvfs, req, wr2);
1238                 break;
1239
1240         case RAW_WRITE_WRITEUNLOCK:
1241                 wr2->writex.in.file.ntvfs= wr->writeunlock.in.file.ntvfs;
1242                 wr2->writex.in.offset    = wr->writeunlock.in.offset;
1243                 wr2->writex.in.wmode     = 0;
1244                 wr2->writex.in.remaining = wr->writeunlock.in.remaining;
1245                 wr2->writex.in.count     = wr->writeunlock.in.count;
1246                 wr2->writex.in.data      = wr->writeunlock.in.data;
1247                 status = ntvfs->ops->write(ntvfs, req, wr2);
1248                 break;
1249
1250         case RAW_WRITE_WRITECLOSE:
1251                 wr2->writex.in.file.ntvfs= wr->writeclose.in.file.ntvfs;
1252                 wr2->writex.in.offset    = wr->writeclose.in.offset;
1253                 wr2->writex.in.wmode     = 0;
1254                 wr2->writex.in.remaining = 0;
1255                 wr2->writex.in.count     = wr->writeclose.in.count;
1256                 wr2->writex.in.data      = wr->writeclose.in.data;
1257                 status = ntvfs->ops->write(ntvfs, req, wr2);
1258                 break;
1259
1260         case RAW_WRITE_SPLWRITE:
1261                 wr2->writex.in.file.ntvfs= wr->splwrite.in.file.ntvfs;
1262                 wr2->writex.in.offset    = 0;
1263                 wr2->writex.in.wmode     = 0;
1264                 wr2->writex.in.remaining = 0;
1265                 wr2->writex.in.count     = wr->splwrite.in.count;
1266                 wr2->writex.in.data      = wr->splwrite.in.data;
1267                 status = ntvfs->ops->write(ntvfs, req, wr2);
1268                 break;
1269
1270         case RAW_WRITE_SMB2:
1271                 wr2->writex.in.file.ntvfs= wr->smb2.in.file.ntvfs;
1272                 wr2->writex.in.offset    = wr->smb2.in.offset;
1273                 wr2->writex.in.wmode     = 0;
1274                 wr2->writex.in.remaining = 0;
1275                 wr2->writex.in.count     = wr->smb2.in.data.length;
1276                 wr2->writex.in.data      = wr->smb2.in.data.data;
1277                 status = ntvfs->ops->write(ntvfs, req, wr2);
1278         }
1279
1280         return ntvfs_map_async_finish(req, status);
1281 }
1282
1283
1284 /* 
1285    NTVFS read generic to any mapper - finish the out mapping
1286 */
1287 static NTSTATUS ntvfs_map_read_finish(struct ntvfs_module_context *ntvfs,
1288                                       struct ntvfs_request *req, 
1289                                       union smb_read *rd, 
1290                                       union smb_read *rd2,
1291                                       NTSTATUS status)
1292 {
1293         switch (rd->generic.level) {
1294         case RAW_READ_READ:
1295                 rd->read.out.nread      = rd2->generic.out.nread;
1296                 break;
1297         case RAW_READ_READBRAW:
1298                 rd->readbraw.out.nread  = rd2->generic.out.nread;
1299                 break;
1300         case RAW_READ_LOCKREAD:
1301                 rd->lockread.out.nread  = rd2->generic.out.nread;
1302                 break;
1303         case RAW_READ_SMB2:
1304                 rd->smb2.out.data.length= rd2->generic.out.nread;
1305                 rd->smb2.out.remaining  = 0;
1306                 rd->smb2.out.reserved   = 0;
1307                 break;
1308         default:
1309                 return NT_STATUS_INVALID_LEVEL;
1310         }
1311
1312         return status;
1313 }
1314
1315 /* 
1316    NTVFS read* to readx mapper
1317 */
1318 NTSTATUS ntvfs_map_read(struct ntvfs_module_context *ntvfs,
1319                                  struct ntvfs_request *req,
1320                                  union smb_read *rd)
1321 {
1322         union smb_read *rd2;
1323         union smb_lock *lck;
1324         NTSTATUS status;
1325         uint_t state;
1326
1327         rd2 = talloc(req, union smb_read);
1328         if (rd2 == NULL) {
1329                 return NT_STATUS_NO_MEMORY;
1330         }
1331
1332         status = ntvfs_map_async_setup(ntvfs, req, rd, rd2, 
1333                                        (second_stage_t)ntvfs_map_read_finish);
1334         if (!NT_STATUS_IS_OK(status)) {
1335                 return status;
1336         }
1337
1338         rd2->readx.level = RAW_READ_READX;
1339         rd2->readx.in.read_for_execute = false;
1340
1341         switch (rd->generic.level) {
1342         case RAW_READ_READX:
1343                 status = NT_STATUS_INVALID_LEVEL;
1344                 break;
1345
1346         case RAW_READ_READ:
1347                 rd2->readx.in.file.ntvfs= rd->read.in.file.ntvfs;
1348                 rd2->readx.in.offset    = rd->read.in.offset;
1349                 rd2->readx.in.mincnt    = rd->read.in.count;
1350                 rd2->readx.in.maxcnt    = rd->read.in.count;
1351                 rd2->readx.in.remaining = rd->read.in.remaining;
1352                 rd2->readx.out.data     = rd->read.out.data;
1353                 status = ntvfs->ops->read(ntvfs, req, rd2);
1354                 break;
1355
1356         case RAW_READ_READBRAW:
1357                 rd2->readx.in.file.ntvfs= rd->readbraw.in.file.ntvfs;
1358                 rd2->readx.in.offset    = rd->readbraw.in.offset;
1359                 rd2->readx.in.mincnt    = rd->readbraw.in.mincnt;
1360                 rd2->readx.in.maxcnt    = rd->readbraw.in.maxcnt;
1361                 rd2->readx.in.remaining = 0;
1362                 rd2->readx.out.data     = rd->readbraw.out.data;
1363                 status = ntvfs->ops->read(ntvfs, req, rd2);
1364                 break;
1365
1366         case RAW_READ_LOCKREAD:
1367                 /* do the initial lock sync for now */
1368                 state = req->async_states->state;
1369                 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1370
1371                 lck = talloc(rd2, union smb_lock);
1372                 if (lck == NULL) {
1373                         status = NT_STATUS_NO_MEMORY;
1374                         goto done;
1375                 }
1376                 lck->lock.level         = RAW_LOCK_LOCK;
1377                 lck->lock.in.file.ntvfs = rd->lockread.in.file.ntvfs;
1378                 lck->lock.in.count      = rd->lockread.in.count;
1379                 lck->lock.in.offset     = rd->lockread.in.offset;
1380                 status = ntvfs->ops->lock(ntvfs, req, lck);
1381                 req->async_states->state = state;
1382
1383                 rd2->readx.in.file.ntvfs= rd->lockread.in.file.ntvfs;
1384                 rd2->readx.in.offset    = rd->lockread.in.offset;
1385                 rd2->readx.in.mincnt    = rd->lockread.in.count;
1386                 rd2->readx.in.maxcnt    = rd->lockread.in.count;
1387                 rd2->readx.in.remaining = rd->lockread.in.remaining;
1388                 rd2->readx.out.data     = rd->lockread.out.data;
1389
1390                 if (NT_STATUS_IS_OK(status)) {
1391                         status = ntvfs->ops->read(ntvfs, req, rd2);
1392                 }
1393                 break;
1394
1395         case RAW_READ_SMB2:
1396                 rd2->readx.in.file.ntvfs= rd->smb2.in.file.ntvfs;
1397                 rd2->readx.in.offset    = rd->smb2.in.offset;
1398                 rd2->readx.in.mincnt    = rd->smb2.in.min_count;
1399                 rd2->readx.in.maxcnt    = rd->smb2.in.length;
1400                 rd2->readx.in.remaining = 0;
1401                 rd2->readx.out.data     = rd->smb2.out.data.data;
1402                 status = ntvfs->ops->read(ntvfs, req, rd2);
1403                 break;
1404         }
1405
1406 done:
1407         return ntvfs_map_async_finish(req, status);
1408 }
1409
1410
1411 /* 
1412    NTVFS close generic to any mapper
1413 */
1414 static NTSTATUS ntvfs_map_close_finish(struct ntvfs_module_context *ntvfs,
1415                                         struct ntvfs_request *req,
1416                                         union smb_close *cl, 
1417                                         union smb_close *cl2, 
1418                                         NTSTATUS status)
1419 {
1420         NT_STATUS_NOT_OK_RETURN(status);
1421
1422         switch (cl->generic.level) {
1423         case RAW_CLOSE_SMB2:
1424                 cl->smb2.out.flags        = cl2->generic.out.flags;
1425                 cl->smb2.out._pad         = 0;
1426                 cl->smb2.out.create_time  = cl2->generic.out.create_time;
1427                 cl->smb2.out.access_time  = cl2->generic.out.access_time;
1428                 cl->smb2.out.write_time   = cl2->generic.out.write_time;
1429                 cl->smb2.out.change_time  = cl2->generic.out.change_time;
1430                 cl->smb2.out.alloc_size   = cl2->generic.out.alloc_size;
1431                 cl->smb2.out.size         = cl2->generic.out.size;
1432                 cl->smb2.out.file_attr    = cl2->generic.out.file_attr;
1433                 break;
1434         default:
1435                 break;
1436         }
1437
1438         return status;
1439 }
1440
1441 /* 
1442    NTVFS close generic to any mapper
1443 */
1444 NTSTATUS ntvfs_map_close(struct ntvfs_module_context *ntvfs,
1445                                   struct ntvfs_request *req,
1446                                   union smb_close *cl)
1447 {
1448         union smb_close *cl2;
1449         NTSTATUS status;
1450
1451         cl2 = talloc(req, union smb_close);
1452         if (cl2 == NULL) {
1453                 return NT_STATUS_NO_MEMORY;
1454         }
1455
1456         switch (cl->generic.level) {
1457         case RAW_CLOSE_GENERIC:
1458                 return NT_STATUS_INVALID_LEVEL;
1459
1460         case RAW_CLOSE_CLOSE:
1461                 cl2->generic.level              = RAW_CLOSE_GENERIC;
1462                 cl2->generic.in.file            = cl->close.in.file;
1463                 cl2->generic.in.write_time      = cl->close.in.write_time;
1464                 cl2->generic.in.flags           = 0;
1465                 break;
1466
1467         case RAW_CLOSE_SPLCLOSE:
1468                 cl2->generic.level              = RAW_CLOSE_GENERIC;
1469                 cl2->generic.in.file            = cl->splclose.in.file;
1470                 cl2->generic.in.write_time      = 0;
1471                 cl2->generic.in.flags           = 0;
1472                 break;
1473
1474         case RAW_CLOSE_SMB2:
1475                 cl2->generic.level              = RAW_CLOSE_GENERIC;
1476                 cl2->generic.in.file            = cl->smb2.in.file;
1477                 cl2->generic.in.write_time      = 0;
1478                 cl2->generic.in.flags           = cl->smb2.in.flags;
1479                 break;
1480         }
1481
1482         status = ntvfs_map_async_setup(ntvfs, req, cl, cl2, 
1483                                        (second_stage_t)ntvfs_map_close_finish);
1484         NT_STATUS_NOT_OK_RETURN(status);
1485
1486         status = ntvfs->ops->close(ntvfs, req, cl2);
1487
1488         return ntvfs_map_async_finish(req, status);
1489 }
1490
1491 /* 
1492    NTVFS notify generic to any mapper
1493 */
1494 static NTSTATUS ntvfs_map_notify_finish(struct ntvfs_module_context *ntvfs,
1495                                         struct ntvfs_request *req,
1496                                         union smb_notify *nt, 
1497                                         union smb_notify *nt2, 
1498                                         NTSTATUS status)
1499 {
1500         NT_STATUS_NOT_OK_RETURN(status);
1501
1502         switch (nt->nttrans.level) {
1503         case RAW_NOTIFY_SMB2:
1504                 if (nt2->nttrans.out.num_changes == 0) {
1505                         return STATUS_NOTIFY_ENUM_DIR;
1506                 }
1507                 nt->smb2.out.num_changes        = nt2->nttrans.out.num_changes;
1508                 nt->smb2.out.changes            = talloc_steal(req, nt2->nttrans.out.changes);
1509                 break;
1510
1511         default:
1512                 return NT_STATUS_INVALID_LEVEL;
1513         }
1514
1515         return status;
1516 }
1517
1518
1519 /* 
1520    NTVFS notify generic to any mapper
1521 */
1522 NTSTATUS ntvfs_map_notify(struct ntvfs_module_context *ntvfs,
1523                                    struct ntvfs_request *req,
1524                                    union smb_notify *nt)
1525 {
1526         union smb_notify *nt2;
1527         NTSTATUS status;
1528
1529         nt2 = talloc(req, union smb_notify);
1530         NT_STATUS_HAVE_NO_MEMORY(nt2);
1531
1532         status = ntvfs_map_async_setup(ntvfs, req, nt, nt2, 
1533                                        (second_stage_t)ntvfs_map_notify_finish);
1534         NT_STATUS_NOT_OK_RETURN(status);
1535
1536         nt2->nttrans.level = RAW_NOTIFY_NTTRANS;
1537
1538         switch (nt->nttrans.level) {
1539         case RAW_NOTIFY_NTTRANS:
1540                 status = NT_STATUS_INVALID_LEVEL;
1541                 break;
1542
1543         case RAW_NOTIFY_SMB2:
1544                 nt2->nttrans.in.file.ntvfs              = nt->smb2.in.file.ntvfs;
1545                 nt2->nttrans.in.buffer_size             = nt->smb2.in.buffer_size;
1546                 nt2->nttrans.in.completion_filter       = nt->smb2.in.completion_filter;
1547                 nt2->nttrans.in.recursive               = nt->smb2.in.recursive;
1548                 status = ntvfs->ops->notify(ntvfs, req, nt2);
1549                 break;
1550         }
1551
1552         return ntvfs_map_async_finish(req, status);
1553 }