2 Unix SMB/CIFS implementation.
4 NTVFS generic level mapping code
6 Copyright (C) Andrew Tridgell 2003
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.
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.
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.
23 this implements mappings between info levels for NTVFS backend calls
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
30 this allows backend writers to only implement one varient of each
31 call unless they need fine grained control of the calls.
37 see if a filename ends in EXE COM DLL or SYM. This is needed for the DENY_DOS mapping for OpenX
39 static BOOL is_exe_file(const char *fname)
42 p = strrchr(fname, '.');
47 if (strcasecmp(p, "EXE") == 0 ||
48 strcasecmp(p, "COM") == 0 ||
49 strcasecmp(p, "DLL") == 0 ||
50 strcasecmp(p, "SYM") == 0) {
58 NTVFS open generic to any mapper
60 NTSTATUS ntvfs_map_open(struct request_context *req, union smb_open *io)
65 if (io->generic.level == RAW_OPEN_GENERIC) {
66 return NT_STATUS_INVALID_LEVEL;
69 switch (io->generic.level) {
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;
76 if (io->openx.in.flags & OPENX_FLAGS_REQUEST_BATCH_OPLOCK) {
77 io2.generic.in.flags |= NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
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;
84 case OPENX_MODE_ACCESS_WRITE:
85 io2.generic.in.access_mask = GENERIC_RIGHTS_FILE_WRITE;
87 case OPENX_MODE_ACCESS_RDWR:
88 case OPENX_MODE_ACCESS_FCB:
89 io2.generic.in.access_mask = GENERIC_RIGHTS_FILE_ALL_ACCESS;
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;
97 case OPENX_MODE_DENY_WRITE:
98 io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
100 case OPENX_MODE_DENY_ALL:
101 io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
103 case OPENX_MODE_DENY_NONE:
104 io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
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;
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;
115 io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
119 case OPENX_MODE_DENY_FCB:
120 io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
124 switch (io->openx.in.open_func) {
125 case (OPENX_OPEN_FUNC_FAIL):
126 io2.generic.in.open_disposition = NTCREATEX_DISP_CREATE;
128 case (OPENX_OPEN_FUNC_OPEN):
129 io2.generic.in.open_disposition = NTCREATEX_DISP_OPEN;
131 case (OPENX_OPEN_FUNC_TRUNC):
132 io2.generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
134 case (OPENX_OPEN_FUNC_FAIL | OPENX_OPEN_FUNC_CREATE):
135 io2.generic.in.open_disposition = NTCREATEX_DISP_CREATE;
137 case (OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE):
138 io2.generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
140 case (OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE):
141 io2.generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
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;
148 status = req->conn->ntvfs_ops->open(req, &io2);
149 if (!NT_STATUS_IS_OK(status)) {
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;
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",
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;
175 case OPEN_FLAGS_OPEN_WRITE:
176 io2.generic.in.access_mask = GENERIC_RIGHTS_FILE_WRITE;
177 io->open.out.rmode = DOS_OPEN_WRONLY;
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 */
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;
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;
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;
201 io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
205 case OPEN_FLAGS_DENY_ALL:
206 io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
208 case OPEN_FLAGS_DENY_WRITE:
209 io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
211 case OPEN_FLAGS_DENY_READ:
212 io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_WRITE;
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;
218 case 0x70: /* FCB mode */
219 io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
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;
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));
229 status = req->conn->ntvfs_ops->open(req, &io2);
230 if (!NT_STATUS_IS_OK(status)) {
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;
244 return NT_STATUS_INVALID_LEVEL;
249 NTVFS fsinfo generic to any mapper
251 NTSTATUS ntvfs_map_fsinfo(struct request_context *req, union smb_fsinfo *fs)
254 union smb_fsinfo fs2;
256 if (fs->generic.level == RAW_QFS_GENERIC) {
257 return NT_STATUS_INVALID_LEVEL;
260 /* ask the backend for the generic info */
261 fs2.generic.level = RAW_QFS_GENERIC;
263 status = req->conn->ntvfs_ops->fsinfo(req, &fs2);
264 if (!NT_STATUS_IS_OK(status)) {
268 /* and convert it to the required level */
269 switch (fs->generic.level) {
270 case RAW_QFS_GENERIC:
271 return NT_STATUS_INVALID_LEVEL;
273 case RAW_QFS_DSKATTR: {
274 /* map from generic to DSKATTR */
275 unsigned bpunit = 64;
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) {
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);
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;
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;
309 fs->volume.out.serial_number = fs2.generic.out.serial_number;
310 fs->volume.out.volume_name.s = fs2.generic.out.volume_name;
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;
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;
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;
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;
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;
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;
356 case RAW_QFS_OBJECTID_INFORMATION:
357 fs->objectid_information.out.guid = fs2.generic.out.guid;
358 ZERO_STRUCT(fs->objectid_information.out.unknown);
363 return NT_STATUS_INVALID_LEVEL;
368 NTVFS fileinfo generic to any mapper
370 NTSTATUS ntvfs_map_fileinfo(struct request_context *req, union smb_fileinfo *info, union smb_fileinfo *info2)
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);
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;
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;
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;
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;
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;
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;
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;
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;
460 case RAW_FILEINFO_EA_INFO:
461 case RAW_FILEINFO_EA_INFORMATION:
462 info->ea_info.out.ea_size = info2->generic.out.ea_size;
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;
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;
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;
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;
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;
497 return NT_STATUS_INVALID_LEVEL;
501 NTVFS fileinfo generic to any mapper
503 NTSTATUS ntvfs_map_qfileinfo(struct request_context *req, union smb_fileinfo *info)
506 union smb_fileinfo info2;
508 if (info->generic.level == RAW_FILEINFO_GENERIC) {
509 return NT_STATUS_INVALID_LEVEL;
512 /* ask the backend for the generic info */
513 info2.generic.level = RAW_FILEINFO_GENERIC;
514 info2.generic.in.fnum = info->generic.in.fnum;
516 status = req->conn->ntvfs_ops->qfileinfo(req, &info2);
517 if (!NT_STATUS_IS_OK(status)) {
520 return ntvfs_map_fileinfo(req, info, &info2);
524 NTVFS pathinfo generic to any mapper
526 NTSTATUS ntvfs_map_qpathinfo(struct request_context *req, union smb_fileinfo *info)
529 union smb_fileinfo info2;
531 if (info->generic.level == RAW_FILEINFO_GENERIC) {
532 return NT_STATUS_INVALID_LEVEL;
535 /* ask the backend for the generic info */
536 info2.generic.level = RAW_FILEINFO_GENERIC;
537 info2.generic.in.fname = info->generic.in.fname;
539 status = req->conn->ntvfs_ops->qpathinfo(req, &info2);
540 if (!NT_STATUS_IS_OK(status)) {
543 return ntvfs_map_fileinfo(req, info, &info2);