• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/samba-3.5.8/source4/ntvfs/posix/
1/*
2   Unix SMB/CIFS implementation.
3
4   POSIX NTVFS backend - read
5
6   Copyright (C) Andrew Tridgell 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 3 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, see <http://www.gnu.org/licenses/>.
20*/
21
22#include "includes.h"
23#include "vfs_posix.h"
24#include "lib/events/events.h"
25
26/*
27  read from a file
28*/
29NTSTATUS pvfs_read(struct ntvfs_module_context *ntvfs,
30		   struct ntvfs_request *req, union smb_read *rd)
31{
32	struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
33				  struct pvfs_state);
34	ssize_t ret;
35	struct pvfs_file *f;
36	NTSTATUS status;
37	uint32_t maxcnt;
38	uint32_t mask;
39
40	if (rd->generic.level != RAW_READ_READX) {
41		return ntvfs_map_read(ntvfs, req, rd);
42	}
43
44	f = pvfs_find_fd(pvfs, req, rd->readx.in.file.ntvfs);
45	if (!f) {
46		return NT_STATUS_INVALID_HANDLE;
47	}
48
49	if (f->handle->fd == -1) {
50		return NT_STATUS_INVALID_DEVICE_REQUEST;
51	}
52
53	mask = SEC_FILE_READ_DATA;
54	if (rd->readx.in.read_for_execute) {
55		mask |= SEC_FILE_EXECUTE;
56	}
57	if (!(f->access_mask & mask)) {
58		return NT_STATUS_ACCESS_DENIED;
59	}
60
61	maxcnt = rd->readx.in.maxcnt;
62	if (maxcnt > 2*UINT16_MAX && req->ctx->protocol < PROTOCOL_SMB2) {
63		return NT_STATUS_INVALID_PARAMETER;
64	}
65
66	status = pvfs_check_lock(pvfs, f, req->smbpid,
67				 rd->readx.in.offset,
68				 maxcnt,
69				 READ_LOCK);
70	if (!NT_STATUS_IS_OK(status)) {
71		return status;
72	}
73
74	if (f->handle->name->stream_name) {
75		ret = pvfs_stream_read(pvfs, f->handle,
76				       rd->readx.out.data, maxcnt, rd->readx.in.offset);
77	} else {
78#if HAVE_LINUX_AIO
79		/* possibly try an aio read */
80		if ((req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC) &&
81		    (pvfs->flags & PVFS_FLAG_LINUX_AIO)) {
82			status = pvfs_aio_pread(req, rd, f, maxcnt);
83			if (NT_STATUS_IS_OK(status)) {
84				return NT_STATUS_OK;
85			}
86		}
87#endif
88		ret = pread(f->handle->fd,
89			    rd->readx.out.data,
90			    maxcnt,
91			    rd->readx.in.offset);
92	}
93	if (ret == -1) {
94		return pvfs_map_errno(pvfs, errno);
95	}
96
97	/* only SMB2 honors mincnt */
98	if (req->ctx->protocol == PROTOCOL_SMB2) {
99		if (rd->readx.in.mincnt > ret ||
100		    (ret == 0 && maxcnt > 0)) {
101			return NT_STATUS_END_OF_FILE;
102		}
103	}
104
105	f->handle->position = f->handle->seek_offset = rd->readx.in.offset + ret;
106
107	rd->readx.out.nread = ret;
108	rd->readx.out.remaining = 0xFFFF;
109	rd->readx.out.compaction_mode = 0;
110
111	return NT_STATUS_OK;
112}
113