r3087: fixed a typo
[gd/samba-autobuild/.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 2 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, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22 /*
23   this implements mappings between info levels for NTVFS backend calls
24
25   the idea is that each of these functions implements one of the NTVFS
26   backend calls in terms of the 'generic' call. All backends that use
27   these functions must supply the generic call, but can if it wants to
28   also implement other levels if the need arises
29
30   this allows backend writers to only implement one variant of each
31   call unless they need fine grained control of the calls.
32 */
33
34 #include "includes.h"
35
36 /*
37   see if a filename ends in EXE COM DLL or SYM. This is needed for the
38   DENY_DOS mapping for OpenX
39 */
40 static BOOL is_exe_file(const char *fname)
41 {
42         char *p;
43         p = strrchr(fname, '.');
44         if (!p) {
45                 return False;
46         }
47         p++;
48         if (strcasecmp(p, "EXE") == 0 ||
49             strcasecmp(p, "COM") == 0 ||
50             strcasecmp(p, "DLL") == 0 ||
51             strcasecmp(p, "SYM") == 0) {
52                 return True;
53         }
54         return False;
55 }
56
57
58 /* 
59    NTVFS open generic to any mapper
60 */
61 NTSTATUS ntvfs_map_open(struct smbsrv_request *req, union smb_open *io, 
62                         struct ntvfs_module_context *ntvfs)
63 {
64         NTSTATUS status;
65         union smb_open *io2;
66
67         io2 = talloc_p(req, union smb_open);
68         if (io2 == NULL) {
69                 return NT_STATUS_NO_MEMORY;
70         }
71
72         /* must be synchronous, or we won't be called to do the 
73            translation */
74         req->control_flags &= ~REQ_CONTROL_MAY_ASYNC;
75
76         switch (io->generic.level) {
77         case RAW_OPEN_GENERIC:
78                 return NT_STATUS_INVALID_LEVEL;
79
80         case RAW_OPEN_OPENX:
81                 ZERO_STRUCT(io2->generic.in);
82                 io2->generic.level = RAW_OPEN_GENERIC;
83                 if (io->openx.in.flags & OPENX_FLAGS_REQUEST_OPLOCK) {
84                         io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_OPLOCK;
85                 }
86                 if (io->openx.in.flags & OPENX_FLAGS_REQUEST_BATCH_OPLOCK) {
87                         io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
88                 }
89
90                 switch (io->openx.in.open_mode & OPENX_MODE_ACCESS_MASK) {
91                 case OPENX_MODE_ACCESS_READ:
92                         io2->generic.in.access_mask = GENERIC_RIGHTS_FILE_READ;
93                         break;
94                 case OPENX_MODE_ACCESS_WRITE:
95                         io2->generic.in.access_mask = GENERIC_RIGHTS_FILE_WRITE;
96                         break;
97                 case OPENX_MODE_ACCESS_RDWR:
98                 case OPENX_MODE_ACCESS_FCB:
99                         io2->generic.in.access_mask = GENERIC_RIGHTS_FILE_ALL_ACCESS;
100                         break;
101                 }
102
103                 switch (io->openx.in.open_mode & OPENX_MODE_DENY_MASK) {
104                 case OPENX_MODE_DENY_READ:
105                         io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_WRITE;
106                         break;
107                 case OPENX_MODE_DENY_WRITE:
108                         io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
109                         break;
110                 case OPENX_MODE_DENY_ALL:
111                         io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
112                         break;
113                 case OPENX_MODE_DENY_NONE:
114                         io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
115                         break;
116                 case OPENX_MODE_DENY_DOS:
117                         /* DENY_DOS is quite strange - it depends on the filename! */
118                         if (is_exe_file(io->openx.in.fname)) {
119                                 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
120                         } else {
121                                 if ((io->openx.in.open_mode & OPENX_MODE_ACCESS_MASK) == 
122                                     OPENX_MODE_ACCESS_READ) {
123                                         io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
124                                 } else {
125                                         io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
126                                 }
127                         }
128                         break;
129                 case OPENX_MODE_DENY_FCB:
130                         io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
131                         break;
132                 }
133
134                 switch (io->openx.in.open_func) {
135                 case (OPENX_OPEN_FUNC_FAIL):
136                         io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
137                         break;
138                 case (OPENX_OPEN_FUNC_OPEN):
139                         io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN;
140                         break;
141                 case (OPENX_OPEN_FUNC_TRUNC):
142                         io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
143                         break;
144                 case (OPENX_OPEN_FUNC_FAIL | OPENX_OPEN_FUNC_CREATE):
145                         io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
146                         break;
147                 case (OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE):
148                         io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
149                         break;
150                 case (OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE):
151                         io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
152                         break;                  
153                 }
154                 io2->generic.in.alloc_size = io->openx.in.size;
155                 io2->generic.in.file_attr = io->openx.in.file_attrs;
156                 io2->generic.in.fname = io->openx.in.fname;
157
158                 status = ntvfs->ops->open(ntvfs, req, io2);
159                 if (!NT_STATUS_IS_OK(status)) {
160                         return status;
161                 }
162                 
163                 ZERO_STRUCT(io->openx.out);
164                 io->openx.out.fnum = io2->generic.out.fnum;
165                 io->openx.out.attrib = io2->generic.out.attrib;
166                 io->openx.out.write_time = nt_time_to_unix(io2->generic.out.write_time);
167                 io->openx.out.size = io2->generic.out.size;
168                 
169                 return NT_STATUS_OK;
170
171
172         case RAW_OPEN_OPEN:
173                 ZERO_STRUCT(io2->generic.in);
174                 io2->generic.level = RAW_OPEN_GENERIC;
175                 io2->generic.in.file_attr = io->open.in.search_attrs;
176                 io2->generic.in.fname = io->open.in.fname;
177                 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN;
178                 DEBUG(9,("ntvfs_map_open(OPEN): mapping flags=0x%x\n",
179                         io->open.in.flags));
180                 switch (io->open.in.flags & OPEN_FLAGS_MODE_MASK) {
181                         case OPEN_FLAGS_OPEN_READ:
182                                 io2->generic.in.access_mask = GENERIC_RIGHTS_FILE_READ;
183                                 io->open.out.rmode = DOS_OPEN_RDONLY;
184                                 break;
185                         case OPEN_FLAGS_OPEN_WRITE:
186                                 io2->generic.in.access_mask = GENERIC_RIGHTS_FILE_WRITE;
187                                 io->open.out.rmode = DOS_OPEN_WRONLY;
188                                 break;
189                         case OPEN_FLAGS_OPEN_RDWR:
190                         case 0xf: /* FCB mode */
191                                 io2->generic.in.access_mask = GENERIC_RIGHTS_FILE_READ |
192                                         GENERIC_RIGHTS_FILE_WRITE;
193                                 io->open.out.rmode = DOS_OPEN_RDWR; /* assume we got r/w */
194                                 break;
195                         default:
196                                 DEBUG(2,("ntvfs_map_open(OPEN): invalid mode 0x%x\n",
197                                         io->open.in.flags & OPEN_FLAGS_MODE_MASK));
198                                 return NT_STATUS_INVALID_PARAMETER;
199                 }
200                 
201                 switch(io->open.in.flags & OPEN_FLAGS_DENY_MASK) {
202                         case OPEN_FLAGS_DENY_DOS:
203                                 /* DENY_DOS is quite strange - it depends on the filename! */
204                                 /* REWRITE: is this necessary for OPEN? */
205                                 if (is_exe_file(io->open.in.fname)) {
206                                         io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
207                                 } else {
208                                         if ((io->open.in.flags & OPEN_FLAGS_MODE_MASK) == 
209                                             OPEN_FLAGS_OPEN_READ) {
210                                                 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
211                                         } else {
212                                                 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
213                                         }
214                                 }
215                                 break;
216                         case OPEN_FLAGS_DENY_ALL:
217                                 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
218                                 break;
219                         case OPEN_FLAGS_DENY_WRITE:
220                                 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
221                                 break;
222                         case OPEN_FLAGS_DENY_READ:
223                                 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_WRITE;
224                                 break;
225                         case OPEN_FLAGS_DENY_NONE:
226                                 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_WRITE |
227                                                 NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_DELETE;
228                                 break;
229                         case 0x70: /* FCB mode */
230                                 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
231                                 break;
232                         default:
233                                 DEBUG(2,("ntvfs_map_open(OPEN): invalid DENY 0x%x\n",
234                                         io->open.in.flags & OPEN_FLAGS_DENY_MASK));
235                                 return NT_STATUS_INVALID_PARAMETER;
236                 }
237                 DEBUG(9,("ntvfs_map_open(OPEN): mapped flags=0x%x to access_mask=0x%x and share_access=0x%x\n",
238                         io->open.in.flags, io2->generic.in.access_mask, io2->generic.in.share_access));
239
240                 status = ntvfs->ops->open(ntvfs, req, io2);
241                 if (!NT_STATUS_IS_OK(status)) {
242                         return status;
243                 }
244                 
245                 ZERO_STRUCT(io->openx.out);
246                 io->open.out.fnum = io2->generic.out.fnum;
247                 io->open.out.attrib = io2->generic.out.attrib;
248                 io->open.out.write_time = nt_time_to_unix(io2->generic.out.write_time);
249                 io->open.out.size = io2->generic.out.size;
250                 io->open.out.rmode = DOS_OPEN_RDWR;
251                 
252                 return NT_STATUS_OK;
253         }
254
255         return NT_STATUS_INVALID_LEVEL;
256 }
257
258
259 /* 
260    NTVFS fsinfo generic to any mapper
261 */
262 NTSTATUS ntvfs_map_fsinfo(struct smbsrv_request *req, union smb_fsinfo *fs, 
263                           struct ntvfs_module_context *ntvfs)
264 {
265         NTSTATUS status;
266         union smb_fsinfo *fs2;
267
268         fs2 = talloc_p(req, union smb_fsinfo);
269         if (fs2 == NULL) {
270                 return NT_STATUS_NO_MEMORY;
271         }
272
273         if (fs->generic.level == RAW_QFS_GENERIC) {
274                 return NT_STATUS_INVALID_LEVEL;
275         }
276
277         /* ask the backend for the generic info */
278         fs2->generic.level = RAW_QFS_GENERIC;
279
280         status = ntvfs->ops->fsinfo(ntvfs, req, fs2);
281         if (!NT_STATUS_IS_OK(status)) {
282                 return status;
283         }
284
285         /* and convert it to the required level */
286         switch (fs->generic.level) {
287         case RAW_QFS_GENERIC:
288                 return NT_STATUS_INVALID_LEVEL;
289
290         case RAW_QFS_DSKATTR: {
291                 /* map from generic to DSKATTR */
292                 uint_t bpunit = 64;
293
294                 /* we need to scale the sizes to fit */
295                 for (bpunit=64; bpunit<0x10000; bpunit *= 2) {
296                         if (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size < bpunit * 512 * 65535.0) {
297                                 break;
298                         }
299                 }
300
301                 fs->dskattr.out.blocks_per_unit = bpunit;
302                 fs->dskattr.out.block_size = 512;
303                 fs->dskattr.out.units_total = 
304                         (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size) / (bpunit * 512);
305                 fs->dskattr.out.units_free  = 
306                         (fs2->generic.out.blocks_free  * (double)fs2->generic.out.block_size) / (bpunit * 512);
307
308                 /* we must return a maximum of 2G to old DOS systems, or they get very confused */
309                 if (bpunit > 64 && req->smb_conn->negotiate.protocol <= PROTOCOL_LANMAN2) {
310                         fs->dskattr.out.blocks_per_unit = 64;
311                         fs->dskattr.out.units_total = 0xFFFF;
312                         fs->dskattr.out.units_free = 0xFFFF;
313                 }
314                 return NT_STATUS_OK;
315         }
316
317         case RAW_QFS_ALLOCATION:
318                 fs->allocation.out.fs_id = fs2->generic.out.fs_id;
319                 fs->allocation.out.total_alloc_units = fs2->generic.out.blocks_total;
320                 fs->allocation.out.avail_alloc_units = fs2->generic.out.blocks_free;
321                 fs->allocation.out.sectors_per_unit = 1;
322                 fs->allocation.out.bytes_per_sector = fs2->generic.out.block_size;
323                 return NT_STATUS_OK;
324
325         case RAW_QFS_VOLUME:
326                 fs->volume.out.serial_number = fs2->generic.out.serial_number;
327                 fs->volume.out.volume_name.s = fs2->generic.out.volume_name;
328                 return NT_STATUS_OK;
329
330         case RAW_QFS_VOLUME_INFO:
331         case RAW_QFS_VOLUME_INFORMATION:
332                 fs->volume_info.out.create_time = fs2->generic.out.create_time;
333                 fs->volume_info.out.serial_number = fs2->generic.out.serial_number;
334                 fs->volume_info.out.volume_name.s = fs2->generic.out.volume_name;
335                 return NT_STATUS_OK;
336
337         case RAW_QFS_SIZE_INFO:
338         case RAW_QFS_SIZE_INFORMATION:
339                 fs->size_info.out.total_alloc_units = fs2->generic.out.blocks_total;
340                 fs->size_info.out.avail_alloc_units = fs2->generic.out.blocks_free;
341                 fs->size_info.out.sectors_per_unit = 1;
342                 fs->size_info.out.bytes_per_sector = fs2->generic.out.block_size;
343                 return NT_STATUS_OK;
344
345         case RAW_QFS_DEVICE_INFO:
346         case RAW_QFS_DEVICE_INFORMATION:
347                 fs->device_info.out.device_type = fs2->generic.out.device_type;
348                 fs->device_info.out.characteristics = fs2->generic.out.device_characteristics;
349                 return NT_STATUS_OK;
350
351         case RAW_QFS_ATTRIBUTE_INFO:
352         case RAW_QFS_ATTRIBUTE_INFORMATION:
353                 fs->attribute_info.out.fs_attr = fs2->generic.out.fs_attr;
354                 fs->attribute_info.out.max_file_component_length = fs2->generic.out.max_file_component_length;
355                 fs->attribute_info.out.fs_type.s = fs2->generic.out.fs_type;
356                 return NT_STATUS_OK;
357
358         case RAW_QFS_QUOTA_INFORMATION:
359                 ZERO_STRUCT(fs->quota_information.out.unknown);
360                 fs->quota_information.out.quota_soft = fs2->generic.out.quota_soft;
361                 fs->quota_information.out.quota_hard = fs2->generic.out.quota_hard;
362                 fs->quota_information.out.quota_flags = fs2->generic.out.quota_flags;
363                 return NT_STATUS_OK;
364
365         case RAW_QFS_FULL_SIZE_INFORMATION:
366                 fs->full_size_information.out.total_alloc_units = fs2->generic.out.blocks_total;
367                 fs->full_size_information.out.call_avail_alloc_units = fs2->generic.out.blocks_free;
368                 fs->full_size_information.out.actual_avail_alloc_units = fs2->generic.out.blocks_free;
369                 fs->full_size_information.out.sectors_per_unit = 1;
370                 fs->full_size_information.out.bytes_per_sector = fs2->generic.out.block_size;
371                 return NT_STATUS_OK;
372
373         case RAW_QFS_OBJECTID_INFORMATION:
374                 fs->objectid_information.out.guid = fs2->generic.out.guid;
375                 ZERO_STRUCT(fs->objectid_information.out.unknown);
376                 return NT_STATUS_OK;
377         }
378
379
380         return NT_STATUS_INVALID_LEVEL;
381 }
382
383
384 /* 
385    NTVFS fileinfo generic to any mapper
386 */
387 NTSTATUS ntvfs_map_fileinfo(struct smbsrv_request *req, union smb_fileinfo *info, 
388                             union smb_fileinfo *info2)
389 {
390         int i;
391         /* and convert it to the required level using results in info2 */
392         switch (info->generic.level) {
393                 case RAW_FILEINFO_GENERIC:
394                 return NT_STATUS_INVALID_LEVEL;
395         case RAW_FILEINFO_GETATTR:
396                 info->getattr.out.attrib = info2->generic.out.attrib & 0xff;
397                 info->getattr.out.size = info2->generic.out.size;
398                 info->getattr.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
399                 return NT_STATUS_OK;
400                 
401         case RAW_FILEINFO_GETATTRE:
402                 info->getattre.out.attrib = info2->generic.out.attrib;
403                 info->getattre.out.size = info2->generic.out.size;
404                 info->getattre.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
405                 info->getattre.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
406                 info->getattre.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
407                 info->getattre.out.alloc_size = info2->generic.out.alloc_size;
408                 return NT_STATUS_OK;
409                 
410         case RAW_FILEINFO_NETWORK_OPEN_INFORMATION:
411                 info->network_open_information.out.create_time = info2->generic.out.create_time;
412                 info->network_open_information.out.access_time = info2->generic.out.access_time;
413                 info->network_open_information.out.write_time =  info2->generic.out.write_time;
414                 info->network_open_information.out.change_time = info2->generic.out.change_time;
415                 info->network_open_information.out.alloc_size = info2->generic.out.alloc_size;
416                 info->network_open_information.out.size = info2->generic.out.size;
417                 info->network_open_information.out.attrib = info2->generic.out.attrib;
418                 return NT_STATUS_OK;
419
420         case RAW_FILEINFO_ALL_INFO:
421         case RAW_FILEINFO_ALL_INFORMATION:
422                 info->all_info.out.create_time = info2->generic.out.create_time;
423                 info->all_info.out.access_time = info2->generic.out.access_time;
424                 info->all_info.out.write_time =  info2->generic.out.write_time;
425                 info->all_info.out.change_time = info2->generic.out.change_time;
426                 info->all_info.out.attrib = info2->generic.out.attrib;
427                 info->all_info.out.alloc_size = info2->generic.out.alloc_size;
428                 info->all_info.out.size = info2->generic.out.size;
429                 info->all_info.out.nlink = info2->generic.out.nlink;
430                 info->all_info.out.delete_pending = info2->generic.out.delete_pending;
431                 info->all_info.out.directory = info2->generic.out.directory;
432                 info->all_info.out.ea_size = info2->generic.out.ea_size;
433                 info->all_info.out.fname.s = info2->generic.out.fname.s;
434                 info->all_info.out.fname.private_length = info2->generic.out.fname.private_length;
435                 return NT_STATUS_OK;
436
437         case RAW_FILEINFO_BASIC_INFO:
438         case RAW_FILEINFO_BASIC_INFORMATION:
439                 info->basic_info.out.create_time = info2->generic.out.create_time;
440                 info->basic_info.out.access_time = info2->generic.out.access_time;
441                 info->basic_info.out.write_time = info2->generic.out.write_time;
442                 info->basic_info.out.change_time = info2->generic.out.change_time;
443                 info->basic_info.out.attrib = info2->generic.out.attrib;
444                 return NT_STATUS_OK;
445
446         case RAW_FILEINFO_STANDARD:
447                 info->standard.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
448                 info->standard.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
449                 info->standard.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
450                 info->standard.out.size = info2->generic.out.size;
451                 info->standard.out.alloc_size = info2->generic.out.alloc_size;
452                 info->standard.out.attrib = info2->generic.out.attrib;
453                 return NT_STATUS_OK;
454
455         case RAW_FILEINFO_EA_SIZE:
456                 info->ea_size.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
457                 info->ea_size.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
458                 info->ea_size.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
459                 info->ea_size.out.size = info2->generic.out.size;
460                 info->ea_size.out.alloc_size = info2->generic.out.alloc_size;
461                 info->ea_size.out.attrib = info2->generic.out.attrib;
462                 info->ea_size.out.ea_size = info2->generic.out.ea_size;
463                 return NT_STATUS_OK;
464
465         case RAW_FILEINFO_STANDARD_INFO:
466         case RAW_FILEINFO_STANDARD_INFORMATION:
467                 info->standard_info.out.alloc_size = info2->generic.out.alloc_size;
468                 info->standard_info.out.size = info2->generic.out.size;
469                 info->standard_info.out.nlink = info2->generic.out.nlink;
470                 info->standard_info.out.delete_pending = info2->generic.out.delete_pending;
471                 info->standard_info.out.directory = info2->generic.out.directory;
472                 return NT_STATUS_OK;
473
474         case RAW_FILEINFO_INTERNAL_INFORMATION:
475                 info->internal_information.out.file_id = info2->generic.out.file_id;
476                 return NT_STATUS_OK;
477
478         case RAW_FILEINFO_EA_INFO:
479         case RAW_FILEINFO_EA_INFORMATION:
480                 info->ea_info.out.ea_size = info2->generic.out.ea_size;
481                 return NT_STATUS_OK;
482
483         case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION:
484                 info->attribute_tag_information.out.attrib = info2->generic.out.attrib;
485                 info->attribute_tag_information.out.reparse_tag = info2->generic.out.reparse_tag;
486                 return NT_STATUS_OK;
487
488         case RAW_FILEINFO_STREAM_INFO:
489         case RAW_FILEINFO_STREAM_INFORMATION:
490                 info->stream_info.out.num_streams = info2->generic.out.num_streams;
491                 if (info->stream_info.out.num_streams > 0) {
492                         info->stream_info.out.streams = talloc(req, 
493                                 info->stream_info.out.num_streams * sizeof(struct stream_struct));
494                         if (!info->stream_info.out.streams) {
495                                 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d streams\n",
496                                         info->stream_info.out.num_streams));
497                                 return NT_STATUS_NO_MEMORY;
498                         }
499                         for (i=0; i < info->stream_info.out.num_streams; i++) {
500                                 info->stream_info.out.streams[i] = info2->generic.out.streams[i];
501                                 info->stream_info.out.streams[i].stream_name.s = 
502                                         talloc_strdup(req, info2->generic.out.streams[i].stream_name.s);
503                                 if (!info->stream_info.out.streams[i].stream_name.s) {
504                                         DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
505                                         return NT_STATUS_NO_MEMORY;
506                                 }
507                         }
508                 }
509                 return NT_STATUS_OK;
510
511         case RAW_FILEINFO_NAME_INFO:
512         case RAW_FILEINFO_NAME_INFORMATION:
513                 info->name_info.out.fname.s = talloc_strdup(req, info2->generic.out.fname.s);
514                 info->name_info.out.fname.private_length = info2->generic.out.fname.private_length;
515                 return NT_STATUS_OK;
516                 
517         case RAW_FILEINFO_ALT_NAME_INFO:
518         case RAW_FILEINFO_ALT_NAME_INFORMATION:
519                 info->alt_name_info.out.fname.s = talloc_strdup(req, info2->generic.out.alt_fname.s);
520                 info->alt_name_info.out.fname.private_length = info2->generic.out.alt_fname.private_length;
521                 return NT_STATUS_OK;
522         
523         case RAW_FILEINFO_POSITION_INFORMATION:
524                 info->position_information.out.position = info2->generic.out.position;
525                 return NT_STATUS_OK;
526         
527         case RAW_FILEINFO_ALL_EAS:
528                 info->all_eas.out.num_eas = info2->generic.out.num_eas;
529                 if (info->all_eas.out.num_eas > 0) {
530                         info->all_eas.out.eas = talloc(req, 
531                                 info->all_eas.out.num_eas * sizeof(struct ea_struct));
532                         if (!info->all_eas.out.eas) {
533                                 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d eas\n",
534                                         info->all_eas.out.num_eas));
535                                 return NT_STATUS_NO_MEMORY;
536                         }
537                         for (i = 0; i < info->all_eas.out.num_eas; i++) {
538                                 info->all_eas.out.eas[i] = info2->generic.out.eas[i];
539                                 info->all_eas.out.eas[i].name.s = 
540                                         talloc_strdup(req, info2->generic.out.eas[i].name.s);
541                                 if (!info->all_eas.out.eas[i].name.s) {
542                                         DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
543                                         return NT_STATUS_NO_MEMORY;
544                                 }
545                                 info->all_eas.out.eas[i].value.data = 
546                                         talloc_memdup(req,
547                                                 info2->generic.out.eas[i].value.data,
548                                                 info2->generic.out.eas[i].value.length);
549                                 if (!info->all_eas.out.eas[i].value.data) {
550                                         DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
551                                         return NT_STATUS_NO_MEMORY;
552                                 }
553                         }
554                 }
555                 return NT_STATUS_OK;
556                 
557         case RAW_FILEINFO_IS_NAME_VALID:
558                 return NT_STATUS_OK;
559                 
560         case RAW_FILEINFO_COMPRESSION_INFO:
561         case RAW_FILEINFO_COMPRESSION_INFORMATION:
562                 info->compression_info.out.compressed_size = info2->generic.out.compressed_size;
563                 info->compression_info.out.format = info2->generic.out.format;
564                 info->compression_info.out.unit_shift = info2->generic.out.unit_shift;
565                 info->compression_info.out.chunk_shift = info2->generic.out.chunk_shift;
566                 info->compression_info.out.cluster_shift = info2->generic.out.cluster_shift;
567                 return NT_STATUS_OK;
568                 
569         case RAW_FILEINFO_ACCESS_INFORMATION:
570                 info->access_information.out.access_flags = info2->generic.out.access_flags;
571                 return NT_STATUS_OK;
572                 
573         case RAW_FILEINFO_MODE_INFORMATION:
574                 info->mode_information.out.mode = info2->generic.out.mode;
575                 return NT_STATUS_OK;
576                 
577         case RAW_FILEINFO_ALIGNMENT_INFORMATION:
578                 info->alignment_information.out.alignment_requirement =
579                         info2->generic.out.alignment_requirement;
580                 return NT_STATUS_OK;
581 #if 0   
582         case RAW_FILEINFO_UNIX_BASIC:
583                 info->unix_basic_info.out.end_of_file = info2->generic.out.end_of_file;
584                 info->unix_basic_info.out.num_bytes = info2->generic.out.size;
585                 info->unix_basic_info.out.status_change_time = info2->generic.out.change_time;
586                 info->unix_basic_info.out.access_time = info2->generic.out.access_time;
587                 info->unix_basic_info.out.change_time = info2->generic.out.change_time;
588                 info->unix_basic_info.out.uid = info2->generic.out.uid;
589                 info->unix_basic_info.out.gid = info2->generic.out.gid;
590                 info->unix_basic_info.out.file_type = info2->generic.out.file_type;
591                 info->unix_basic_info.out.dev_major = info2->generic.out.device;
592                 info->unix_basic_info.out.dev_minor = info2->generic.out.device;
593                 info->unix_basic_info.out.unique_id = info2->generic.out.inode;
594                 info->unix_basic_info.out.permissions = info2->generic.out.permissions;
595                 info->unix_basic_info.out.nlink = info2->generic.out.nlink;
596                 return NT_STATUS_OK;
597                 
598         case RAW_FILEINFO_UNIX_LINK:
599                 info->unix_link_info.out.link_dest = info2->generic.out.link_dest;
600                 return NT_STATUS_OK;
601 #endif
602         }
603
604         return NT_STATUS_INVALID_LEVEL;
605 }
606
607 /* 
608    NTVFS fileinfo generic to any mapper
609 */
610 NTSTATUS ntvfs_map_qfileinfo(struct smbsrv_request *req, union smb_fileinfo *info, 
611                              struct ntvfs_module_context *ntvfs)
612 {
613         NTSTATUS status;
614         union smb_fileinfo *info2;
615
616         info2 = talloc_p(req, union smb_fileinfo);
617         if (info2 == NULL) {
618                 return NT_STATUS_NO_MEMORY;
619         }
620
621         if (info->generic.level == RAW_FILEINFO_GENERIC) {
622                 return NT_STATUS_INVALID_LEVEL;
623         }
624
625         /* ask the backend for the generic info */
626         info2->generic.level = RAW_FILEINFO_GENERIC;
627         info2->generic.in.fnum = info->generic.in.fnum;
628
629         status = ntvfs->ops->qfileinfo(ntvfs, req, info2);
630         if (!NT_STATUS_IS_OK(status)) {
631                 return status;
632         }
633         return ntvfs_map_fileinfo(req, info, info2);
634 }
635
636 /* 
637    NTVFS pathinfo generic to any mapper
638 */
639 NTSTATUS ntvfs_map_qpathinfo(struct smbsrv_request *req, union smb_fileinfo *info, 
640                              struct ntvfs_module_context *ntvfs)
641 {
642         NTSTATUS status;
643         union smb_fileinfo *info2;
644
645         info2 = talloc_p(req, union smb_fileinfo);
646         if (info2 == NULL) {
647                 return NT_STATUS_NO_MEMORY;
648         }
649
650         if (info->generic.level == RAW_FILEINFO_GENERIC) {
651                 return NT_STATUS_INVALID_LEVEL;
652         }
653
654         /* ask the backend for the generic info */
655         info2->generic.level = RAW_FILEINFO_GENERIC;
656         info2->generic.in.fname = info->generic.in.fname;
657
658         /* must be synchronous, or we won't be called to do the 
659            translation */
660         req->control_flags &= ~REQ_CONTROL_MAY_ASYNC;
661
662         status = ntvfs->ops->qpathinfo(ntvfs, req, info2);
663         if (!NT_STATUS_IS_OK(status)) {
664                 return status;
665         }
666         return ntvfs_map_fileinfo(req, info, info2);
667 }
668
669
670 /* 
671    NTVFS lock generic to any mapper
672 */
673 NTSTATUS ntvfs_map_lock(struct smbsrv_request *req, union smb_lock *lck, 
674                         struct ntvfs_module_context *ntvfs)
675 {
676         union smb_lock *lck2;
677         struct smb_lock_entry *locks;
678
679         lck2 = talloc_p(req, union smb_lock);
680         if (lck2 == NULL) {
681                 return NT_STATUS_NO_MEMORY;
682         }
683
684         locks = talloc_array_p(lck2, struct smb_lock_entry, 1);
685         if (locks == NULL) {
686                 return NT_STATUS_NO_MEMORY;
687         }
688
689         switch (lck->generic.level) {
690         case RAW_LOCK_LOCKX:
691                 return NT_STATUS_INVALID_LEVEL;
692
693         case RAW_LOCK_LOCK:
694                 lck2->generic.in.ulock_cnt = 0;
695                 lck2->generic.in.lock_cnt = 1;
696                 break;
697
698         case RAW_LOCK_UNLOCK:
699                 lck2->generic.in.ulock_cnt = 1;
700                 lck2->generic.in.lock_cnt = 0;
701                 break;
702         }
703
704         lck2->generic.level = RAW_LOCK_GENERIC;
705         lck2->generic.in.fnum = lck->lock.in.fnum;
706         lck2->generic.in.mode = 0;
707         lck2->generic.in.timeout = 0;
708         lck2->generic.in.locks = locks;
709         locks->pid = req->smbpid;
710         locks->offset = lck->lock.in.offset;
711         locks->count = lck->lock.in.count;
712
713         return ntvfs->ops->lock(ntvfs, req, lck2);
714 }
715
716
717 /* 
718    NTVFS write generic to any mapper
719 */
720 NTSTATUS ntvfs_map_write(struct smbsrv_request *req, union smb_write *wr, 
721                          struct ntvfs_module_context *ntvfs)
722 {
723         union smb_write *wr2;
724         union smb_lock *lck;
725         union smb_close *cl;
726         NTSTATUS status;
727
728         wr2 = talloc_p(req, union smb_write);
729         if (wr2 == NULL) {
730                 return NT_STATUS_NO_MEMORY;
731         }
732
733         wr2->generic.level = RAW_WRITE_GENERIC;
734
735         /* we can't map asynchronously */
736         req->control_flags &= ~REQ_CONTROL_MAY_ASYNC;
737
738         switch (wr->generic.level) {
739         case RAW_WRITE_WRITEX:
740                 status = NT_STATUS_INVALID_LEVEL;
741                 break;
742
743         case RAW_WRITE_WRITE:
744                 wr2->generic.in.fnum      = wr->write.in.fnum;
745                 wr2->generic.in.offset    = wr->write.in.offset;
746                 wr2->generic.in.wmode     = 0;
747                 wr2->generic.in.remaining = wr->write.in.remaining;
748                 wr2->generic.in.count     = wr->write.in.count;
749                 wr2->generic.in.data      = wr->write.in.data;
750                 status = ntvfs->ops->write(ntvfs, req, wr2);
751                 wr->write.out.nwritten    = wr2->generic.out.nwritten;
752                 break;
753
754         case RAW_WRITE_WRITEUNLOCK:
755                 lck = talloc_p(wr2, union smb_lock);
756                 if (lck == NULL) {
757                         return NT_STATUS_NO_MEMORY;
758                 }
759
760                 wr2->generic.in.fnum      = wr->writeunlock.in.fnum;
761                 wr2->generic.in.offset    = wr->writeunlock.in.offset;
762                 wr2->generic.in.wmode     = 0;
763                 wr2->generic.in.remaining = wr->writeunlock.in.remaining;
764                 wr2->generic.in.count     = wr->writeunlock.in.count;
765                 wr2->generic.in.data      = wr->writeunlock.in.data;
766
767                 lck->unlock.level      = RAW_LOCK_UNLOCK;
768                 lck->unlock.in.fnum    = wr->writeunlock.in.fnum;
769                 lck->unlock.in.count   = wr->writeunlock.in.count;
770                 lck->unlock.in.offset  = wr->writeunlock.in.offset;
771
772                 status = ntvfs->ops->write(ntvfs, req, wr2);
773
774                 wr->writeunlock.out.nwritten = wr2->generic.out.nwritten;
775
776                 if (NT_STATUS_IS_OK(status) && 
777                     lck->unlock.in.count != 0) {
778                         status = ntvfs->ops->lock(ntvfs, req, lck);
779                 }
780                 break;
781
782         case RAW_WRITE_WRITECLOSE:
783                 cl = talloc_p(wr2, union smb_close);
784                 if (cl == NULL) {
785                         return NT_STATUS_NO_MEMORY;
786                 }
787
788                 wr2->generic.in.fnum      = wr->writeclose.in.fnum;
789                 wr2->generic.in.offset    = wr->writeclose.in.offset;
790                 wr2->generic.in.wmode     = 0;
791                 wr2->generic.in.remaining = 0;
792                 wr2->generic.in.count     = wr->writeclose.in.count;
793                 wr2->generic.in.data      = wr->writeclose.in.data;
794
795                 cl->close.level           = RAW_CLOSE_CLOSE;
796                 cl->close.in.fnum         = wr->writeclose.in.fnum;
797                 cl->close.in.write_time   = wr->writeclose.in.mtime;
798
799                 status = ntvfs->ops->write(ntvfs, req, wr2);
800                 wr->writeclose.out.nwritten    = wr2->generic.out.nwritten;
801
802                 if (NT_STATUS_IS_OK(status) &&
803                     wr2->generic.in.count != 0) {
804                         status = ntvfs->ops->close(ntvfs, req, cl);
805                 }
806                 break;
807
808         case RAW_WRITE_SPLWRITE:
809                 wr2->generic.in.fnum      = wr->splwrite.in.fnum;
810                 wr2->generic.in.offset    = 0;
811                 wr2->generic.in.wmode     = 0;
812                 wr2->generic.in.remaining = 0;
813                 wr2->generic.in.count     = wr->splwrite.in.count;
814                 wr2->generic.in.data      = wr->splwrite.in.data;
815                 status = ntvfs->ops->write(ntvfs, req, wr2);
816                 break;
817         }
818
819
820         return status;
821 }
822
823
824 /* 
825    NTVFS read generic to any mapper
826 */
827 NTSTATUS ntvfs_map_read(struct smbsrv_request *req, union smb_read *rd, 
828                          struct ntvfs_module_context *ntvfs)
829 {
830         union smb_read *rd2;
831         union smb_lock *lck;
832         NTSTATUS status;
833
834         rd2 = talloc_p(req, union smb_read);
835         if (rd2 == NULL) {
836                 return NT_STATUS_NO_MEMORY;
837         }
838
839         rd2->generic.level = RAW_READ_GENERIC;
840
841         /* we can't map asynchronously */
842         req->control_flags &= ~REQ_CONTROL_MAY_ASYNC;
843
844         switch (rd->generic.level) {
845         case RAW_READ_READX:
846                 status = NT_STATUS_INVALID_LEVEL;
847                 break;
848
849         case RAW_READ_READ:
850                 rd2->generic.in.fnum      = rd->read.in.fnum;
851                 rd2->generic.in.offset    = rd->read.in.offset;
852                 rd2->generic.in.mincnt    = rd->read.in.count;
853                 rd2->generic.in.maxcnt    = rd->read.in.count;
854                 rd2->generic.in.remaining = rd->read.in.remaining;
855                 rd2->generic.out.data     = rd->read.out.data;
856                 status = ntvfs->ops->read(ntvfs, req, rd2);
857                 rd->read.out.nread        = rd2->generic.out.nread;
858                 break;
859
860         case RAW_READ_READBRAW:
861                 rd2->generic.in.fnum      = rd->readbraw.in.fnum;
862                 rd2->generic.in.offset    = rd->readbraw.in.offset;
863                 rd2->generic.in.mincnt    = rd->readbraw.in.mincnt;
864                 rd2->generic.in.maxcnt    = rd->readbraw.in.maxcnt;
865                 rd2->generic.in.remaining = 0;
866                 rd2->generic.out.data     = rd->readbraw.out.data;
867                 status = ntvfs->ops->read(ntvfs, req, rd2);
868                 rd->readbraw.out.nread    = rd2->generic.out.nread;
869                 break;
870
871         case RAW_READ_LOCKREAD:
872                 lck = talloc_p(rd2, union smb_lock);
873                 if (lck == NULL) {
874                         return NT_STATUS_NO_MEMORY;
875                 }
876
877                 rd2->generic.in.fnum      = rd->lockread.in.fnum;
878                 rd2->generic.in.offset    = rd->lockread.in.offset;
879                 rd2->generic.in.mincnt    = rd->lockread.in.count;
880                 rd2->generic.in.maxcnt    = rd->lockread.in.count;
881                 rd2->generic.in.remaining = rd->lockread.in.remaining;
882                 rd2->generic.out.data     = rd->lockread.out.data;
883
884                 lck->lock.level      = RAW_LOCK_LOCK;
885                 lck->lock.in.fnum    = rd->lockread.in.fnum;
886                 lck->lock.in.count   = rd->lockread.in.count;
887                 lck->lock.in.offset  = rd->lockread.in.offset;
888
889                 status = ntvfs->ops->lock(ntvfs, req, lck);
890
891                 if (NT_STATUS_IS_OK(status)) {
892                         status = ntvfs->ops->read(ntvfs, req, rd2);
893                         rd->lockread.out.nread = rd2->generic.out.nread;
894                 }
895                 break;
896         }
897
898
899         return status;
900 }
901
902
903 /* 
904    NTVFS close generic to any mapper
905 */
906 NTSTATUS ntvfs_map_close(struct smbsrv_request *req, union smb_close *cl, 
907                          struct ntvfs_module_context *ntvfs)
908 {
909         union smb_close *cl2;
910
911         cl2 = talloc_p(req, union smb_close);
912         if (cl2 == NULL) {
913                 return NT_STATUS_NO_MEMORY;
914         }
915
916         switch (cl->generic.level) {
917         case RAW_CLOSE_CLOSE:
918                 return NT_STATUS_INVALID_LEVEL;
919
920         case RAW_CLOSE_SPLCLOSE:
921                 cl2->close.level   = RAW_CLOSE_CLOSE;
922                 cl2->close.in.fnum = cl->splclose.in.fnum;
923                 break;
924         }
925
926         return ntvfs->ops->close(ntvfs, req, cl2);
927 }