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