Merge branch 'v4-0-test' of ssh://git.samba.org/data/git/samba into nosmbpython
[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                 /* this is only approximate! We need to change the
1016                    generic structure to fix this properly */
1017                 int i;
1018                 if (lck->smb2.in.lock_count < 1) {
1019                         return NT_STATUS_INVALID_PARAMETER;
1020                 }
1021
1022                 lck2->generic.level = RAW_LOCK_GENERIC;
1023                 lck2->generic.in.file.ntvfs= lck->smb2.in.file.ntvfs;
1024                 lck2->generic.in.timeout = UINT32_MAX;
1025                 lck2->generic.in.mode = 0;
1026                 lck2->generic.in.lock_cnt = 0;
1027                 lck2->generic.in.ulock_cnt = 0;
1028                 lck2->generic.in.locks = talloc_zero_array(lck2, struct smb_lock_entry, 
1029                                                            lck->smb2.in.lock_count);
1030                 if (lck2->generic.in.locks == NULL) {
1031                         return NT_STATUS_NO_MEMORY;
1032                 }
1033                 for (i=0;i<lck->smb2.in.lock_count;i++) {
1034                         if (lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_UNLOCK) {
1035                                 int j = lck2->generic.in.ulock_cnt;
1036                                 lck2->generic.in.ulock_cnt++;
1037                                 lck2->generic.in.locks[j].pid = 0;
1038                                 lck2->generic.in.locks[j].offset = lck->smb2.in.locks[i].offset;
1039                                 lck2->generic.in.locks[j].count = lck->smb2.in.locks[i].length;
1040                                 lck2->generic.in.locks[j].pid = 0;
1041                         }
1042                 }
1043                 for (i=0;i<lck->smb2.in.lock_count;i++) {
1044                         if (!(lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_UNLOCK)) {
1045                                 int j = lck2->generic.in.ulock_cnt + 
1046                                         lck2->generic.in.lock_cnt;
1047                                 lck2->generic.in.lock_cnt++;
1048                                 lck2->generic.in.locks[j].pid = 0;
1049                                 lck2->generic.in.locks[j].offset = lck->smb2.in.locks[i].offset;
1050                                 lck2->generic.in.locks[j].count = lck->smb2.in.locks[i].length;
1051                                 lck2->generic.in.locks[j].pid = 0;
1052                                 if (!(lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_EXCLUSIVE)) {
1053                                         lck2->generic.in.mode = LOCKING_ANDX_SHARED_LOCK;
1054                                 }
1055                                 if (lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_FAIL_IMMEDIATELY) {
1056                                         lck2->generic.in.timeout = 0;
1057                                 }
1058                         }
1059                 }
1060                 /* initialize output value */
1061                 lck->smb2.out.reserved = 0;
1062                 break;
1063         }
1064
1065         case RAW_LOCK_SMB2_BREAK:
1066                 lck2->generic.level             = RAW_LOCK_GENERIC;
1067                 lck2->generic.in.file.ntvfs     = lck->smb2_break.in.file.ntvfs;
1068                 lck2->generic.in.mode           = LOCKING_ANDX_OPLOCK_RELEASE |
1069                                                   ((lck->smb2_break.in.oplock_level << 8) & 0xFF00);
1070                 lck2->generic.in.timeout        = 0;
1071                 lck2->generic.in.ulock_cnt      = 0;
1072                 lck2->generic.in.lock_cnt       = 0;
1073                 lck2->generic.in.locks          = NULL;
1074
1075                 /* initialize output value */
1076                 lck->smb2_break.out.oplock_level= lck->smb2_break.in.oplock_level;
1077                 lck->smb2_break.out.reserved    = lck->smb2_break.in.reserved;
1078                 lck->smb2_break.out.reserved2   = lck->smb2_break.in.reserved2;
1079                 lck->smb2_break.out.file        = lck->smb2_break.in.file;
1080                 break;
1081         }
1082
1083         /* 
1084          * we don't need to call ntvfs_map_async_setup() here,
1085          * as lock() doesn't have any output fields
1086          */
1087
1088         return ntvfs->ops->lock(ntvfs, req, lck2);
1089 }
1090
1091
1092 /* 
1093    NTVFS write generic to any mapper
1094 */
1095 static NTSTATUS ntvfs_map_write_finish(struct ntvfs_module_context *ntvfs,
1096                                        struct ntvfs_request *req,
1097                                        union smb_write *wr, 
1098                                        union smb_write *wr2, 
1099                                        NTSTATUS status)
1100 {
1101         union smb_lock *lck;
1102         union smb_close *cl;
1103         uint_t state;
1104
1105         if (NT_STATUS_IS_ERR(status)) {
1106                 return status;
1107         }
1108
1109         switch (wr->generic.level) {
1110         case RAW_WRITE_WRITE:
1111                 wr->write.out.nwritten    = wr2->generic.out.nwritten;
1112                 break;
1113
1114         case RAW_WRITE_WRITEUNLOCK:
1115                 wr->writeunlock.out.nwritten = wr2->generic.out.nwritten;
1116
1117                 lck = talloc(wr2, union smb_lock);
1118                 if (lck == NULL) {
1119                         return NT_STATUS_NO_MEMORY;
1120                 }
1121
1122                 lck->unlock.level               = RAW_LOCK_UNLOCK;
1123                 lck->unlock.in.file.ntvfs       = wr->writeunlock.in.file.ntvfs;
1124                 lck->unlock.in.count            = wr->writeunlock.in.count;
1125                 lck->unlock.in.offset           = wr->writeunlock.in.offset;
1126
1127                 if (lck->unlock.in.count != 0) {
1128                         /* do the lock sync for now */
1129                         state = req->async_states->state;
1130                         req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1131                         status = ntvfs->ops->lock(ntvfs, req, lck);
1132                         req->async_states->state = state;
1133                 }
1134                 break;
1135
1136         case RAW_WRITE_WRITECLOSE:
1137                 wr->writeclose.out.nwritten    = wr2->generic.out.nwritten;
1138
1139                 cl = talloc(wr2, union smb_close);
1140                 if (cl == NULL) {
1141                         return NT_STATUS_NO_MEMORY;
1142                 }
1143
1144                 cl->close.level         = RAW_CLOSE_CLOSE;
1145                 cl->close.in.file.ntvfs = wr->writeclose.in.file.ntvfs;
1146                 cl->close.in.write_time = wr->writeclose.in.mtime;
1147
1148                 if (wr2->generic.in.count != 0) {
1149                         /* do the close sync for now */
1150                         state = req->async_states->state;
1151                         req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1152                         status = ntvfs->ops->close(ntvfs, req, cl);
1153                         req->async_states->state = state;
1154                 }
1155                 break;
1156
1157         case RAW_WRITE_SPLWRITE:
1158                 break;
1159
1160         case RAW_WRITE_SMB2:
1161                 wr->smb2.out._pad       = 0;
1162                 wr->smb2.out.nwritten   = wr2->generic.out.nwritten;
1163                 wr->smb2.out.unknown1   = 0;
1164                 break;
1165
1166         default:
1167                 return NT_STATUS_INVALID_LEVEL;
1168         }
1169
1170         return status;
1171 }
1172
1173
1174 /* 
1175    NTVFS write generic to any mapper
1176 */
1177 NTSTATUS ntvfs_map_write(struct ntvfs_module_context *ntvfs,
1178                                   struct ntvfs_request *req,
1179                                   union smb_write *wr)
1180 {
1181         union smb_write *wr2;
1182         NTSTATUS status;
1183
1184         wr2 = talloc(req, union smb_write);
1185         if (wr2 == NULL) {
1186                 return NT_STATUS_NO_MEMORY;
1187         }
1188
1189         status = ntvfs_map_async_setup(ntvfs, req, wr, wr2, 
1190                                        (second_stage_t)ntvfs_map_write_finish);
1191         if (!NT_STATUS_IS_OK(status)) {
1192                 return status;
1193         }
1194
1195         wr2->writex.level = RAW_WRITE_GENERIC;
1196
1197         switch (wr->generic.level) {
1198         case RAW_WRITE_WRITEX:
1199                 status = NT_STATUS_INVALID_LEVEL;
1200                 break;
1201
1202         case RAW_WRITE_WRITE:
1203                 wr2->writex.in.file.ntvfs= wr->write.in.file.ntvfs;
1204                 wr2->writex.in.offset    = wr->write.in.offset;
1205                 wr2->writex.in.wmode     = 0;
1206                 wr2->writex.in.remaining = wr->write.in.remaining;
1207                 wr2->writex.in.count     = wr->write.in.count;
1208                 wr2->writex.in.data      = wr->write.in.data;
1209                 status = ntvfs->ops->write(ntvfs, req, wr2);
1210                 break;
1211
1212         case RAW_WRITE_WRITEUNLOCK:
1213                 wr2->writex.in.file.ntvfs= wr->writeunlock.in.file.ntvfs;
1214                 wr2->writex.in.offset    = wr->writeunlock.in.offset;
1215                 wr2->writex.in.wmode     = 0;
1216                 wr2->writex.in.remaining = wr->writeunlock.in.remaining;
1217                 wr2->writex.in.count     = wr->writeunlock.in.count;
1218                 wr2->writex.in.data      = wr->writeunlock.in.data;
1219                 status = ntvfs->ops->write(ntvfs, req, wr2);
1220                 break;
1221
1222         case RAW_WRITE_WRITECLOSE:
1223                 wr2->writex.in.file.ntvfs= wr->writeclose.in.file.ntvfs;
1224                 wr2->writex.in.offset    = wr->writeclose.in.offset;
1225                 wr2->writex.in.wmode     = 0;
1226                 wr2->writex.in.remaining = 0;
1227                 wr2->writex.in.count     = wr->writeclose.in.count;
1228                 wr2->writex.in.data      = wr->writeclose.in.data;
1229                 status = ntvfs->ops->write(ntvfs, req, wr2);
1230                 break;
1231
1232         case RAW_WRITE_SPLWRITE:
1233                 wr2->writex.in.file.ntvfs= wr->splwrite.in.file.ntvfs;
1234                 wr2->writex.in.offset    = 0;
1235                 wr2->writex.in.wmode     = 0;
1236                 wr2->writex.in.remaining = 0;
1237                 wr2->writex.in.count     = wr->splwrite.in.count;
1238                 wr2->writex.in.data      = wr->splwrite.in.data;
1239                 status = ntvfs->ops->write(ntvfs, req, wr2);
1240                 break;
1241
1242         case RAW_WRITE_SMB2:
1243                 wr2->writex.in.file.ntvfs= wr->smb2.in.file.ntvfs;
1244                 wr2->writex.in.offset    = wr->smb2.in.offset;
1245                 wr2->writex.in.wmode     = 0;
1246                 wr2->writex.in.remaining = 0;
1247                 wr2->writex.in.count     = wr->smb2.in.data.length;
1248                 wr2->writex.in.data      = wr->smb2.in.data.data;
1249                 status = ntvfs->ops->write(ntvfs, req, wr2);
1250         }
1251
1252         return ntvfs_map_async_finish(req, status);
1253 }
1254
1255
1256 /* 
1257    NTVFS read generic to any mapper - finish the out mapping
1258 */
1259 static NTSTATUS ntvfs_map_read_finish(struct ntvfs_module_context *ntvfs,
1260                                       struct ntvfs_request *req, 
1261                                       union smb_read *rd, 
1262                                       union smb_read *rd2,
1263                                       NTSTATUS status)
1264 {
1265         switch (rd->generic.level) {
1266         case RAW_READ_READ:
1267                 rd->read.out.nread      = rd2->generic.out.nread;
1268                 break;
1269         case RAW_READ_READBRAW:
1270                 rd->readbraw.out.nread  = rd2->generic.out.nread;
1271                 break;
1272         case RAW_READ_LOCKREAD:
1273                 rd->lockread.out.nread  = rd2->generic.out.nread;
1274                 break;
1275         case RAW_READ_SMB2:
1276                 rd->smb2.out.data.length= rd2->generic.out.nread;
1277                 rd->smb2.out.remaining  = 0;
1278                 rd->smb2.out.reserved   = 0;
1279                 break;
1280         default:
1281                 return NT_STATUS_INVALID_LEVEL;
1282         }
1283
1284         return status;
1285 }
1286
1287 /* 
1288    NTVFS read* to readx mapper
1289 */
1290 NTSTATUS ntvfs_map_read(struct ntvfs_module_context *ntvfs,
1291                                  struct ntvfs_request *req,
1292                                  union smb_read *rd)
1293 {
1294         union smb_read *rd2;
1295         union smb_lock *lck;
1296         NTSTATUS status;
1297         uint_t state;
1298
1299         rd2 = talloc(req, union smb_read);
1300         if (rd2 == NULL) {
1301                 return NT_STATUS_NO_MEMORY;
1302         }
1303
1304         status = ntvfs_map_async_setup(ntvfs, req, rd, rd2, 
1305                                        (second_stage_t)ntvfs_map_read_finish);
1306         if (!NT_STATUS_IS_OK(status)) {
1307                 return status;
1308         }
1309
1310         rd2->readx.level = RAW_READ_READX;
1311         rd2->readx.in.read_for_execute = false;
1312
1313         switch (rd->generic.level) {
1314         case RAW_READ_READX:
1315                 status = NT_STATUS_INVALID_LEVEL;
1316                 break;
1317
1318         case RAW_READ_READ:
1319                 rd2->readx.in.file.ntvfs= rd->read.in.file.ntvfs;
1320                 rd2->readx.in.offset    = rd->read.in.offset;
1321                 rd2->readx.in.mincnt    = rd->read.in.count;
1322                 rd2->readx.in.maxcnt    = rd->read.in.count;
1323                 rd2->readx.in.remaining = rd->read.in.remaining;
1324                 rd2->readx.out.data     = rd->read.out.data;
1325                 status = ntvfs->ops->read(ntvfs, req, rd2);
1326                 break;
1327
1328         case RAW_READ_READBRAW:
1329                 rd2->readx.in.file.ntvfs= rd->readbraw.in.file.ntvfs;
1330                 rd2->readx.in.offset    = rd->readbraw.in.offset;
1331                 rd2->readx.in.mincnt    = rd->readbraw.in.mincnt;
1332                 rd2->readx.in.maxcnt    = rd->readbraw.in.maxcnt;
1333                 rd2->readx.in.remaining = 0;
1334                 rd2->readx.out.data     = rd->readbraw.out.data;
1335                 status = ntvfs->ops->read(ntvfs, req, rd2);
1336                 break;
1337
1338         case RAW_READ_LOCKREAD:
1339                 /* do the initial lock sync for now */
1340                 state = req->async_states->state;
1341                 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1342
1343                 lck = talloc(rd2, union smb_lock);
1344                 if (lck == NULL) {
1345                         status = NT_STATUS_NO_MEMORY;
1346                         goto done;
1347                 }
1348                 lck->lock.level         = RAW_LOCK_LOCK;
1349                 lck->lock.in.file.ntvfs = rd->lockread.in.file.ntvfs;
1350                 lck->lock.in.count      = rd->lockread.in.count;
1351                 lck->lock.in.offset     = rd->lockread.in.offset;
1352                 status = ntvfs->ops->lock(ntvfs, req, lck);
1353                 req->async_states->state = state;
1354
1355                 rd2->readx.in.file.ntvfs= rd->lockread.in.file.ntvfs;
1356                 rd2->readx.in.offset    = rd->lockread.in.offset;
1357                 rd2->readx.in.mincnt    = rd->lockread.in.count;
1358                 rd2->readx.in.maxcnt    = rd->lockread.in.count;
1359                 rd2->readx.in.remaining = rd->lockread.in.remaining;
1360                 rd2->readx.out.data     = rd->lockread.out.data;
1361
1362                 if (NT_STATUS_IS_OK(status)) {
1363                         status = ntvfs->ops->read(ntvfs, req, rd2);
1364                 }
1365                 break;
1366
1367         case RAW_READ_SMB2:
1368                 rd2->readx.in.file.ntvfs= rd->smb2.in.file.ntvfs;
1369                 rd2->readx.in.offset    = rd->smb2.in.offset;
1370                 rd2->readx.in.mincnt    = rd->smb2.in.length;
1371                 rd2->readx.in.maxcnt    = rd->smb2.in.length;
1372                 rd2->readx.in.remaining = 0;
1373                 rd2->readx.out.data     = rd->smb2.out.data.data;
1374                 status = ntvfs->ops->read(ntvfs, req, rd2);
1375                 break;
1376         }
1377
1378 done:
1379         return ntvfs_map_async_finish(req, status);
1380 }
1381
1382
1383 /* 
1384    NTVFS close generic to any mapper
1385 */
1386 NTSTATUS ntvfs_map_close(struct ntvfs_module_context *ntvfs,
1387                                   struct ntvfs_request *req,
1388                                   union smb_close *cl)
1389 {
1390         union smb_close *cl2;
1391
1392         cl2 = talloc(req, union smb_close);
1393         if (cl2 == NULL) {
1394                 return NT_STATUS_NO_MEMORY;
1395         }
1396
1397         switch (cl->generic.level) {
1398         case RAW_CLOSE_CLOSE:
1399                 return NT_STATUS_INVALID_LEVEL;
1400
1401         case RAW_CLOSE_SPLCLOSE:
1402                 cl2->generic.level              = RAW_CLOSE_CLOSE;
1403                 cl2->generic.in.file.ntvfs      = cl->splclose.in.file.ntvfs;
1404                 cl2->generic.in.write_time      = 0;
1405                 break;
1406
1407         case RAW_CLOSE_SMB2:
1408                 cl2->generic.level              = RAW_CLOSE_CLOSE;
1409                 cl2->generic.in.file.ntvfs      = cl->smb2.in.file.ntvfs;
1410                 cl2->generic.in.write_time      = 0;
1411                 /* SMB2 Close has output parameter, but we just zero them */
1412                 ZERO_STRUCT(cl->smb2.out);
1413                 break;
1414         }
1415
1416         /* 
1417          * we don't need to call ntvfs_map_async_setup() here,
1418          * as close() doesn't have any output fields
1419          */
1420
1421         return ntvfs->ops->close(ntvfs, req, cl2);
1422 }
1423
1424 /* 
1425    NTVFS notify generic to any mapper
1426 */
1427 static NTSTATUS ntvfs_map_notify_finish(struct ntvfs_module_context *ntvfs,
1428                                         struct ntvfs_request *req,
1429                                         union smb_notify *nt, 
1430                                         union smb_notify *nt2, 
1431                                         NTSTATUS status)
1432 {
1433         NT_STATUS_NOT_OK_RETURN(status);
1434
1435         switch (nt->nttrans.level) {
1436         case RAW_NOTIFY_SMB2:
1437                 if (nt2->nttrans.out.num_changes == 0) {
1438                         return STATUS_NOTIFY_ENUM_DIR;
1439                 }
1440                 nt->smb2.out.num_changes        = nt2->nttrans.out.num_changes;
1441                 nt->smb2.out.changes            = talloc_steal(req, nt2->nttrans.out.changes);
1442                 break;
1443
1444         default:
1445                 return NT_STATUS_INVALID_LEVEL;
1446         }
1447
1448         return status;
1449 }
1450
1451
1452 /* 
1453    NTVFS notify generic to any mapper
1454 */
1455 NTSTATUS ntvfs_map_notify(struct ntvfs_module_context *ntvfs,
1456                                    struct ntvfs_request *req,
1457                                    union smb_notify *nt)
1458 {
1459         union smb_notify *nt2;
1460         NTSTATUS status;
1461
1462         nt2 = talloc(req, union smb_notify);
1463         NT_STATUS_HAVE_NO_MEMORY(nt2);
1464
1465         status = ntvfs_map_async_setup(ntvfs, req, nt, nt2, 
1466                                        (second_stage_t)ntvfs_map_notify_finish);
1467         NT_STATUS_NOT_OK_RETURN(status);
1468
1469         nt2->nttrans.level = RAW_NOTIFY_NTTRANS;
1470
1471         switch (nt->nttrans.level) {
1472         case RAW_NOTIFY_NTTRANS:
1473                 status = NT_STATUS_INVALID_LEVEL;
1474                 break;
1475
1476         case RAW_NOTIFY_SMB2:
1477                 nt2->nttrans.in.file.ntvfs              = nt->smb2.in.file.ntvfs;
1478                 nt2->nttrans.in.buffer_size             = nt->smb2.in.buffer_size;
1479                 nt2->nttrans.in.completion_filter       = nt->smb2.in.completion_filter;
1480                 nt2->nttrans.in.recursive               = nt->smb2.in.recursive;
1481                 status = ntvfs->ops->notify(ntvfs, req, nt2);
1482                 break;
1483         }
1484
1485         return ntvfs_map_async_finish(req, status);
1486 }