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