r9152: fix a crash bug
[Samba/aatanasov.git] / source / ntvfs / ntvfs_generic.c
blob024a48bf7a7a1298606729980f0823fb692538f0
1 /*
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.
34 #include "includes.h"
35 #include "smb_server/smb_server.h"
36 #include "librpc/gen_ndr/ndr_security.h"
38 /* a second stage function converts from the out parameters of the generic
39 call onto the out parameters of the specific call made */
40 typedef NTSTATUS (*second_stage_t)(struct smbsrv_request *,
41 struct ntvfs_module_context *,
42 void *, void *, NTSTATUS);
44 /*
45 this structure holds the async state for pending mapped async calls
47 struct ntvfs_map_async {
48 struct ntvfs_module_context *ntvfs;
49 void *io, *io2;
50 second_stage_t fn;
54 this is a async wrapper, called from the backend when it has completed
55 a function that it has decided to reply to in an async fashion
57 static void ntvfs_map_async_send(struct smbsrv_request *req)
59 struct ntvfs_map_async *m = req->async_states->private_data;
61 ntvfs_async_state_pop(req);
63 /* call the _finish function setup in ntvfs_map_async_setup() */
64 req->async_states->status = m->fn(req, m->ntvfs, m->io, m->io2, req->async_states->status);
66 /* call the send function from the next module up */
67 req->async_states->send_fn(req);
71 prepare for calling a ntvfs backend with async support
72 io is the original call structure
73 io2 is the new call structure for the mapped call
74 fn is a second stage function for processing the out arguments
76 static NTSTATUS ntvfs_map_async_setup(struct smbsrv_request *req,
77 struct ntvfs_module_context *ntvfs,
78 void *io, void *io2,
79 second_stage_t fn)
81 struct ntvfs_map_async *m;
82 m = talloc(req, struct ntvfs_map_async);
83 if (m == NULL) {
84 return NT_STATUS_NO_MEMORY;
86 m->ntvfs = ntvfs;
87 m->io = io;
88 m->io2 = io2;
89 m->fn = fn;
90 return ntvfs_async_state_push(req, m, ntvfs_map_async_send, ntvfs);
95 called when first stage processing is complete.
96 */
97 static NTSTATUS ntvfs_map_async_finish(struct smbsrv_request *req, NTSTATUS status)
99 struct ntvfs_map_async *m;
101 /* if the backend has decided to reply in an async fashion then
102 we don't need to do any work here */
103 if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
104 return status;
107 /* the backend is replying immediately. call the 2nd stage function after popping our local
108 async state */
109 m = req->async_states->private_data;
111 ntvfs_async_state_pop(req);
113 return m->fn(req, m->ntvfs, m->io, m->io2, status);
118 see if a filename ends in EXE COM DLL or SYM. This is needed for the
119 DENY_DOS mapping for OpenX
121 BOOL is_exe_filename(const char *fname)
123 char *p;
124 p = strrchr(fname, '.');
125 if (!p) {
126 return False;
128 p++;
129 if (strcasecmp(p, "EXE") == 0 ||
130 strcasecmp(p, "COM") == 0 ||
131 strcasecmp(p, "DLL") == 0 ||
132 strcasecmp(p, "SYM") == 0) {
133 return True;
135 return False;
140 NTVFS openx to ntcreatex mapper
142 static NTSTATUS ntvfs_map_open_finish(struct smbsrv_request *req,
143 struct ntvfs_module_context *ntvfs,
144 union smb_open *io,
145 union smb_open *io2,
146 NTSTATUS status)
148 time_t write_time = 0;
149 uint32_t set_size = 0;
150 union smb_setfileinfo *sf;
151 uint_t state;
153 if (!NT_STATUS_IS_OK(status)) {
154 return status;
157 switch (io->generic.level) {
158 case RAW_OPEN_OPEN:
159 io->openold.out.fnum = io2->generic.out.fnum;
160 io->openold.out.attrib = io2->generic.out.attrib;
161 io->openold.out.write_time = nt_time_to_unix(io2->generic.out.write_time);
162 io->openold.out.size = io2->generic.out.size;
163 io->openold.out.rmode = io->openold.in.open_mode;
164 break;
166 case RAW_OPEN_OPENX:
167 io->openx.out.fnum = io2->generic.out.fnum;
168 io->openx.out.attrib = io2->generic.out.attrib;
169 io->openx.out.write_time = nt_time_to_unix(io2->generic.out.write_time);
170 io->openx.out.size = io2->generic.out.size;
171 io->openx.out.access = (io->openx.in.open_mode & OPENX_MODE_ACCESS_MASK);
172 io->openx.out.ftype = 0;
173 io->openx.out.devstate = 0;
174 io->openx.out.action = io2->generic.out.create_action;
175 io->openx.out.unique_fid = 0;
176 io->openx.out.access_mask = SEC_STD_ALL;
177 io->openx.out.unknown = 0;
179 /* we need to extend the file to the requested size if
180 it was newly created */
181 if (io2->generic.out.create_action == NTCREATEX_ACTION_CREATED) {
182 set_size = io->openx.in.size;
184 break;
186 case RAW_OPEN_T2OPEN:
187 io->t2open.out.fnum = io2->generic.out.fnum;
188 io->t2open.out.attrib = io2->generic.out.attrib;
189 io->t2open.out.write_time = nt_time_to_unix(io2->generic.out.write_time);
190 io->t2open.out.size = io2->generic.out.size;
191 io->t2open.out.access = io->t2open.in.open_mode;
192 io->t2open.out.ftype = 0;
193 io->t2open.out.devstate = 0;
194 io->t2open.out.action = io2->generic.out.create_action;
195 io->t2open.out.file_id = 0;
196 break;
198 case RAW_OPEN_MKNEW:
199 case RAW_OPEN_CREATE:
200 io->mknew.out.fnum = io2->generic.out.fnum;
201 write_time = io->mknew.in.write_time;
202 break;
204 case RAW_OPEN_CTEMP:
205 io->ctemp.out.fnum = io2->generic.out.fnum;
206 io->ctemp.out.name = talloc_strdup(req, io2->generic.in.fname +
207 strlen(io->ctemp.in.directory) + 1);
208 break;
210 default:
211 return NT_STATUS_INVALID_LEVEL;
214 /* doing a secondary request async is more trouble than its
215 worth */
216 state = req->async_states->state;
217 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
219 if (write_time != 0) {
220 sf = talloc(req, union smb_setfileinfo);
221 sf->generic.level = RAW_SFILEINFO_STANDARD;
222 sf->generic.file.fnum = io2->generic.out.fnum;
223 sf->standard.in.create_time = 0;
224 sf->standard.in.write_time = write_time;
225 sf->standard.in.access_time = 0;
226 status = ntvfs->ops->setfileinfo(ntvfs, req, sf);
229 if (set_size != 0) {
230 sf = talloc(req, union smb_setfileinfo);
231 sf->generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
232 sf->generic.file.fnum = io2->generic.out.fnum;
233 sf->end_of_file_info.in.size = set_size;
234 status = ntvfs->ops->setfileinfo(ntvfs, req, sf);
235 if (NT_STATUS_IS_OK(status)) {
236 io->openx.out.size = io->openx.in.size;
240 req->async_states->state = state;
242 return NT_STATUS_OK;
246 the core of the mapping between openx style parameters and ntcreatex
247 parameters
249 static NTSTATUS map_openx_open(uint16_t flags, uint16_t open_mode,
250 uint16_t open_func, const char *fname,
251 union smb_open *io2)
253 if (flags & OPENX_FLAGS_REQUEST_OPLOCK) {
254 io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_OPLOCK;
256 if (flags & OPENX_FLAGS_REQUEST_BATCH_OPLOCK) {
257 io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
260 switch (open_mode & OPENX_MODE_ACCESS_MASK) {
261 case OPENX_MODE_ACCESS_READ:
262 io2->generic.in.access_mask = SEC_RIGHTS_FILE_READ;
263 break;
264 case OPENX_MODE_ACCESS_WRITE:
265 io2->generic.in.access_mask = SEC_RIGHTS_FILE_WRITE;
266 break;
267 case OPENX_MODE_ACCESS_RDWR:
268 case OPENX_MODE_ACCESS_FCB:
269 case OPENX_MODE_ACCESS_EXEC:
270 io2->generic.in.access_mask =
271 SEC_RIGHTS_FILE_READ |
272 SEC_RIGHTS_FILE_WRITE;
273 break;
274 default:
275 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
278 switch (open_mode & OPENX_MODE_DENY_MASK) {
279 case OPENX_MODE_DENY_READ:
280 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_WRITE;
281 break;
282 case OPENX_MODE_DENY_WRITE:
283 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
284 break;
285 case OPENX_MODE_DENY_ALL:
286 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
287 break;
288 case OPENX_MODE_DENY_NONE:
289 io2->generic.in.share_access =
290 NTCREATEX_SHARE_ACCESS_READ |
291 NTCREATEX_SHARE_ACCESS_WRITE;
292 break;
293 case OPENX_MODE_DENY_DOS:
294 /* DENY_DOS is quite strange - it depends on the filename! */
295 io2->generic.in.create_options |=
296 NTCREATEX_OPTIONS_PRIVATE_DENY_DOS;
297 if (is_exe_filename(fname)) {
298 io2->generic.in.share_access =
299 NTCREATEX_SHARE_ACCESS_READ |
300 NTCREATEX_SHARE_ACCESS_WRITE;
301 } else {
302 if ((open_mode & OPENX_MODE_ACCESS_MASK) == OPENX_MODE_ACCESS_READ) {
303 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
304 } else {
305 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
308 break;
309 case OPENX_MODE_DENY_FCB:
310 io2->generic.in.create_options |= NTCREATEX_OPTIONS_PRIVATE_DENY_FCB;
311 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
312 break;
313 default:
314 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
317 switch (open_func) {
318 case (OPENX_OPEN_FUNC_OPEN):
319 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN;
320 break;
321 case (OPENX_OPEN_FUNC_TRUNC):
322 io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
323 break;
324 case (OPENX_OPEN_FUNC_FAIL | OPENX_OPEN_FUNC_CREATE):
325 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
326 break;
327 case (OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE):
328 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
329 break;
330 case (OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE):
331 io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
332 break;
333 default:
334 /* this one is very strange */
335 if ((open_mode & OPENX_MODE_ACCESS_MASK) == OPENX_MODE_ACCESS_EXEC) {
336 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
337 break;
339 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
342 return NT_STATUS_OK;
346 NTVFS open generic to any mapper
348 NTSTATUS ntvfs_map_open(struct smbsrv_request *req, union smb_open *io,
349 struct ntvfs_module_context *ntvfs)
351 NTSTATUS status;
352 union smb_open *io2;
354 io2 = talloc_zero(req, union smb_open);
355 if (io2 == NULL) {
356 return NT_STATUS_NO_MEMORY;
359 status = ntvfs_map_async_setup(req, ntvfs, io, io2,
360 (second_stage_t)ntvfs_map_open_finish);
361 if (!NT_STATUS_IS_OK(status)) {
362 return status;
365 io2->generic.level = RAW_OPEN_GENERIC;
367 switch (io->generic.level) {
368 case RAW_OPEN_OPENX:
369 status = map_openx_open(io->openx.in.flags,
370 io->openx.in.open_mode,
371 io->openx.in.open_func,
372 io->openx.in.fname,
373 io2);
374 if (!NT_STATUS_IS_OK(status)) {
375 goto done;
378 io2->generic.in.file_attr = io->openx.in.file_attrs;
379 io2->generic.in.fname = io->openx.in.fname;
381 status = ntvfs->ops->openfile(ntvfs, req, io2);
382 break;
385 case RAW_OPEN_OPEN:
386 status = map_openx_open(0,
387 io->openold.in.open_mode,
388 OPENX_OPEN_FUNC_OPEN,
389 io->openold.in.fname,
390 io2);
391 if (!NT_STATUS_IS_OK(status)) {
392 goto done;
395 io2->generic.in.file_attr = io->openold.in.search_attrs;
396 io2->generic.in.fname = io->openold.in.fname;
398 status = ntvfs->ops->openfile(ntvfs, req, io2);
399 break;
401 case RAW_OPEN_T2OPEN:
402 io2->generic.level = RAW_OPEN_NTTRANS_CREATE;
404 if (io->t2open.in.open_func == 0) {
405 status = NT_STATUS_OBJECT_NAME_COLLISION;
406 goto done;
409 status = map_openx_open(io->t2open.in.flags,
410 io->t2open.in.open_mode,
411 io->t2open.in.open_func,
412 io->t2open.in.fname,
413 io2);
414 if (!NT_STATUS_IS_OK(status)) {
415 goto done;
418 io2->generic.in.file_attr = io->t2open.in.file_attrs;
419 io2->generic.in.fname = io->t2open.in.fname;
420 io2->generic.in.ea_list = talloc(io2, struct smb_ea_list);
421 io2->generic.in.ea_list->num_eas = io->t2open.in.num_eas;
422 io2->generic.in.ea_list->eas = io->t2open.in.eas;
424 status = ntvfs->ops->openfile(ntvfs, req, io2);
425 break;
427 case RAW_OPEN_MKNEW:
428 io2->generic.in.file_attr = io->mknew.in.attrib;
429 io2->generic.in.fname = io->mknew.in.fname;
430 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
431 io2->generic.in.access_mask =
432 SEC_RIGHTS_FILE_READ |
433 SEC_RIGHTS_FILE_WRITE;
434 io2->generic.in.share_access =
435 NTCREATEX_SHARE_ACCESS_READ |
436 NTCREATEX_SHARE_ACCESS_WRITE;
437 status = ntvfs->ops->openfile(ntvfs, req, io2);
438 break;
440 case RAW_OPEN_CREATE:
441 io2->generic.in.file_attr = io->mknew.in.attrib;
442 io2->generic.in.fname = io->mknew.in.fname;
443 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
444 io2->generic.in.access_mask =
445 SEC_RIGHTS_FILE_READ |
446 SEC_RIGHTS_FILE_WRITE;
447 io2->generic.in.share_access =
448 NTCREATEX_SHARE_ACCESS_READ |
449 NTCREATEX_SHARE_ACCESS_WRITE;
450 status = ntvfs->ops->openfile(ntvfs, req, io2);
451 break;
453 case RAW_OPEN_CTEMP:
454 io2->generic.in.file_attr = io->ctemp.in.attrib;
455 io2->generic.in.file_attr = 0;
456 io2->generic.in.fname =
457 talloc_asprintf(io2, "%s\\SRV%s",
458 io->ctemp.in.directory,
459 generate_random_str_list(io2, 5, "0123456789"));
460 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
461 io2->generic.in.access_mask =
462 SEC_RIGHTS_FILE_READ |
463 SEC_RIGHTS_FILE_WRITE;
464 io2->generic.in.share_access =
465 NTCREATEX_SHARE_ACCESS_READ |
466 NTCREATEX_SHARE_ACCESS_WRITE;
467 status = ntvfs->ops->openfile(ntvfs, req, io2);
468 break;
470 default:
471 status = NT_STATUS_INVALID_LEVEL;
472 break;
474 done:
475 return ntvfs_map_async_finish(req, status);
480 NTVFS fsinfo generic to any mapper
482 NTSTATUS ntvfs_map_fsinfo(struct smbsrv_request *req, union smb_fsinfo *fs,
483 struct ntvfs_module_context *ntvfs)
485 NTSTATUS status;
486 union smb_fsinfo *fs2;
488 fs2 = talloc(req, union smb_fsinfo);
489 if (fs2 == NULL) {
490 return NT_STATUS_NO_MEMORY;
493 if (fs->generic.level == RAW_QFS_GENERIC) {
494 return NT_STATUS_INVALID_LEVEL;
497 /* this map function is only used by the simple backend, which
498 doesn't do async */
499 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
501 /* ask the backend for the generic info */
502 fs2->generic.level = RAW_QFS_GENERIC;
504 status = ntvfs->ops->fsinfo(ntvfs, req, fs2);
505 if (!NT_STATUS_IS_OK(status)) {
506 return status;
509 /* and convert it to the required level */
510 switch (fs->generic.level) {
511 case RAW_QFS_GENERIC:
512 return NT_STATUS_INVALID_LEVEL;
514 case RAW_QFS_DSKATTR: {
515 /* map from generic to DSKATTR */
516 uint_t bpunit = 64;
518 /* we need to scale the sizes to fit */
519 for (bpunit=64; bpunit<0x10000; bpunit *= 2) {
520 if (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size < bpunit * 512 * 65535.0) {
521 break;
525 fs->dskattr.out.blocks_per_unit = bpunit;
526 fs->dskattr.out.block_size = 512;
527 fs->dskattr.out.units_total =
528 (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size) / (bpunit * 512);
529 fs->dskattr.out.units_free =
530 (fs2->generic.out.blocks_free * (double)fs2->generic.out.block_size) / (bpunit * 512);
532 /* we must return a maximum of 2G to old DOS systems, or they get very confused */
533 if (bpunit > 64 && req->smb_conn->negotiate.protocol <= PROTOCOL_LANMAN2) {
534 fs->dskattr.out.blocks_per_unit = 64;
535 fs->dskattr.out.units_total = 0xFFFF;
536 fs->dskattr.out.units_free = 0xFFFF;
538 return NT_STATUS_OK;
541 case RAW_QFS_ALLOCATION:
542 fs->allocation.out.fs_id = fs2->generic.out.fs_id;
543 fs->allocation.out.total_alloc_units = fs2->generic.out.blocks_total;
544 fs->allocation.out.avail_alloc_units = fs2->generic.out.blocks_free;
545 fs->allocation.out.sectors_per_unit = 1;
546 fs->allocation.out.bytes_per_sector = fs2->generic.out.block_size;
547 return NT_STATUS_OK;
549 case RAW_QFS_VOLUME:
550 fs->volume.out.serial_number = fs2->generic.out.serial_number;
551 fs->volume.out.volume_name.s = fs2->generic.out.volume_name;
552 return NT_STATUS_OK;
554 case RAW_QFS_VOLUME_INFO:
555 case RAW_QFS_VOLUME_INFORMATION:
556 fs->volume_info.out.create_time = fs2->generic.out.create_time;
557 fs->volume_info.out.serial_number = fs2->generic.out.serial_number;
558 fs->volume_info.out.volume_name.s = fs2->generic.out.volume_name;
559 return NT_STATUS_OK;
561 case RAW_QFS_SIZE_INFO:
562 case RAW_QFS_SIZE_INFORMATION:
563 fs->size_info.out.total_alloc_units = fs2->generic.out.blocks_total;
564 fs->size_info.out.avail_alloc_units = fs2->generic.out.blocks_free;
565 fs->size_info.out.sectors_per_unit = 1;
566 fs->size_info.out.bytes_per_sector = fs2->generic.out.block_size;
567 return NT_STATUS_OK;
569 case RAW_QFS_DEVICE_INFO:
570 case RAW_QFS_DEVICE_INFORMATION:
571 fs->device_info.out.device_type = fs2->generic.out.device_type;
572 fs->device_info.out.characteristics = fs2->generic.out.device_characteristics;
573 return NT_STATUS_OK;
575 case RAW_QFS_ATTRIBUTE_INFO:
576 case RAW_QFS_ATTRIBUTE_INFORMATION:
577 fs->attribute_info.out.fs_attr = fs2->generic.out.fs_attr;
578 fs->attribute_info.out.max_file_component_length = fs2->generic.out.max_file_component_length;
579 fs->attribute_info.out.fs_type.s = fs2->generic.out.fs_type;
580 return NT_STATUS_OK;
582 case RAW_QFS_QUOTA_INFORMATION:
583 ZERO_STRUCT(fs->quota_information.out.unknown);
584 fs->quota_information.out.quota_soft = fs2->generic.out.quota_soft;
585 fs->quota_information.out.quota_hard = fs2->generic.out.quota_hard;
586 fs->quota_information.out.quota_flags = fs2->generic.out.quota_flags;
587 return NT_STATUS_OK;
589 case RAW_QFS_FULL_SIZE_INFORMATION:
590 fs->full_size_information.out.total_alloc_units = fs2->generic.out.blocks_total;
591 fs->full_size_information.out.call_avail_alloc_units = fs2->generic.out.blocks_free;
592 fs->full_size_information.out.actual_avail_alloc_units = fs2->generic.out.blocks_free;
593 fs->full_size_information.out.sectors_per_unit = 1;
594 fs->full_size_information.out.bytes_per_sector = fs2->generic.out.block_size;
595 return NT_STATUS_OK;
597 case RAW_QFS_OBJECTID_INFORMATION:
598 fs->objectid_information.out.guid = fs2->generic.out.guid;
599 ZERO_STRUCT(fs->objectid_information.out.unknown);
600 return NT_STATUS_OK;
604 return NT_STATUS_INVALID_LEVEL;
609 NTVFS fileinfo generic to any mapper
611 NTSTATUS ntvfs_map_fileinfo(struct smbsrv_request *req, union smb_fileinfo *info,
612 union smb_fileinfo *info2)
614 int i;
615 /* and convert it to the required level using results in info2 */
616 switch (info->generic.level) {
617 case RAW_FILEINFO_GENERIC:
618 return NT_STATUS_INVALID_LEVEL;
619 case RAW_FILEINFO_GETATTR:
620 info->getattr.out.attrib = info2->generic.out.attrib & 0xff;
621 info->getattr.out.size = info2->generic.out.size;
622 info->getattr.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
623 return NT_STATUS_OK;
625 case RAW_FILEINFO_GETATTRE:
626 info->getattre.out.attrib = info2->generic.out.attrib;
627 info->getattre.out.size = info2->generic.out.size;
628 info->getattre.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
629 info->getattre.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
630 info->getattre.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
631 info->getattre.out.alloc_size = info2->generic.out.alloc_size;
632 return NT_STATUS_OK;
634 case RAW_FILEINFO_NETWORK_OPEN_INFORMATION:
635 info->network_open_information.out.create_time = info2->generic.out.create_time;
636 info->network_open_information.out.access_time = info2->generic.out.access_time;
637 info->network_open_information.out.write_time = info2->generic.out.write_time;
638 info->network_open_information.out.change_time = info2->generic.out.change_time;
639 info->network_open_information.out.alloc_size = info2->generic.out.alloc_size;
640 info->network_open_information.out.size = info2->generic.out.size;
641 info->network_open_information.out.attrib = info2->generic.out.attrib;
642 return NT_STATUS_OK;
644 case RAW_FILEINFO_ALL_INFO:
645 case RAW_FILEINFO_ALL_INFORMATION:
646 info->all_info.out.create_time = info2->generic.out.create_time;
647 info->all_info.out.access_time = info2->generic.out.access_time;
648 info->all_info.out.write_time = info2->generic.out.write_time;
649 info->all_info.out.change_time = info2->generic.out.change_time;
650 info->all_info.out.attrib = info2->generic.out.attrib;
651 info->all_info.out.alloc_size = info2->generic.out.alloc_size;
652 info->all_info.out.size = info2->generic.out.size;
653 info->all_info.out.nlink = info2->generic.out.nlink;
654 info->all_info.out.delete_pending = info2->generic.out.delete_pending;
655 info->all_info.out.directory = info2->generic.out.directory;
656 info->all_info.out.ea_size = info2->generic.out.ea_size;
657 info->all_info.out.fname.s = info2->generic.out.fname.s;
658 info->all_info.out.fname.private_length = info2->generic.out.fname.private_length;
659 return NT_STATUS_OK;
661 case RAW_FILEINFO_BASIC_INFO:
662 case RAW_FILEINFO_BASIC_INFORMATION:
663 info->basic_info.out.create_time = info2->generic.out.create_time;
664 info->basic_info.out.access_time = info2->generic.out.access_time;
665 info->basic_info.out.write_time = info2->generic.out.write_time;
666 info->basic_info.out.change_time = info2->generic.out.change_time;
667 info->basic_info.out.attrib = info2->generic.out.attrib;
668 return NT_STATUS_OK;
670 case RAW_FILEINFO_STANDARD:
671 info->standard.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
672 info->standard.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
673 info->standard.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
674 info->standard.out.size = info2->generic.out.size;
675 info->standard.out.alloc_size = info2->generic.out.alloc_size;
676 info->standard.out.attrib = info2->generic.out.attrib;
677 return NT_STATUS_OK;
679 case RAW_FILEINFO_EA_SIZE:
680 info->ea_size.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
681 info->ea_size.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
682 info->ea_size.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
683 info->ea_size.out.size = info2->generic.out.size;
684 info->ea_size.out.alloc_size = info2->generic.out.alloc_size;
685 info->ea_size.out.attrib = info2->generic.out.attrib;
686 info->ea_size.out.ea_size = info2->generic.out.ea_size;
687 return NT_STATUS_OK;
689 case RAW_FILEINFO_STANDARD_INFO:
690 case RAW_FILEINFO_STANDARD_INFORMATION:
691 info->standard_info.out.alloc_size = info2->generic.out.alloc_size;
692 info->standard_info.out.size = info2->generic.out.size;
693 info->standard_info.out.nlink = info2->generic.out.nlink;
694 info->standard_info.out.delete_pending = info2->generic.out.delete_pending;
695 info->standard_info.out.directory = info2->generic.out.directory;
696 return NT_STATUS_OK;
698 case RAW_FILEINFO_INTERNAL_INFORMATION:
699 info->internal_information.out.file_id = info2->generic.out.file_id;
700 return NT_STATUS_OK;
702 case RAW_FILEINFO_EA_INFO:
703 case RAW_FILEINFO_EA_INFORMATION:
704 info->ea_info.out.ea_size = info2->generic.out.ea_size;
705 return NT_STATUS_OK;
707 case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION:
708 info->attribute_tag_information.out.attrib = info2->generic.out.attrib;
709 info->attribute_tag_information.out.reparse_tag = info2->generic.out.reparse_tag;
710 return NT_STATUS_OK;
712 case RAW_FILEINFO_STREAM_INFO:
713 case RAW_FILEINFO_STREAM_INFORMATION:
714 info->stream_info.out.num_streams = info2->generic.out.num_streams;
715 if (info->stream_info.out.num_streams > 0) {
716 info->stream_info.out.streams =
717 talloc_array(req,
718 struct stream_struct,
719 info->stream_info.out.num_streams);
720 if (!info->stream_info.out.streams) {
721 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d streams\n",
722 info->stream_info.out.num_streams));
723 return NT_STATUS_NO_MEMORY;
725 for (i=0; i < info->stream_info.out.num_streams; i++) {
726 info->stream_info.out.streams[i] = info2->generic.out.streams[i];
727 info->stream_info.out.streams[i].stream_name.s =
728 talloc_strdup(req, info2->generic.out.streams[i].stream_name.s);
729 if (!info->stream_info.out.streams[i].stream_name.s) {
730 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
731 return NT_STATUS_NO_MEMORY;
735 return NT_STATUS_OK;
737 case RAW_FILEINFO_NAME_INFO:
738 case RAW_FILEINFO_NAME_INFORMATION:
739 info->name_info.out.fname.s = talloc_strdup(req, info2->generic.out.fname.s);
740 info->name_info.out.fname.private_length = info2->generic.out.fname.private_length;
741 return NT_STATUS_OK;
743 case RAW_FILEINFO_ALT_NAME_INFO:
744 case RAW_FILEINFO_ALT_NAME_INFORMATION:
745 info->alt_name_info.out.fname.s = talloc_strdup(req, info2->generic.out.alt_fname.s);
746 info->alt_name_info.out.fname.private_length = info2->generic.out.alt_fname.private_length;
747 return NT_STATUS_OK;
749 case RAW_FILEINFO_POSITION_INFORMATION:
750 info->position_information.out.position = info2->generic.out.position;
751 return NT_STATUS_OK;
753 case RAW_FILEINFO_ALL_EAS:
754 info->all_eas.out.num_eas = info2->generic.out.num_eas;
755 if (info->all_eas.out.num_eas > 0) {
756 info->all_eas.out.eas = talloc_array(req,
757 struct ea_struct,
758 info->all_eas.out.num_eas);
759 if (!info->all_eas.out.eas) {
760 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d eas\n",
761 info->all_eas.out.num_eas));
762 return NT_STATUS_NO_MEMORY;
764 for (i = 0; i < info->all_eas.out.num_eas; i++) {
765 info->all_eas.out.eas[i] = info2->generic.out.eas[i];
766 info->all_eas.out.eas[i].name.s =
767 talloc_strdup(req, info2->generic.out.eas[i].name.s);
768 if (!info->all_eas.out.eas[i].name.s) {
769 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
770 return NT_STATUS_NO_MEMORY;
772 info->all_eas.out.eas[i].value.data =
773 talloc_memdup(req,
774 info2->generic.out.eas[i].value.data,
775 info2->generic.out.eas[i].value.length);
776 if (!info->all_eas.out.eas[i].value.data) {
777 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
778 return NT_STATUS_NO_MEMORY;
782 return NT_STATUS_OK;
784 case RAW_FILEINFO_IS_NAME_VALID:
785 return NT_STATUS_OK;
787 case RAW_FILEINFO_COMPRESSION_INFO:
788 case RAW_FILEINFO_COMPRESSION_INFORMATION:
789 info->compression_info.out.compressed_size = info2->generic.out.compressed_size;
790 info->compression_info.out.format = info2->generic.out.format;
791 info->compression_info.out.unit_shift = info2->generic.out.unit_shift;
792 info->compression_info.out.chunk_shift = info2->generic.out.chunk_shift;
793 info->compression_info.out.cluster_shift = info2->generic.out.cluster_shift;
794 return NT_STATUS_OK;
796 case RAW_FILEINFO_ACCESS_INFORMATION:
797 info->access_information.out.access_flags = info2->generic.out.access_flags;
798 return NT_STATUS_OK;
800 case RAW_FILEINFO_MODE_INFORMATION:
801 info->mode_information.out.mode = info2->generic.out.mode;
802 return NT_STATUS_OK;
804 case RAW_FILEINFO_ALIGNMENT_INFORMATION:
805 info->alignment_information.out.alignment_requirement =
806 info2->generic.out.alignment_requirement;
807 return NT_STATUS_OK;
808 #if 0
809 case RAW_FILEINFO_UNIX_BASIC:
810 info->unix_basic_info.out.end_of_file = info2->generic.out.end_of_file;
811 info->unix_basic_info.out.num_bytes = info2->generic.out.size;
812 info->unix_basic_info.out.status_change_time = info2->generic.out.change_time;
813 info->unix_basic_info.out.access_time = info2->generic.out.access_time;
814 info->unix_basic_info.out.change_time = info2->generic.out.change_time;
815 info->unix_basic_info.out.uid = info2->generic.out.uid;
816 info->unix_basic_info.out.gid = info2->generic.out.gid;
817 info->unix_basic_info.out.file_type = info2->generic.out.file_type;
818 info->unix_basic_info.out.dev_major = info2->generic.out.device;
819 info->unix_basic_info.out.dev_minor = info2->generic.out.device;
820 info->unix_basic_info.out.unique_id = info2->generic.out.inode;
821 info->unix_basic_info.out.permissions = info2->generic.out.permissions;
822 info->unix_basic_info.out.nlink = info2->generic.out.nlink;
823 return NT_STATUS_OK;
825 case RAW_FILEINFO_UNIX_LINK:
826 info->unix_link_info.out.link_dest = info2->generic.out.link_dest;
827 return NT_STATUS_OK;
828 #endif
831 return NT_STATUS_INVALID_LEVEL;
835 NTVFS fileinfo generic to any mapper
837 NTSTATUS ntvfs_map_qfileinfo(struct smbsrv_request *req, union smb_fileinfo *info,
838 struct ntvfs_module_context *ntvfs)
840 NTSTATUS status;
841 union smb_fileinfo *info2;
843 info2 = talloc(req, union smb_fileinfo);
844 if (info2 == NULL) {
845 return NT_STATUS_NO_MEMORY;
848 if (info->generic.level == RAW_FILEINFO_GENERIC) {
849 return NT_STATUS_INVALID_LEVEL;
852 /* ask the backend for the generic info */
853 info2->generic.level = RAW_FILEINFO_GENERIC;
854 info2->generic.in.fnum = info->generic.in.fnum;
856 status = ntvfs->ops->qfileinfo(ntvfs, req, info2);
857 if (!NT_STATUS_IS_OK(status)) {
858 return status;
860 return ntvfs_map_fileinfo(req, info, info2);
864 NTVFS pathinfo generic to any mapper
866 NTSTATUS ntvfs_map_qpathinfo(struct smbsrv_request *req, union smb_fileinfo *info,
867 struct ntvfs_module_context *ntvfs)
869 NTSTATUS status;
870 union smb_fileinfo *info2;
872 info2 = talloc(req, union smb_fileinfo);
873 if (info2 == NULL) {
874 return NT_STATUS_NO_MEMORY;
877 if (info->generic.level == RAW_FILEINFO_GENERIC) {
878 return NT_STATUS_INVALID_LEVEL;
881 /* ask the backend for the generic info */
882 info2->generic.level = RAW_FILEINFO_GENERIC;
883 info2->generic.in.fname = info->generic.in.fname;
885 /* only used by the simple backend, which doesn't do async */
886 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
888 status = ntvfs->ops->qpathinfo(ntvfs, req, info2);
889 if (!NT_STATUS_IS_OK(status)) {
890 return status;
892 return ntvfs_map_fileinfo(req, info, info2);
897 NTVFS lock generic to any mapper
899 NTSTATUS ntvfs_map_lock(struct smbsrv_request *req, union smb_lock *lck,
900 struct ntvfs_module_context *ntvfs)
902 union smb_lock *lck2;
903 struct smb_lock_entry *locks;
905 lck2 = talloc(req, union smb_lock);
906 if (lck2 == NULL) {
907 return NT_STATUS_NO_MEMORY;
910 locks = talloc_array(lck2, struct smb_lock_entry, 1);
911 if (locks == NULL) {
912 return NT_STATUS_NO_MEMORY;
915 switch (lck->generic.level) {
916 case RAW_LOCK_LOCKX:
917 return NT_STATUS_INVALID_LEVEL;
919 case RAW_LOCK_LOCK:
920 lck2->generic.in.ulock_cnt = 0;
921 lck2->generic.in.lock_cnt = 1;
922 break;
924 case RAW_LOCK_UNLOCK:
925 lck2->generic.in.ulock_cnt = 1;
926 lck2->generic.in.lock_cnt = 0;
927 break;
930 lck2->generic.level = RAW_LOCK_GENERIC;
931 lck2->generic.in.fnum = lck->lock.in.fnum;
932 lck2->generic.in.mode = 0;
933 lck2->generic.in.timeout = 0;
934 lck2->generic.in.locks = locks;
935 locks->pid = req->smbpid;
936 locks->offset = lck->lock.in.offset;
937 locks->count = lck->lock.in.count;
939 return ntvfs->ops->lock(ntvfs, req, lck2);
944 NTVFS write generic to any mapper
946 static NTSTATUS ntvfs_map_write_finish(struct smbsrv_request *req,
947 struct ntvfs_module_context *ntvfs,
948 union smb_write *wr,
949 union smb_write *wr2,
950 NTSTATUS status)
953 union smb_lock *lck;
954 union smb_close *cl;
955 uint_t state;
957 if (NT_STATUS_IS_ERR(status)) {
958 return status;
961 switch (wr->generic.level) {
962 case RAW_WRITE_WRITE:
963 wr->write.out.nwritten = wr2->generic.out.nwritten;
964 break;
966 case RAW_WRITE_WRITEUNLOCK:
967 wr->writeunlock.out.nwritten = wr2->generic.out.nwritten;
969 lck = talloc(wr2, union smb_lock);
970 if (lck == NULL) {
971 return NT_STATUS_NO_MEMORY;
974 lck->unlock.level = RAW_LOCK_UNLOCK;
975 lck->unlock.in.fnum = wr->writeunlock.in.fnum;
976 lck->unlock.in.count = wr->writeunlock.in.count;
977 lck->unlock.in.offset = wr->writeunlock.in.offset;
979 if (lck->unlock.in.count != 0) {
980 /* do the lock sync for now */
981 state = req->async_states->state;
982 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
983 status = ntvfs->ops->lock(ntvfs, req, lck);
984 req->async_states->state = state;
986 break;
988 case RAW_WRITE_WRITECLOSE:
989 wr->writeclose.out.nwritten = wr2->generic.out.nwritten;
991 cl = talloc(wr2, union smb_close);
992 if (cl == NULL) {
993 return NT_STATUS_NO_MEMORY;
996 cl->close.level = RAW_CLOSE_CLOSE;
997 cl->close.in.fnum = wr->writeclose.in.fnum;
998 cl->close.in.write_time = wr->writeclose.in.mtime;
1000 if (wr2->generic.in.count != 0) {
1001 /* do the close sync for now */
1002 state = req->async_states->state;
1003 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1004 status = ntvfs->ops->close(ntvfs, req, cl);
1005 req->async_states->state = state;
1007 break;
1009 case RAW_WRITE_SPLWRITE:
1010 break;
1011 default:
1012 return NT_STATUS_INVALID_LEVEL;
1015 return status;
1020 NTVFS write generic to any mapper
1022 NTSTATUS ntvfs_map_write(struct smbsrv_request *req, union smb_write *wr,
1023 struct ntvfs_module_context *ntvfs)
1025 union smb_write *wr2;
1026 NTSTATUS status;
1028 wr2 = talloc(req, union smb_write);
1029 if (wr2 == NULL) {
1030 return NT_STATUS_NO_MEMORY;
1033 status = ntvfs_map_async_setup(req, ntvfs, wr, wr2,
1034 (second_stage_t)ntvfs_map_write_finish);
1035 if (!NT_STATUS_IS_OK(status)) {
1036 return status;
1039 wr2->writex.level = RAW_WRITE_GENERIC;
1041 switch (wr->generic.level) {
1042 case RAW_WRITE_WRITEX:
1043 status = NT_STATUS_INVALID_LEVEL;
1044 break;
1046 case RAW_WRITE_WRITE:
1047 wr2->writex.in.fnum = wr->write.in.fnum;
1048 wr2->writex.in.offset = wr->write.in.offset;
1049 wr2->writex.in.wmode = 0;
1050 wr2->writex.in.remaining = wr->write.in.remaining;
1051 wr2->writex.in.count = wr->write.in.count;
1052 wr2->writex.in.data = wr->write.in.data;
1053 status = ntvfs->ops->write(ntvfs, req, wr2);
1054 break;
1056 case RAW_WRITE_WRITEUNLOCK:
1057 wr2->writex.in.fnum = wr->writeunlock.in.fnum;
1058 wr2->writex.in.offset = wr->writeunlock.in.offset;
1059 wr2->writex.in.wmode = 0;
1060 wr2->writex.in.remaining = wr->writeunlock.in.remaining;
1061 wr2->writex.in.count = wr->writeunlock.in.count;
1062 wr2->writex.in.data = wr->writeunlock.in.data;
1063 status = ntvfs->ops->write(ntvfs, req, wr2);
1064 break;
1066 case RAW_WRITE_WRITECLOSE:
1067 wr2->writex.in.fnum = wr->writeclose.in.fnum;
1068 wr2->writex.in.offset = wr->writeclose.in.offset;
1069 wr2->writex.in.wmode = 0;
1070 wr2->writex.in.remaining = 0;
1071 wr2->writex.in.count = wr->writeclose.in.count;
1072 wr2->writex.in.data = wr->writeclose.in.data;
1073 status = ntvfs->ops->write(ntvfs, req, wr2);
1074 break;
1076 case RAW_WRITE_SPLWRITE:
1077 wr2->writex.in.fnum = wr->splwrite.in.fnum;
1078 wr2->writex.in.offset = 0;
1079 wr2->writex.in.wmode = 0;
1080 wr2->writex.in.remaining = 0;
1081 wr2->writex.in.count = wr->splwrite.in.count;
1082 wr2->writex.in.data = wr->splwrite.in.data;
1083 status = ntvfs->ops->write(ntvfs, req, wr2);
1084 break;
1087 return ntvfs_map_async_finish(req, status);
1092 NTVFS read generic to any mapper - finish the out mapping
1094 static NTSTATUS ntvfs_map_read_finish(struct smbsrv_request *req,
1095 struct ntvfs_module_context *ntvfs,
1096 union smb_read *rd,
1097 union smb_read *rd2,
1098 NTSTATUS status)
1100 switch (rd->generic.level) {
1101 case RAW_READ_READ:
1102 rd->read.out.nread = rd2->generic.out.nread;
1103 break;
1104 case RAW_READ_READBRAW:
1105 rd->readbraw.out.nread = rd2->generic.out.nread;
1106 break;
1107 case RAW_READ_LOCKREAD:
1108 rd->lockread.out.nread = rd2->generic.out.nread;
1109 break;
1110 default:
1111 return NT_STATUS_INVALID_LEVEL;
1114 return status;
1118 NTVFS read* to readx mapper
1120 NTSTATUS ntvfs_map_read(struct smbsrv_request *req, union smb_read *rd,
1121 struct ntvfs_module_context *ntvfs)
1123 union smb_read *rd2;
1124 union smb_lock *lck;
1125 NTSTATUS status;
1126 uint_t state;
1128 rd2 = talloc(req, union smb_read);
1129 if (rd2 == NULL) {
1130 return NT_STATUS_NO_MEMORY;
1133 status = ntvfs_map_async_setup(req, ntvfs, rd, rd2,
1134 (second_stage_t)ntvfs_map_read_finish);
1135 if (!NT_STATUS_IS_OK(status)) {
1136 return status;
1139 rd2->readx.level = RAW_READ_READX;
1141 switch (rd->generic.level) {
1142 case RAW_READ_READX:
1143 status = NT_STATUS_INVALID_LEVEL;
1144 break;
1146 case RAW_READ_READ:
1147 rd2->readx.in.fnum = rd->read.in.fnum;
1148 rd2->readx.in.offset = rd->read.in.offset;
1149 rd2->readx.in.mincnt = rd->read.in.count;
1150 rd2->readx.in.maxcnt = rd->read.in.count;
1151 rd2->readx.in.remaining = rd->read.in.remaining;
1152 rd2->readx.out.data = rd->read.out.data;
1153 status = ntvfs->ops->read(ntvfs, req, rd2);
1154 break;
1156 case RAW_READ_READBRAW:
1157 rd2->readx.in.fnum = rd->readbraw.in.fnum;
1158 rd2->readx.in.offset = rd->readbraw.in.offset;
1159 rd2->readx.in.mincnt = rd->readbraw.in.mincnt;
1160 rd2->readx.in.maxcnt = rd->readbraw.in.maxcnt;
1161 rd2->readx.in.remaining = 0;
1162 rd2->readx.out.data = rd->readbraw.out.data;
1163 status = ntvfs->ops->read(ntvfs, req, rd2);
1164 break;
1166 case RAW_READ_LOCKREAD:
1167 /* do the initial lock sync for now */
1168 state = req->async_states->state;
1169 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1171 lck = talloc(rd2, union smb_lock);
1172 if (lck == NULL) {
1173 status = NT_STATUS_NO_MEMORY;
1174 goto done;
1176 lck->lock.level = RAW_LOCK_LOCK;
1177 lck->lock.in.fnum = rd->lockread.in.fnum;
1178 lck->lock.in.count = rd->lockread.in.count;
1179 lck->lock.in.offset = rd->lockread.in.offset;
1180 status = ntvfs->ops->lock(ntvfs, req, lck);
1181 req->async_states->state = state;
1183 rd2->readx.in.fnum = rd->lockread.in.fnum;
1184 rd2->readx.in.offset = rd->lockread.in.offset;
1185 rd2->readx.in.mincnt = rd->lockread.in.count;
1186 rd2->readx.in.maxcnt = rd->lockread.in.count;
1187 rd2->readx.in.remaining = rd->lockread.in.remaining;
1188 rd2->readx.out.data = rd->lockread.out.data;
1190 if (NT_STATUS_IS_OK(status)) {
1191 status = ntvfs->ops->read(ntvfs, req, rd2);
1193 break;
1196 done:
1197 return ntvfs_map_async_finish(req, status);
1202 NTVFS close generic to any mapper
1204 NTSTATUS ntvfs_map_close(struct smbsrv_request *req, union smb_close *cl,
1205 struct ntvfs_module_context *ntvfs)
1207 union smb_close *cl2;
1209 cl2 = talloc(req, union smb_close);
1210 if (cl2 == NULL) {
1211 return NT_STATUS_NO_MEMORY;
1214 switch (cl->generic.level) {
1215 case RAW_CLOSE_CLOSE:
1216 return NT_STATUS_INVALID_LEVEL;
1218 case RAW_CLOSE_SPLCLOSE:
1219 cl2->close.level = RAW_CLOSE_CLOSE;
1220 cl2->close.in.fnum = cl->splclose.in.fnum;
1221 break;
1224 return ntvfs->ops->close(ntvfs, req, cl2);