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