first public release of samba4 code
[jelmer/samba4-debian.git] / source / ntvfs / ntvfs_generic.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    NTVFS generic level mapping code
5
6    Copyright (C) Andrew Tridgell 2003
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 varient 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 DENY_DOS mapping for OpenX
38 */
39 static BOOL is_exe_file(const char *fname)
40 {
41         char *p;
42         p = strrchr(fname, '.');
43         if (!p) {
44                 return False;
45         }
46         p++;
47         if (strcasecmp(p, "EXE") == 0 ||
48             strcasecmp(p, "COM") == 0 ||
49             strcasecmp(p, "DLL") == 0 ||
50             strcasecmp(p, "SYM") == 0) {
51                 return True;
52         }
53         return False;
54 }
55
56
57 /* 
58    NTVFS open generic to any mapper
59 */
60 NTSTATUS ntvfs_map_open(struct request_context *req, union smb_open *io)
61 {
62         NTSTATUS status;
63         union smb_open io2;
64
65         if (io->generic.level == RAW_OPEN_GENERIC) {
66                 return NT_STATUS_INVALID_LEVEL;
67         }
68
69         switch (io->generic.level) {
70         case RAW_OPEN_OPENX:
71                 ZERO_STRUCT(io2.generic.in);
72                 io2.generic.level = RAW_OPEN_GENERIC;
73                 if (io->openx.in.flags & OPENX_FLAGS_REQUEST_OPLOCK) {
74                         io2.generic.in.flags |= NTCREATEX_FLAGS_REQUEST_OPLOCK;
75                 }
76                 if (io->openx.in.flags & OPENX_FLAGS_REQUEST_BATCH_OPLOCK) {
77                         io2.generic.in.flags |= NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
78                 }
79
80                 switch (io->openx.in.open_mode & OPENX_MODE_ACCESS_MASK) {
81                 case OPENX_MODE_ACCESS_READ:
82                         io2.generic.in.access_mask = GENERIC_RIGHTS_FILE_READ;
83                         break;
84                 case OPENX_MODE_ACCESS_WRITE:
85                         io2.generic.in.access_mask = GENERIC_RIGHTS_FILE_WRITE;
86                         break;
87                 case OPENX_MODE_ACCESS_RDWR:
88                 case OPENX_MODE_ACCESS_FCB:
89                         io2.generic.in.access_mask = GENERIC_RIGHTS_FILE_ALL_ACCESS;
90                         break;
91                 }
92
93                 switch (io->openx.in.open_mode & OPENX_MODE_DENY_MASK) {
94                 case OPENX_MODE_DENY_READ:
95                         io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_WRITE;
96                         break;
97                 case OPENX_MODE_DENY_WRITE:
98                         io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
99                         break;
100                 case OPENX_MODE_DENY_ALL:
101                         io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
102                         break;
103                 case OPENX_MODE_DENY_NONE:
104                         io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
105                         break;
106                 case OPENX_MODE_DENY_DOS:
107                         /* DENY_DOS is quite strange - it depends on the filename! */
108                         if (is_exe_file(io->openx.in.fname)) {
109                                 io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
110                         } else {
111                                 if ((io->openx.in.open_mode & OPENX_MODE_ACCESS_MASK) == 
112                                     OPENX_MODE_ACCESS_READ) {
113                                         io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
114                                 } else {
115                                         io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
116                                 }
117                         }
118                         break;
119                 case OPENX_MODE_DENY_FCB:
120                         io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
121                         break;
122                 }
123
124                 switch (io->openx.in.open_func) {
125                 case (OPENX_OPEN_FUNC_FAIL):
126                         io2.generic.in.open_disposition = NTCREATEX_DISP_CREATE;
127                         break;
128                 case (OPENX_OPEN_FUNC_OPEN):
129                         io2.generic.in.open_disposition = NTCREATEX_DISP_OPEN;
130                         break;
131                 case (OPENX_OPEN_FUNC_TRUNC):
132                         io2.generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
133                         break;
134                 case (OPENX_OPEN_FUNC_FAIL | OPENX_OPEN_FUNC_CREATE):
135                         io2.generic.in.open_disposition = NTCREATEX_DISP_CREATE;
136                         break;
137                 case (OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE):
138                         io2.generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
139                         break;
140                 case (OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE):
141                         io2.generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
142                         break;                  
143                 }
144                 io2.generic.in.alloc_size = io->openx.in.size;
145                 io2.generic.in.file_attr = io->openx.in.file_attrs;
146                 io2.generic.in.fname = io->openx.in.fname;
147
148                 status = req->conn->ntvfs_ops->open(req, &io2);
149                 if (!NT_STATUS_IS_OK(status)) {
150                         return status;
151                 }
152                 
153                 ZERO_STRUCT(io->openx.out);
154                 io->openx.out.fnum = io2.generic.out.fnum;
155                 io->openx.out.attrib = io2.generic.out.attrib;
156                 io->openx.out.write_time = nt_time_to_unix(&io2.generic.out.write_time);
157                 io->openx.out.size = io2.generic.out.size;
158                 
159                 return NT_STATUS_OK;
160
161
162         case RAW_OPEN_OPEN:
163                 ZERO_STRUCT(io2.generic.in);
164                 io2.generic.level = RAW_OPEN_GENERIC;
165                 io2.generic.in.file_attr = io->open.in.search_attrs;
166                 io2.generic.in.fname = io->open.in.fname;
167                 io2.generic.in.open_disposition = NTCREATEX_DISP_OPEN;
168                 DEBUG(9,("ntvfs_map_open(OPEN): mapping flags=0x%x\n",
169                         io->open.in.flags));
170                 switch (io->open.in.flags & OPEN_FLAGS_MODE_MASK) {
171                         case OPEN_FLAGS_OPEN_READ:
172                                 io2.generic.in.access_mask = GENERIC_RIGHTS_FILE_READ;
173                                 io->open.out.rmode = DOS_OPEN_RDONLY;
174                                 break;
175                         case OPEN_FLAGS_OPEN_WRITE:
176                                 io2.generic.in.access_mask = GENERIC_RIGHTS_FILE_WRITE;
177                                 io->open.out.rmode = DOS_OPEN_WRONLY;
178                                 break;
179                         case OPEN_FLAGS_OPEN_RDWR:
180                         case 0xf: /* FCB mode */
181                                 io2.generic.in.access_mask = GENERIC_RIGHTS_FILE_ALL_ACCESS;
182                                 io->open.out.rmode = DOS_OPEN_RDWR; /* assume we got r/w */
183                                 break;
184                         default:
185                                 DEBUG(2,("ntvfs_map_open(OPEN): invalid mode 0x%x\n",
186                                         io->open.in.flags & OPEN_FLAGS_MODE_MASK));
187                                 return NT_STATUS_INVALID_PARAMETER;
188                 }
189                 
190                 switch(io->open.in.flags & OPEN_FLAGS_DENY_MASK) {
191                         case OPEN_FLAGS_DENY_DOS:
192                                 /* DENY_DOS is quite strange - it depends on the filename! */
193                                 /* REWRITE: is this necessary for OPEN? */
194                                 if (is_exe_file(io->open.in.fname)) {
195                                         io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
196                                 } else {
197                                         if ((io->open.in.flags & OPEN_FLAGS_MODE_MASK) == 
198                                             OPEN_FLAGS_OPEN_READ) {
199                                                 io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
200                                         } else {
201                                                 io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
202                                         }
203                                 }
204                                 break;
205                         case OPEN_FLAGS_DENY_ALL:
206                                 io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
207                                 break;
208                         case OPEN_FLAGS_DENY_WRITE:
209                                 io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
210                                 break;
211                         case OPEN_FLAGS_DENY_READ:
212                                 io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_WRITE;
213                                 break;
214                         case OPEN_FLAGS_DENY_NONE:
215                                 io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_WRITE |
216                                                 NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_DELETE;
217                                 break;
218                         case 0x70: /* FCB mode */
219                                 io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
220                                 break;
221                         default:
222                                 DEBUG(2,("ntvfs_map_open(OPEN): invalid DENY 0x%x\n",
223                                         io->open.in.flags & OPEN_FLAGS_DENY_MASK));
224                                 return NT_STATUS_INVALID_PARAMETER;
225                 }
226                 DEBUG(9,("ntvfs_map_open(OPEN): mapped flags=0x%x to access_mask=0x%x and share_access=0x%x\n",
227                         io->open.in.flags, io2.generic.in.access_mask, io2.generic.in.share_access));
228
229                 status = req->conn->ntvfs_ops->open(req, &io2);
230                 if (!NT_STATUS_IS_OK(status)) {
231                         return status;
232                 }
233                 
234                 ZERO_STRUCT(io->openx.out);
235                 io->open.out.fnum = io2.generic.out.fnum;
236                 io->open.out.attrib = io2.generic.out.attrib;
237                 io->open.out.write_time = nt_time_to_unix(&io2.generic.out.write_time);
238                 io->open.out.size = io2.generic.out.size;
239                 io->open.out.rmode = DOS_OPEN_RDWR;
240                 
241                 return NT_STATUS_OK;
242         }
243
244         return NT_STATUS_INVALID_LEVEL;
245 }
246
247
248 /* 
249    NTVFS fsinfo generic to any mapper
250 */
251 NTSTATUS ntvfs_map_fsinfo(struct request_context *req, union smb_fsinfo *fs)
252 {
253         NTSTATUS status;
254         union smb_fsinfo fs2;
255
256         if (fs->generic.level == RAW_QFS_GENERIC) {
257                 return NT_STATUS_INVALID_LEVEL;
258         }
259
260         /* ask the backend for the generic info */
261         fs2.generic.level = RAW_QFS_GENERIC;
262
263         status = req->conn->ntvfs_ops->fsinfo(req, &fs2);
264         if (!NT_STATUS_IS_OK(status)) {
265                 return status;
266         }
267
268         /* and convert it to the required level */
269         switch (fs->generic.level) {
270         case RAW_QFS_GENERIC:
271                 return NT_STATUS_INVALID_LEVEL;
272
273         case RAW_QFS_DSKATTR: {
274                 /* map from generic to DSKATTR */
275                 unsigned bpunit = 64;
276
277                 /* we need to scale the sizes to fit */
278                 for (bpunit=64; bpunit<0x10000; bpunit *= 2) {
279                         if (fs2.generic.out.blocks_total * (double)fs2.generic.out.block_size < bpunit * 512 * 65535.0) {
280                                 break;
281                         }
282                 }
283
284                 fs->dskattr.out.blocks_per_unit = bpunit;
285                 fs->dskattr.out.block_size = 512;
286                 fs->dskattr.out.units_total = 
287                         (fs2.generic.out.blocks_total * (double)fs2.generic.out.block_size) / (bpunit * 512);
288                 fs->dskattr.out.units_free  = 
289                         (fs2.generic.out.blocks_free  * (double)fs2.generic.out.block_size) / (bpunit * 512);
290
291                 /* we must return a maximum of 2G to old DOS systems, or they get very confused */
292                 if (bpunit > 64 && req->smb->negotiate.protocol <= PROTOCOL_LANMAN2) {
293                         fs->dskattr.out.blocks_per_unit = 64;
294                         fs->dskattr.out.units_total = 0xFFFF;
295                         fs->dskattr.out.units_free = 0xFFFF;
296                 }
297                 return NT_STATUS_OK;
298         }
299
300         case RAW_QFS_ALLOCATION:
301                 fs->allocation.out.fs_id = fs2.generic.out.fs_id;
302                 fs->allocation.out.total_alloc_units = fs2.generic.out.blocks_total;
303                 fs->allocation.out.avail_alloc_units = fs2.generic.out.blocks_free;
304                 fs->allocation.out.sectors_per_unit = 1;
305                 fs->allocation.out.bytes_per_sector = fs2.generic.out.block_size;
306                 return NT_STATUS_OK;
307
308         case RAW_QFS_VOLUME:
309                 fs->volume.out.serial_number = fs2.generic.out.serial_number;
310                 fs->volume.out.volume_name.s = fs2.generic.out.volume_name;
311                 return NT_STATUS_OK;
312
313         case RAW_QFS_VOLUME_INFO:
314         case RAW_QFS_VOLUME_INFORMATION:
315                 fs->volume_info.out.create_time = fs2.generic.out.create_time;
316                 fs->volume_info.out.serial_number = fs2.generic.out.serial_number;
317                 fs->volume_info.out.volume_name.s = fs2.generic.out.volume_name;
318                 return NT_STATUS_OK;
319
320         case RAW_QFS_SIZE_INFO:
321         case RAW_QFS_SIZE_INFORMATION:
322                 fs->size_info.out.total_alloc_units = fs2.generic.out.blocks_total;
323                 fs->size_info.out.avail_alloc_units = fs2.generic.out.blocks_free;
324                 fs->size_info.out.sectors_per_unit = 1;
325                 fs->size_info.out.bytes_per_sector = fs2.generic.out.block_size;
326                 return NT_STATUS_OK;
327
328         case RAW_QFS_DEVICE_INFO:
329         case RAW_QFS_DEVICE_INFORMATION:
330                 fs->device_info.out.device_type = fs2.generic.out.device_type;
331                 fs->device_info.out.characteristics = fs2.generic.out.device_characteristics;
332                 return NT_STATUS_OK;
333
334         case RAW_QFS_ATTRIBUTE_INFO:
335         case RAW_QFS_ATTRIBUTE_INFORMATION:
336                 fs->attribute_info.out.fs_attr = fs2.generic.out.fs_attr;
337                 fs->attribute_info.out.max_file_component_length = fs2.generic.out.max_file_component_length;
338                 fs->attribute_info.out.fs_type.s = fs2.generic.out.fs_type;
339                 return NT_STATUS_OK;
340
341         case RAW_QFS_QUOTA_INFORMATION:
342                 ZERO_STRUCT(fs->quota_information.out.unknown);
343                 fs->quota_information.out.quota_soft = fs2.generic.out.quota_soft;
344                 fs->quota_information.out.quota_hard = fs2.generic.out.quota_hard;
345                 fs->quota_information.out.quota_flags = fs2.generic.out.quota_flags;
346                 return NT_STATUS_OK;
347
348         case RAW_QFS_FULL_SIZE_INFORMATION:
349                 fs->full_size_information.out.total_alloc_units = fs2.generic.out.blocks_total;
350                 fs->full_size_information.out.call_avail_alloc_units = fs2.generic.out.blocks_free;
351                 fs->full_size_information.out.actual_avail_alloc_units = fs2.generic.out.blocks_free;
352                 fs->full_size_information.out.sectors_per_unit = 1;
353                 fs->full_size_information.out.bytes_per_sector = fs2.generic.out.block_size;
354                 return NT_STATUS_OK;
355
356         case RAW_QFS_OBJECTID_INFORMATION:
357                 fs->objectid_information.out.guid = fs2.generic.out.guid;
358                 ZERO_STRUCT(fs->objectid_information.out.unknown);
359                 return NT_STATUS_OK;
360         }
361
362
363         return NT_STATUS_INVALID_LEVEL;
364 }
365
366
367 /* 
368    NTVFS fileinfo generic to any mapper
369 */
370 NTSTATUS ntvfs_map_fileinfo(struct request_context *req, union smb_fileinfo *info, union smb_fileinfo *info2)
371 {
372         /* and convert it to the required level using results in info2 */
373         switch (info->generic.level) {
374                 case RAW_FILEINFO_GENERIC:
375                 return NT_STATUS_INVALID_LEVEL;
376         case RAW_FILEINFO_GETATTR:
377                 info->getattr.out.attrib = info2->generic.out.attrib & 0x3f;
378                 info->getattr.out.size = info2->generic.out.size;
379                 info->getattr.out.write_time = nt_time_to_unix(&info2->generic.out.write_time);
380                 return NT_STATUS_OK;
381                 
382         case RAW_FILEINFO_GETATTRE:
383                 info->getattre.out.attrib = info2->generic.out.attrib;
384                 info->getattre.out.size = info2->generic.out.size;
385                 info->getattre.out.write_time = nt_time_to_unix(&info2->generic.out.write_time);
386                 info->getattre.out.create_time = nt_time_to_unix(&info2->generic.out.create_time);
387                 info->getattre.out.access_time = nt_time_to_unix(&info2->generic.out.access_time);
388                 info->getattre.out.alloc_size = info2->generic.out.alloc_size;
389                 return NT_STATUS_OK;
390                 
391         case RAW_FILEINFO_NETWORK_OPEN_INFORMATION:
392                 info->network_open_information.out.create_time = info2->generic.out.create_time;
393                 info->network_open_information.out.access_time = info2->generic.out.access_time;
394                 info->network_open_information.out.write_time =  info2->generic.out.write_time;
395                 info->network_open_information.out.change_time = info2->generic.out.change_time;
396                 info->network_open_information.out.alloc_size = info2->generic.out.alloc_size;
397                 info->network_open_information.out.size = info2->generic.out.size;
398                 info->network_open_information.out.attrib = info2->generic.out.attrib;
399                 return NT_STATUS_OK;
400
401         case RAW_FILEINFO_ALL_INFO:
402         case RAW_FILEINFO_ALL_INFORMATION:
403                 info->all_info.out.create_time = info2->generic.out.create_time;
404                 info->all_info.out.access_time = info2->generic.out.access_time;
405                 info->all_info.out.write_time =  info2->generic.out.write_time;
406                 info->all_info.out.change_time = info2->generic.out.change_time;
407                 info->all_info.out.attrib = info2->generic.out.attrib;
408                 info->all_info.out.alloc_size = info2->generic.out.alloc_size;
409                 info->all_info.out.size = info2->generic.out.size;
410                 info->all_info.out.nlink = info2->generic.out.nlink;
411                 info->all_info.out.delete_pending = info2->generic.out.delete_pending;
412                 info->all_info.out.directory = info2->generic.out.directory;
413                 info->all_info.out.ea_size = info2->generic.out.ea_size;
414                 info->all_info.out.fname.s = info2->generic.out.fname.s;
415                 info->all_info.out.fname.private_length = info2->generic.out.fname.private_length;
416                 return NT_STATUS_OK;
417
418         case RAW_FILEINFO_BASIC_INFO:
419         case RAW_FILEINFO_BASIC_INFORMATION:
420                 info->basic_info.out.create_time = info2->generic.out.create_time;
421                 info->basic_info.out.access_time = info2->generic.out.access_time;
422                 info->basic_info.out.write_time = info2->generic.out.write_time;
423                 info->basic_info.out.change_time = info2->generic.out.change_time;
424                 info->basic_info.out.attrib = info2->generic.out.attrib;
425                 return NT_STATUS_OK;
426
427         case RAW_FILEINFO_STANDARD:
428                 info->standard.out.create_time = nt_time_to_unix(&info2->generic.out.create_time);
429                 info->standard.out.access_time = nt_time_to_unix(&info2->generic.out.access_time);
430                 info->standard.out.write_time = nt_time_to_unix(&info2->generic.out.write_time);
431                 info->standard.out.size = info2->generic.out.size;
432                 info->standard.out.alloc_size = info2->generic.out.alloc_size;
433                 info->standard.out.attrib = info2->generic.out.attrib;
434                 return NT_STATUS_OK;
435
436         case RAW_FILEINFO_EA_SIZE:
437                 info->ea_size.out.create_time = nt_time_to_unix(&info2->generic.out.create_time);
438                 info->ea_size.out.access_time = nt_time_to_unix(&info2->generic.out.access_time);
439                 info->ea_size.out.write_time = nt_time_to_unix(&info2->generic.out.write_time);
440                 info->ea_size.out.size = info2->generic.out.size;
441                 info->ea_size.out.alloc_size = info2->generic.out.alloc_size;
442                 info->ea_size.out.attrib = info2->generic.out.attrib;
443                 info->ea_size.out.ea_size = info2->generic.out.ea_size;
444                 return NT_STATUS_OK;
445
446         case RAW_FILEINFO_STANDARD_INFO:
447         case RAW_FILEINFO_STANDARD_INFORMATION:
448                 info->standard_info.out.alloc_size = info2->generic.out.alloc_size;
449                 info->standard_info.out.size = info2->generic.out.size;
450                 info->standard_info.out.nlink = info2->generic.out.nlink;
451                 info->standard_info.out.delete_pending = info2->generic.out.delete_pending;
452                 info->standard_info.out.directory = info2->generic.out.directory;
453                 return NT_STATUS_OK;
454
455         case RAW_FILEINFO_INTERNAL_INFORMATION:
456                 info->internal_information.out.device = info2->generic.out.device;
457                 info->internal_information.out.inode = info2->generic.out.inode;
458                 return NT_STATUS_OK;
459
460         case RAW_FILEINFO_EA_INFO:
461         case RAW_FILEINFO_EA_INFORMATION:
462                 info->ea_info.out.ea_size = info2->generic.out.ea_size;
463                 return NT_STATUS_OK;
464
465         case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION:
466                 info->attribute_tag_information.out.attrib = info2->generic.out.attrib;
467                 info->attribute_tag_information.out.reparse_tag = info2->generic.out.reparse_tag;
468                 return NT_STATUS_OK;
469
470         case RAW_FILEINFO_STREAM_INFO:
471         case RAW_FILEINFO_STREAM_INFORMATION:
472                 /* setup a single data stream */
473                 info->stream_info.out.num_streams = info2->generic.out.num_streams;
474                 info->stream_info.out.streams = talloc(req->mem_ctx, sizeof(info2->stream_info.out.streams[0]));
475                 if (!info->stream_info.out.streams) {
476                         return NT_STATUS_NO_MEMORY;
477                 }
478                 info->stream_info.out.streams[0].size = info2->generic.out.streams[0].size;
479                 info->stream_info.out.streams[0].alloc_size = info2->generic.out.streams[0].alloc_size;
480                 info->stream_info.out.streams[0].stream_name.s = info2->generic.out.streams[0].stream_name.s;
481                 info->stream_info.out.streams[0].stream_name.private_length = info->generic.out.streams[0].stream_name.private_length;
482                 return NT_STATUS_OK;
483
484         case RAW_FILEINFO_NAME_INFO:
485         case RAW_FILEINFO_NAME_INFORMATION:
486                 info->name_info.out.fname.s = info2->generic.out.fname.s;
487                 info->name_info.out.fname.private_length = info2->generic.out.fname.private_length;
488                 return NT_STATUS_OK;
489                 
490         case RAW_FILEINFO_ALT_NAME_INFO:
491         case RAW_FILEINFO_ALT_NAME_INFORMATION:
492                 info->alt_name_info.out.fname.s = info2->generic.out.alt_fname.s;
493                 info->alt_name_info.out.fname.private_length = info2->generic.out.alt_fname.private_length;
494                 return NT_STATUS_OK;
495         }
496
497         return NT_STATUS_INVALID_LEVEL;
498 }
499
500 /* 
501    NTVFS fileinfo generic to any mapper
502 */
503 NTSTATUS ntvfs_map_qfileinfo(struct request_context *req, union smb_fileinfo *info)
504 {
505         NTSTATUS status;
506         union smb_fileinfo info2;
507
508         if (info->generic.level == RAW_FILEINFO_GENERIC) {
509                 return NT_STATUS_INVALID_LEVEL;
510         }
511
512         /* ask the backend for the generic info */
513         info2.generic.level = RAW_FILEINFO_GENERIC;
514         info2.generic.in.fnum = info->generic.in.fnum;
515
516         status = req->conn->ntvfs_ops->qfileinfo(req, &info2);
517         if (!NT_STATUS_IS_OK(status)) {
518                 return status;
519         }
520         return ntvfs_map_fileinfo(req, info, &info2);
521 }
522
523 /* 
524    NTVFS pathinfo generic to any mapper
525 */
526 NTSTATUS ntvfs_map_qpathinfo(struct request_context *req, union smb_fileinfo *info)
527 {
528         NTSTATUS status;
529         union smb_fileinfo info2;
530
531         if (info->generic.level == RAW_FILEINFO_GENERIC) {
532                 return NT_STATUS_INVALID_LEVEL;
533         }
534
535         /* ask the backend for the generic info */
536         info2.generic.level = RAW_FILEINFO_GENERIC;
537         info2.generic.in.fname = info->generic.in.fname;
538
539         status = req->conn->ntvfs_ops->qpathinfo(req, &info2);
540         if (!NT_STATUS_IS_OK(status)) {
541                 return status;
542         }
543         return ntvfs_map_fileinfo(req, info, &info2);
544 }