r1291: rename struct smbsrv_context to smbsrv_connection
[bbaumbach/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
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 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 smbsrv_request *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->tcon->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_READ |
182                                         GENERIC_RIGHTS_FILE_WRITE;
183                                 io->open.out.rmode = DOS_OPEN_RDWR; /* assume we got r/w */
184                                 break;
185                         default:
186                                 DEBUG(2,("ntvfs_map_open(OPEN): invalid mode 0x%x\n",
187                                         io->open.in.flags & OPEN_FLAGS_MODE_MASK));
188                                 return NT_STATUS_INVALID_PARAMETER;
189                 }
190                 
191                 switch(io->open.in.flags & OPEN_FLAGS_DENY_MASK) {
192                         case OPEN_FLAGS_DENY_DOS:
193                                 /* DENY_DOS is quite strange - it depends on the filename! */
194                                 /* REWRITE: is this necessary for OPEN? */
195                                 if (is_exe_file(io->open.in.fname)) {
196                                         io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
197                                 } else {
198                                         if ((io->open.in.flags & OPEN_FLAGS_MODE_MASK) == 
199                                             OPEN_FLAGS_OPEN_READ) {
200                                                 io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
201                                         } else {
202                                                 io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
203                                         }
204                                 }
205                                 break;
206                         case OPEN_FLAGS_DENY_ALL:
207                                 io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
208                                 break;
209                         case OPEN_FLAGS_DENY_WRITE:
210                                 io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
211                                 break;
212                         case OPEN_FLAGS_DENY_READ:
213                                 io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_WRITE;
214                                 break;
215                         case OPEN_FLAGS_DENY_NONE:
216                                 io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_WRITE |
217                                                 NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_DELETE;
218                                 break;
219                         case 0x70: /* FCB mode */
220                                 io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
221                                 break;
222                         default:
223                                 DEBUG(2,("ntvfs_map_open(OPEN): invalid DENY 0x%x\n",
224                                         io->open.in.flags & OPEN_FLAGS_DENY_MASK));
225                                 return NT_STATUS_INVALID_PARAMETER;
226                 }
227                 DEBUG(9,("ntvfs_map_open(OPEN): mapped flags=0x%x to access_mask=0x%x and share_access=0x%x\n",
228                         io->open.in.flags, io2.generic.in.access_mask, io2.generic.in.share_access));
229
230                 status = req->tcon->ntvfs_ops->open(req, &io2);
231                 if (!NT_STATUS_IS_OK(status)) {
232                         return status;
233                 }
234                 
235                 ZERO_STRUCT(io->openx.out);
236                 io->open.out.fnum = io2.generic.out.fnum;
237                 io->open.out.attrib = io2.generic.out.attrib;
238                 io->open.out.write_time = nt_time_to_unix(io2.generic.out.write_time);
239                 io->open.out.size = io2.generic.out.size;
240                 io->open.out.rmode = DOS_OPEN_RDWR;
241                 
242                 return NT_STATUS_OK;
243         }
244
245         return NT_STATUS_INVALID_LEVEL;
246 }
247
248
249 /* 
250    NTVFS fsinfo generic to any mapper
251 */
252 NTSTATUS ntvfs_map_fsinfo(struct smbsrv_request *req, union smb_fsinfo *fs)
253 {
254         NTSTATUS status;
255         union smb_fsinfo fs2;
256
257         if (fs->generic.level == RAW_QFS_GENERIC) {
258                 return NT_STATUS_INVALID_LEVEL;
259         }
260
261         /* ask the backend for the generic info */
262         fs2.generic.level = RAW_QFS_GENERIC;
263
264         status = req->tcon->ntvfs_ops->fsinfo(req, &fs2);
265         if (!NT_STATUS_IS_OK(status)) {
266                 return status;
267         }
268
269         /* and convert it to the required level */
270         switch (fs->generic.level) {
271         case RAW_QFS_GENERIC:
272                 return NT_STATUS_INVALID_LEVEL;
273
274         case RAW_QFS_DSKATTR: {
275                 /* map from generic to DSKATTR */
276                 uint_t bpunit = 64;
277
278                 /* we need to scale the sizes to fit */
279                 for (bpunit=64; bpunit<0x10000; bpunit *= 2) {
280                         if (fs2.generic.out.blocks_total * (double)fs2.generic.out.block_size < bpunit * 512 * 65535.0) {
281                                 break;
282                         }
283                 }
284
285                 fs->dskattr.out.blocks_per_unit = bpunit;
286                 fs->dskattr.out.block_size = 512;
287                 fs->dskattr.out.units_total = 
288                         (fs2.generic.out.blocks_total * (double)fs2.generic.out.block_size) / (bpunit * 512);
289                 fs->dskattr.out.units_free  = 
290                         (fs2.generic.out.blocks_free  * (double)fs2.generic.out.block_size) / (bpunit * 512);
291
292                 /* we must return a maximum of 2G to old DOS systems, or they get very confused */
293                 if (bpunit > 64 && req->smb_conn->negotiate.protocol <= PROTOCOL_LANMAN2) {
294                         fs->dskattr.out.blocks_per_unit = 64;
295                         fs->dskattr.out.units_total = 0xFFFF;
296                         fs->dskattr.out.units_free = 0xFFFF;
297                 }
298                 return NT_STATUS_OK;
299         }
300
301         case RAW_QFS_ALLOCATION:
302                 fs->allocation.out.fs_id = fs2.generic.out.fs_id;
303                 fs->allocation.out.total_alloc_units = fs2.generic.out.blocks_total;
304                 fs->allocation.out.avail_alloc_units = fs2.generic.out.blocks_free;
305                 fs->allocation.out.sectors_per_unit = 1;
306                 fs->allocation.out.bytes_per_sector = fs2.generic.out.block_size;
307                 return NT_STATUS_OK;
308
309         case RAW_QFS_VOLUME:
310                 fs->volume.out.serial_number = fs2.generic.out.serial_number;
311                 fs->volume.out.volume_name.s = fs2.generic.out.volume_name;
312                 return NT_STATUS_OK;
313
314         case RAW_QFS_VOLUME_INFO:
315         case RAW_QFS_VOLUME_INFORMATION:
316                 fs->volume_info.out.create_time = fs2.generic.out.create_time;
317                 fs->volume_info.out.serial_number = fs2.generic.out.serial_number;
318                 fs->volume_info.out.volume_name.s = fs2.generic.out.volume_name;
319                 return NT_STATUS_OK;
320
321         case RAW_QFS_SIZE_INFO:
322         case RAW_QFS_SIZE_INFORMATION:
323                 fs->size_info.out.total_alloc_units = fs2.generic.out.blocks_total;
324                 fs->size_info.out.avail_alloc_units = fs2.generic.out.blocks_free;
325                 fs->size_info.out.sectors_per_unit = 1;
326                 fs->size_info.out.bytes_per_sector = fs2.generic.out.block_size;
327                 return NT_STATUS_OK;
328
329         case RAW_QFS_DEVICE_INFO:
330         case RAW_QFS_DEVICE_INFORMATION:
331                 fs->device_info.out.device_type = fs2.generic.out.device_type;
332                 fs->device_info.out.characteristics = fs2.generic.out.device_characteristics;
333                 return NT_STATUS_OK;
334
335         case RAW_QFS_ATTRIBUTE_INFO:
336         case RAW_QFS_ATTRIBUTE_INFORMATION:
337                 fs->attribute_info.out.fs_attr = fs2.generic.out.fs_attr;
338                 fs->attribute_info.out.max_file_component_length = fs2.generic.out.max_file_component_length;
339                 fs->attribute_info.out.fs_type.s = fs2.generic.out.fs_type;
340                 return NT_STATUS_OK;
341
342         case RAW_QFS_QUOTA_INFORMATION:
343                 ZERO_STRUCT(fs->quota_information.out.unknown);
344                 fs->quota_information.out.quota_soft = fs2.generic.out.quota_soft;
345                 fs->quota_information.out.quota_hard = fs2.generic.out.quota_hard;
346                 fs->quota_information.out.quota_flags = fs2.generic.out.quota_flags;
347                 return NT_STATUS_OK;
348
349         case RAW_QFS_FULL_SIZE_INFORMATION:
350                 fs->full_size_information.out.total_alloc_units = fs2.generic.out.blocks_total;
351                 fs->full_size_information.out.call_avail_alloc_units = fs2.generic.out.blocks_free;
352                 fs->full_size_information.out.actual_avail_alloc_units = fs2.generic.out.blocks_free;
353                 fs->full_size_information.out.sectors_per_unit = 1;
354                 fs->full_size_information.out.bytes_per_sector = fs2.generic.out.block_size;
355                 return NT_STATUS_OK;
356
357         case RAW_QFS_OBJECTID_INFORMATION:
358                 fs->objectid_information.out.guid = fs2.generic.out.guid;
359                 ZERO_STRUCT(fs->objectid_information.out.unknown);
360                 return NT_STATUS_OK;
361         }
362
363
364         return NT_STATUS_INVALID_LEVEL;
365 }
366
367
368 /* 
369    NTVFS fileinfo generic to any mapper
370 */
371 NTSTATUS ntvfs_map_fileinfo(struct smbsrv_request *req, union smb_fileinfo *info, union smb_fileinfo *info2)
372 {
373         int i;
374         /* and convert it to the required level using results in info2 */
375         switch (info->generic.level) {
376                 case RAW_FILEINFO_GENERIC:
377                 return NT_STATUS_INVALID_LEVEL;
378         case RAW_FILEINFO_GETATTR:
379                 info->getattr.out.attrib = info2->generic.out.attrib & 0xff;
380                 info->getattr.out.size = info2->generic.out.size;
381                 info->getattr.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
382                 return NT_STATUS_OK;
383                 
384         case RAW_FILEINFO_GETATTRE:
385                 info->getattre.out.attrib = info2->generic.out.attrib;
386                 info->getattre.out.size = info2->generic.out.size;
387                 info->getattre.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
388                 info->getattre.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
389                 info->getattre.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
390                 info->getattre.out.alloc_size = info2->generic.out.alloc_size;
391                 return NT_STATUS_OK;
392                 
393         case RAW_FILEINFO_NETWORK_OPEN_INFORMATION:
394                 info->network_open_information.out.create_time = info2->generic.out.create_time;
395                 info->network_open_information.out.access_time = info2->generic.out.access_time;
396                 info->network_open_information.out.write_time =  info2->generic.out.write_time;
397                 info->network_open_information.out.change_time = info2->generic.out.change_time;
398                 info->network_open_information.out.alloc_size = info2->generic.out.alloc_size;
399                 info->network_open_information.out.size = info2->generic.out.size;
400                 info->network_open_information.out.attrib = info2->generic.out.attrib;
401                 return NT_STATUS_OK;
402
403         case RAW_FILEINFO_ALL_INFO:
404         case RAW_FILEINFO_ALL_INFORMATION:
405                 info->all_info.out.create_time = info2->generic.out.create_time;
406                 info->all_info.out.access_time = info2->generic.out.access_time;
407                 info->all_info.out.write_time =  info2->generic.out.write_time;
408                 info->all_info.out.change_time = info2->generic.out.change_time;
409                 info->all_info.out.attrib = info2->generic.out.attrib;
410                 info->all_info.out.alloc_size = info2->generic.out.alloc_size;
411                 info->all_info.out.size = info2->generic.out.size;
412                 info->all_info.out.nlink = info2->generic.out.nlink;
413                 info->all_info.out.delete_pending = info2->generic.out.delete_pending;
414                 info->all_info.out.directory = info2->generic.out.directory;
415                 info->all_info.out.ea_size = info2->generic.out.ea_size;
416                 info->all_info.out.fname.s = info2->generic.out.fname.s;
417                 info->all_info.out.fname.private_length = info2->generic.out.fname.private_length;
418                 return NT_STATUS_OK;
419
420         case RAW_FILEINFO_BASIC_INFO:
421         case RAW_FILEINFO_BASIC_INFORMATION:
422                 info->basic_info.out.create_time = info2->generic.out.create_time;
423                 info->basic_info.out.access_time = info2->generic.out.access_time;
424                 info->basic_info.out.write_time = info2->generic.out.write_time;
425                 info->basic_info.out.change_time = info2->generic.out.change_time;
426                 info->basic_info.out.attrib = info2->generic.out.attrib;
427                 return NT_STATUS_OK;
428
429         case RAW_FILEINFO_STANDARD:
430                 info->standard.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
431                 info->standard.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
432                 info->standard.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
433                 info->standard.out.size = info2->generic.out.size;
434                 info->standard.out.alloc_size = info2->generic.out.alloc_size;
435                 info->standard.out.attrib = info2->generic.out.attrib;
436                 return NT_STATUS_OK;
437
438         case RAW_FILEINFO_EA_SIZE:
439                 info->ea_size.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
440                 info->ea_size.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
441                 info->ea_size.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
442                 info->ea_size.out.size = info2->generic.out.size;
443                 info->ea_size.out.alloc_size = info2->generic.out.alloc_size;
444                 info->ea_size.out.attrib = info2->generic.out.attrib;
445                 info->ea_size.out.ea_size = info2->generic.out.ea_size;
446                 return NT_STATUS_OK;
447
448         case RAW_FILEINFO_STANDARD_INFO:
449         case RAW_FILEINFO_STANDARD_INFORMATION:
450                 info->standard_info.out.alloc_size = info2->generic.out.alloc_size;
451                 info->standard_info.out.size = info2->generic.out.size;
452                 info->standard_info.out.nlink = info2->generic.out.nlink;
453                 info->standard_info.out.delete_pending = info2->generic.out.delete_pending;
454                 info->standard_info.out.directory = info2->generic.out.directory;
455                 return NT_STATUS_OK;
456
457         case RAW_FILEINFO_INTERNAL_INFORMATION:
458                 info->internal_information.out.file_id = info2->generic.out.file_id;
459                 return NT_STATUS_OK;
460
461         case RAW_FILEINFO_EA_INFO:
462         case RAW_FILEINFO_EA_INFORMATION:
463                 info->ea_info.out.ea_size = info2->generic.out.ea_size;
464                 return NT_STATUS_OK;
465
466         case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION:
467                 info->attribute_tag_information.out.attrib = info2->generic.out.attrib;
468                 info->attribute_tag_information.out.reparse_tag = info2->generic.out.reparse_tag;
469                 return NT_STATUS_OK;
470
471         case RAW_FILEINFO_STREAM_INFO:
472         case RAW_FILEINFO_STREAM_INFORMATION:
473                 info->stream_info.out.num_streams = info2->generic.out.num_streams;
474                 if (info->stream_info.out.num_streams > 0) {
475                         info->stream_info.out.streams = talloc(req->mem_ctx, 
476                                 info->stream_info.out.num_streams * sizeof(struct stream_struct));
477                         if (!info->stream_info.out.streams) {
478                                 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d streams\n",
479                                         info->stream_info.out.num_streams));
480                                 return NT_STATUS_NO_MEMORY;
481                         }
482                         for (i=0; i < info->stream_info.out.num_streams; i++) {
483                                 info->stream_info.out.streams[i] = info2->generic.out.streams[i];
484                                 info->stream_info.out.streams[i].stream_name.s = 
485                                         talloc_strdup(req->mem_ctx, info2->generic.out.streams[i].stream_name.s);
486                                 if (!info->stream_info.out.streams[i].stream_name.s) {
487                                         DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
488                                         return NT_STATUS_NO_MEMORY;
489                                 }
490                         }
491                 }
492                 return NT_STATUS_OK;
493
494         case RAW_FILEINFO_NAME_INFO:
495         case RAW_FILEINFO_NAME_INFORMATION:
496                 info->name_info.out.fname.s = talloc_strdup(req->mem_ctx, info2->generic.out.fname.s);
497                 info->name_info.out.fname.private_length = info2->generic.out.fname.private_length;
498                 return NT_STATUS_OK;
499                 
500         case RAW_FILEINFO_ALT_NAME_INFO:
501         case RAW_FILEINFO_ALT_NAME_INFORMATION:
502                 info->alt_name_info.out.fname.s = talloc_strdup(req->mem_ctx, info2->generic.out.alt_fname.s);
503                 info->alt_name_info.out.fname.private_length = info2->generic.out.alt_fname.private_length;
504                 return NT_STATUS_OK;
505         
506         case RAW_FILEINFO_POSITION_INFORMATION:
507                 info->position_information.out.position = info2->generic.out.position;
508                 return NT_STATUS_OK;
509         
510         case RAW_FILEINFO_ALL_EAS:
511                 info->all_eas.out.num_eas = info2->generic.out.num_eas;
512                 if (info->all_eas.out.num_eas > 0) {
513                         info->all_eas.out.eas = talloc(req->mem_ctx, 
514                                 info->all_eas.out.num_eas * sizeof(struct ea_struct));
515                         if (!info->all_eas.out.eas) {
516                                 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d eas\n",
517                                         info->all_eas.out.num_eas));
518                                 return NT_STATUS_NO_MEMORY;
519                         }
520                         for (i = 0; i < info->all_eas.out.num_eas; i++) {
521                                 info->all_eas.out.eas[i] = info2->generic.out.eas[i];
522                                 info->all_eas.out.eas[i].name.s = 
523                                         talloc_strdup(req->mem_ctx, info2->generic.out.eas[i].name.s);
524                                 if (!info->all_eas.out.eas[i].name.s) {
525                                         DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
526                                         return NT_STATUS_NO_MEMORY;
527                                 }
528                                 info->all_eas.out.eas[i].value.data = 
529                                         talloc_memdup(req->mem_ctx,
530                                                 info2->generic.out.eas[i].value.data,
531                                                 info2->generic.out.eas[i].value.length);
532                                 if (!info->all_eas.out.eas[i].value.data) {
533                                         DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
534                                         return NT_STATUS_NO_MEMORY;
535                                 }
536                         }
537                 }
538                 return NT_STATUS_OK;
539                 
540         case RAW_FILEINFO_IS_NAME_VALID:
541                 return NT_STATUS_OK;
542                 
543         case RAW_FILEINFO_COMPRESSION_INFO:
544         case RAW_FILEINFO_COMPRESSION_INFORMATION:
545                 info->compression_info.out.compressed_size = info2->generic.out.compressed_size;
546                 info->compression_info.out.format = info2->generic.out.format;
547                 info->compression_info.out.unit_shift = info2->generic.out.unit_shift;
548                 info->compression_info.out.chunk_shift = info2->generic.out.chunk_shift;
549                 info->compression_info.out.cluster_shift = info2->generic.out.cluster_shift;
550                 return NT_STATUS_OK;
551                 
552         case RAW_FILEINFO_ACCESS_INFORMATION:
553                 info->access_information.out.access_flags = info2->generic.out.access_flags;
554                 return NT_STATUS_OK;
555                 
556         case RAW_FILEINFO_MODE_INFORMATION:
557                 info->mode_information.out.mode = info2->generic.out.mode;
558                 return NT_STATUS_OK;
559                 
560         case RAW_FILEINFO_ALIGNMENT_INFORMATION:
561                 info->alignment_information.out.alignment_requirement =
562                         info2->generic.out.alignment_requirement;
563                 return NT_STATUS_OK;
564 #if 0   
565         case RAW_FILEINFO_UNIX_BASIC:
566                 info->unix_basic_info.out.end_of_file = info2->generic.out.end_of_file;
567                 info->unix_basic_info.out.num_bytes = info2->generic.out.size;
568                 info->unix_basic_info.out.status_change_time = info2->generic.out.change_time;
569                 info->unix_basic_info.out.access_time = info2->generic.out.access_time;
570                 info->unix_basic_info.out.change_time = info2->generic.out.change_time;
571                 info->unix_basic_info.out.uid = info2->generic.out.uid;
572                 info->unix_basic_info.out.gid = info2->generic.out.gid;
573                 info->unix_basic_info.out.file_type = info2->generic.out.file_type;
574                 info->unix_basic_info.out.dev_major = info2->generic.out.device;
575                 info->unix_basic_info.out.dev_minor = info2->generic.out.device;
576                 info->unix_basic_info.out.unique_id = info2->generic.out.inode;
577                 info->unix_basic_info.out.permissions = info2->generic.out.permissions;
578                 info->unix_basic_info.out.nlink = info2->generic.out.nlink;
579                 return NT_STATUS_OK;
580                 
581         case RAW_FILEINFO_UNIX_LINK:
582                 info->unix_link_info.out.link_dest = info2->generic.out.link_dest;
583                 return NT_STATUS_OK;
584 #endif
585         }
586
587         return NT_STATUS_INVALID_LEVEL;
588 }
589
590 /* 
591    NTVFS fileinfo generic to any mapper
592 */
593 NTSTATUS ntvfs_map_qfileinfo(struct smbsrv_request *req, union smb_fileinfo *info)
594 {
595         NTSTATUS status;
596         union smb_fileinfo info2;
597
598         if (info->generic.level == RAW_FILEINFO_GENERIC) {
599                 return NT_STATUS_INVALID_LEVEL;
600         }
601
602         /* ask the backend for the generic info */
603         info2.generic.level = RAW_FILEINFO_GENERIC;
604         info2.generic.in.fnum = info->generic.in.fnum;
605
606         status = req->tcon->ntvfs_ops->qfileinfo(req, &info2);
607         if (!NT_STATUS_IS_OK(status)) {
608                 return status;
609         }
610         return ntvfs_map_fileinfo(req, info, &info2);
611 }
612
613 /* 
614    NTVFS pathinfo generic to any mapper
615 */
616 NTSTATUS ntvfs_map_qpathinfo(struct smbsrv_request *req, union smb_fileinfo *info)
617 {
618         NTSTATUS status;
619         union smb_fileinfo info2;
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.fname = info->generic.in.fname;
628
629         status = req->tcon->ntvfs_ops->qpathinfo(req, &info2);
630         if (!NT_STATUS_IS_OK(status)) {
631                 return status;
632         }
633         return ntvfs_map_fileinfo(req, info, &info2);
634 }