2 Unix SMB/CIFS implementation.
4 NTVFS generic level mapping code
6 Copyright (C) Andrew Tridgell 2003-2004
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 variant 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
38 DENY_DOS mapping for OpenX
40 static BOOL is_exe_file(const char *fname)
43 p = strrchr(fname, '.');
48 if (strcasecmp(p, "EXE") == 0 ||
49 strcasecmp(p, "COM") == 0 ||
50 strcasecmp(p, "DLL") == 0 ||
51 strcasecmp(p, "SYM") == 0) {
59 NTVFS open generic to any mapper
61 NTSTATUS ntvfs_map_open(struct smbsrv_request *req, union smb_open *io,
62 struct ntvfs_module_context *ntvfs)
67 io2 = talloc_p(req, union smb_open);
69 return NT_STATUS_NO_MEMORY;
72 /* must be synchronous, or we won't be called to do the
74 req->control_flags &= ~REQ_CONTROL_MAY_ASYNC;
76 switch (io->generic.level) {
77 case RAW_OPEN_GENERIC:
78 return NT_STATUS_INVALID_LEVEL;
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;
86 if (io->openx.in.flags & OPENX_FLAGS_REQUEST_BATCH_OPLOCK) {
87 io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
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;
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;
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;
106 return NT_STATUS_INVALID_LOCK_SEQUENCE;
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;
113 case OPENX_MODE_DENY_WRITE:
114 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
116 case OPENX_MODE_DENY_ALL:
117 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
119 case OPENX_MODE_DENY_NONE:
120 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
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;
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;
131 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
135 case OPENX_MODE_DENY_FCB:
136 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
139 return NT_STATUS_INVALID_LOCK_SEQUENCE;
142 switch (io->openx.in.open_func) {
143 case (OPENX_OPEN_FUNC_OPEN):
144 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN;
146 case (OPENX_OPEN_FUNC_TRUNC):
147 io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
149 case (OPENX_OPEN_FUNC_FAIL | OPENX_OPEN_FUNC_CREATE):
150 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
152 case (OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE):
153 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
155 case (OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE):
156 io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
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;
165 return NT_STATUS_INVALID_LOCK_SEQUENCE;
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;
172 status = ntvfs->ops->open(ntvfs, req, io2);
173 if (!NT_STATUS_IS_OK(status)) {
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;
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);
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;
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",
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;
221 case OPEN_FLAGS_OPEN_WRITE:
222 io2->generic.in.access_mask = GENERIC_RIGHTS_FILE_WRITE;
223 io->open.out.rmode = DOS_OPEN_WRONLY;
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 */
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;
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;
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;
247 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
251 case OPEN_FLAGS_DENY_ALL:
252 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
254 case OPEN_FLAGS_DENY_WRITE:
255 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
257 case OPEN_FLAGS_DENY_READ:
258 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_WRITE;
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;
264 case 0x70: /* FCB mode */
265 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
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;
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));
275 status = ntvfs->ops->open(ntvfs, req, io2);
276 if (!NT_STATUS_IS_OK(status)) {
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;
290 return NT_STATUS_INVALID_LEVEL;
295 NTVFS fsinfo generic to any mapper
297 NTSTATUS ntvfs_map_fsinfo(struct smbsrv_request *req, union smb_fsinfo *fs,
298 struct ntvfs_module_context *ntvfs)
301 union smb_fsinfo *fs2;
303 fs2 = talloc_p(req, union smb_fsinfo);
305 return NT_STATUS_NO_MEMORY;
308 if (fs->generic.level == RAW_QFS_GENERIC) {
309 return NT_STATUS_INVALID_LEVEL;
312 /* ask the backend for the generic info */
313 fs2->generic.level = RAW_QFS_GENERIC;
315 status = ntvfs->ops->fsinfo(ntvfs, req, fs2);
316 if (!NT_STATUS_IS_OK(status)) {
320 /* and convert it to the required level */
321 switch (fs->generic.level) {
322 case RAW_QFS_GENERIC:
323 return NT_STATUS_INVALID_LEVEL;
325 case RAW_QFS_DSKATTR: {
326 /* map from generic to DSKATTR */
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) {
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);
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;
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;
361 fs->volume.out.serial_number = fs2->generic.out.serial_number;
362 fs->volume.out.volume_name.s = fs2->generic.out.volume_name;
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;
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;
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;
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;
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;
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;
408 case RAW_QFS_OBJECTID_INFORMATION:
409 fs->objectid_information.out.guid = fs2->generic.out.guid;
410 ZERO_STRUCT(fs->objectid_information.out.unknown);
415 return NT_STATUS_INVALID_LEVEL;
420 NTVFS fileinfo generic to any mapper
422 NTSTATUS ntvfs_map_fileinfo(struct smbsrv_request *req, union smb_fileinfo *info,
423 union smb_fileinfo *info2)
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);
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;
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;
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;
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;
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;
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;
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;
509 case RAW_FILEINFO_INTERNAL_INFORMATION:
510 info->internal_information.out.file_id = info2->generic.out.file_id;
513 case RAW_FILEINFO_EA_INFO:
514 case RAW_FILEINFO_EA_INFORMATION:
515 info->ea_info.out.ea_size = info2->generic.out.ea_size;
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;
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;
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;
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;
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;
558 case RAW_FILEINFO_POSITION_INFORMATION:
559 info->position_information.out.position = info2->generic.out.position;
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;
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;
580 info->all_eas.out.eas[i].value.data =
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;
592 case RAW_FILEINFO_IS_NAME_VALID:
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;
604 case RAW_FILEINFO_ACCESS_INFORMATION:
605 info->access_information.out.access_flags = info2->generic.out.access_flags;
608 case RAW_FILEINFO_MODE_INFORMATION:
609 info->mode_information.out.mode = info2->generic.out.mode;
612 case RAW_FILEINFO_ALIGNMENT_INFORMATION:
613 info->alignment_information.out.alignment_requirement =
614 info2->generic.out.alignment_requirement;
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;
633 case RAW_FILEINFO_UNIX_LINK:
634 info->unix_link_info.out.link_dest = info2->generic.out.link_dest;
639 return NT_STATUS_INVALID_LEVEL;
643 NTVFS fileinfo generic to any mapper
645 NTSTATUS ntvfs_map_qfileinfo(struct smbsrv_request *req, union smb_fileinfo *info,
646 struct ntvfs_module_context *ntvfs)
649 union smb_fileinfo *info2;
651 info2 = talloc_p(req, union smb_fileinfo);
653 return NT_STATUS_NO_MEMORY;
656 if (info->generic.level == RAW_FILEINFO_GENERIC) {
657 return NT_STATUS_INVALID_LEVEL;
660 /* ask the backend for the generic info */
661 info2->generic.level = RAW_FILEINFO_GENERIC;
662 info2->generic.in.fnum = info->generic.in.fnum;
664 status = ntvfs->ops->qfileinfo(ntvfs, req, info2);
665 if (!NT_STATUS_IS_OK(status)) {
668 return ntvfs_map_fileinfo(req, info, info2);
672 NTVFS pathinfo generic to any mapper
674 NTSTATUS ntvfs_map_qpathinfo(struct smbsrv_request *req, union smb_fileinfo *info,
675 struct ntvfs_module_context *ntvfs)
678 union smb_fileinfo *info2;
680 info2 = talloc_p(req, union smb_fileinfo);
682 return NT_STATUS_NO_MEMORY;
685 if (info->generic.level == RAW_FILEINFO_GENERIC) {
686 return NT_STATUS_INVALID_LEVEL;
689 /* ask the backend for the generic info */
690 info2->generic.level = RAW_FILEINFO_GENERIC;
691 info2->generic.in.fname = info->generic.in.fname;
693 /* must be synchronous, or we won't be called to do the
695 req->control_flags &= ~REQ_CONTROL_MAY_ASYNC;
697 status = ntvfs->ops->qpathinfo(ntvfs, req, info2);
698 if (!NT_STATUS_IS_OK(status)) {
701 return ntvfs_map_fileinfo(req, info, info2);
706 NTVFS lock generic to any mapper
708 NTSTATUS ntvfs_map_lock(struct smbsrv_request *req, union smb_lock *lck,
709 struct ntvfs_module_context *ntvfs)
711 union smb_lock *lck2;
712 struct smb_lock_entry *locks;
714 lck2 = talloc_p(req, union smb_lock);
716 return NT_STATUS_NO_MEMORY;
719 locks = talloc_array_p(lck2, struct smb_lock_entry, 1);
721 return NT_STATUS_NO_MEMORY;
724 switch (lck->generic.level) {
726 return NT_STATUS_INVALID_LEVEL;
729 lck2->generic.in.ulock_cnt = 0;
730 lck2->generic.in.lock_cnt = 1;
733 case RAW_LOCK_UNLOCK:
734 lck2->generic.in.ulock_cnt = 1;
735 lck2->generic.in.lock_cnt = 0;
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;
748 return ntvfs->ops->lock(ntvfs, req, lck2);
753 NTVFS write generic to any mapper
755 NTSTATUS ntvfs_map_write(struct smbsrv_request *req, union smb_write *wr,
756 struct ntvfs_module_context *ntvfs)
758 union smb_write *wr2;
763 wr2 = talloc_p(req, union smb_write);
765 return NT_STATUS_NO_MEMORY;
768 wr2->generic.level = RAW_WRITE_GENERIC;
770 /* we can't map asynchronously */
771 req->control_flags &= ~REQ_CONTROL_MAY_ASYNC;
773 switch (wr->generic.level) {
774 case RAW_WRITE_WRITEX:
775 status = NT_STATUS_INVALID_LEVEL;
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;
789 case RAW_WRITE_WRITEUNLOCK:
790 lck = talloc_p(wr2, union smb_lock);
792 return NT_STATUS_NO_MEMORY;
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;
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;
807 status = ntvfs->ops->write(ntvfs, req, wr2);
809 wr->writeunlock.out.nwritten = wr2->generic.out.nwritten;
811 if (NT_STATUS_IS_OK(status) &&
812 lck->unlock.in.count != 0) {
813 status = ntvfs->ops->lock(ntvfs, req, lck);
817 case RAW_WRITE_WRITECLOSE:
818 cl = talloc_p(wr2, union smb_close);
820 return NT_STATUS_NO_MEMORY;
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;
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;
834 status = ntvfs->ops->write(ntvfs, req, wr2);
835 wr->writeclose.out.nwritten = wr2->generic.out.nwritten;
837 if (NT_STATUS_IS_OK(status) &&
838 wr2->generic.in.count != 0) {
839 status = ntvfs->ops->close(ntvfs, req, cl);
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);
860 NTVFS read generic to any mapper
862 NTSTATUS ntvfs_map_read(struct smbsrv_request *req, union smb_read *rd,
863 struct ntvfs_module_context *ntvfs)
869 rd2 = talloc_p(req, union smb_read);
871 return NT_STATUS_NO_MEMORY;
874 rd2->generic.level = RAW_READ_GENERIC;
876 /* we can't map asynchronously */
877 req->control_flags &= ~REQ_CONTROL_MAY_ASYNC;
879 switch (rd->generic.level) {
881 status = NT_STATUS_INVALID_LEVEL;
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;
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;
906 case RAW_READ_LOCKREAD:
907 lck = talloc_p(rd2, union smb_lock);
909 return NT_STATUS_NO_MEMORY;
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;
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;
924 status = ntvfs->ops->lock(ntvfs, req, lck);
926 if (NT_STATUS_IS_OK(status)) {
927 status = ntvfs->ops->read(ntvfs, req, rd2);
928 rd->lockread.out.nread = rd2->generic.out.nread;
939 NTVFS close generic to any mapper
941 NTSTATUS ntvfs_map_close(struct smbsrv_request *req, union smb_close *cl,
942 struct ntvfs_module_context *ntvfs)
944 union smb_close *cl2;
946 cl2 = talloc_p(req, union smb_close);
948 return NT_STATUS_NO_MEMORY;
951 switch (cl->generic.level) {
952 case RAW_CLOSE_CLOSE:
953 return NT_STATUS_INVALID_LEVEL;
955 case RAW_CLOSE_SPLCLOSE:
956 cl2->close.level = RAW_CLOSE_CLOSE;
957 cl2->close.in.fnum = cl->splclose.in.fnum;
961 return ntvfs->ops->close(ntvfs, req, cl2);