2 Unix SMB/CIFS implementation.
4 POSIX NTVFS backend - read
6 Copyright (C) Andrew Tridgell 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 3 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, see <http://www.gnu.org/licenses/>.
23 #include "vfs_posix.h"
24 #include "librpc/gen_ndr/xattr.h"
28 determine what access bits are needed for a call
30 static uint32_t pvfs_fileinfo_access(union smb_fileinfo
*info
)
34 switch (info
->generic
.level
) {
35 case RAW_FILEINFO_EA_LIST
:
36 case RAW_FILEINFO_ALL_EAS
:
37 needed
= SEC_FILE_READ_EA
;
40 case RAW_FILEINFO_IS_NAME_VALID
:
44 case RAW_FILEINFO_ACCESS_INFORMATION
:
48 case RAW_FILEINFO_STREAM_INFO
:
49 case RAW_FILEINFO_STREAM_INFORMATION
:
53 case RAW_FILEINFO_SEC_DESC
:
55 if (info
->query_secdesc
.in
.secinfo_flags
& (SECINFO_OWNER
|SECINFO_GROUP
)) {
56 needed
|= SEC_STD_READ_CONTROL
;
58 if (info
->query_secdesc
.in
.secinfo_flags
& SECINFO_DACL
) {
59 needed
|= SEC_STD_READ_CONTROL
;
61 if (info
->query_secdesc
.in
.secinfo_flags
& SECINFO_SACL
) {
62 needed
|= SEC_FLAG_SYSTEM_SECURITY
;
67 needed
= SEC_FILE_READ_ATTRIBUTE
;
75 reply to a RAW_FILEINFO_EA_LIST call
77 NTSTATUS
pvfs_query_ea_list(struct pvfs_state
*pvfs
, TALLOC_CTX
*mem_ctx
,
78 struct pvfs_filename
*name
, int fd
,
79 unsigned int num_names
,
80 struct ea_name
*names
,
81 struct smb_ea_list
*eas
)
85 struct xattr_DosEAs
*ealist
= talloc(mem_ctx
, struct xattr_DosEAs
);
88 status
= pvfs_doseas_load(pvfs
, name
, fd
, ealist
);
89 if (!NT_STATUS_IS_OK(status
)) {
92 eas
->eas
= talloc_array(mem_ctx
, struct ea_struct
, num_names
);
93 if (eas
->eas
== NULL
) {
94 return NT_STATUS_NO_MEMORY
;
96 eas
->num_eas
= num_names
;
97 for (i
=0;i
<num_names
;i
++) {
99 eas
->eas
[i
].flags
= 0;
100 eas
->eas
[i
].name
.s
= names
[i
].name
.s
;
101 eas
->eas
[i
].value
= data_blob(NULL
, 0);
102 for (j
=0;j
<ealist
->num_eas
;j
++) {
103 if (strcasecmp_m(eas
->eas
[i
].name
.s
,
104 ealist
->eas
[j
].name
) == 0) {
105 if (ealist
->eas
[j
].value
.length
== 0) {
108 eas
->eas
[i
].value
= ealist
->eas
[j
].value
;
117 reply to a RAW_FILEINFO_ALL_EAS call
119 static NTSTATUS
pvfs_query_all_eas(struct pvfs_state
*pvfs
, TALLOC_CTX
*mem_ctx
,
120 struct pvfs_filename
*name
, int fd
,
121 struct smb_ea_list
*eas
)
125 struct xattr_DosEAs
*ealist
= talloc(mem_ctx
, struct xattr_DosEAs
);
128 status
= pvfs_doseas_load(pvfs
, name
, fd
, ealist
);
129 if (!NT_STATUS_IS_OK(status
)) {
132 eas
->eas
= talloc_array(mem_ctx
, struct ea_struct
, ealist
->num_eas
);
133 if (eas
->eas
== NULL
) {
134 return NT_STATUS_NO_MEMORY
;
137 for (i
=0;i
<ealist
->num_eas
;i
++) {
138 eas
->eas
[eas
->num_eas
].flags
= 0;
139 eas
->eas
[eas
->num_eas
].name
.s
= ealist
->eas
[i
].name
;
140 if (ealist
->eas
[i
].value
.length
== 0) {
143 eas
->eas
[eas
->num_eas
].value
= ealist
->eas
[i
].value
;
150 approximately map a struct pvfs_filename to a generic fileinfo struct
152 static NTSTATUS
pvfs_map_fileinfo(struct pvfs_state
*pvfs
,
153 struct ntvfs_request
*req
,
154 struct pvfs_filename
*name
, union smb_fileinfo
*info
,
157 switch (info
->generic
.level
) {
158 case RAW_FILEINFO_GETATTR
:
159 info
->getattr
.out
.attrib
= name
->dos
.attrib
;
160 info
->getattr
.out
.size
= name
->st
.st_size
;
161 info
->getattr
.out
.write_time
= nt_time_to_unix(name
->dos
.write_time
);
164 case RAW_FILEINFO_GETATTRE
:
165 case RAW_FILEINFO_STANDARD
:
166 info
->standard
.out
.create_time
= nt_time_to_unix(name
->dos
.create_time
);
167 info
->standard
.out
.access_time
= nt_time_to_unix(name
->dos
.access_time
);
168 info
->standard
.out
.write_time
= nt_time_to_unix(name
->dos
.write_time
);
169 info
->standard
.out
.size
= name
->st
.st_size
;
170 info
->standard
.out
.alloc_size
= name
->dos
.alloc_size
;
171 info
->standard
.out
.attrib
= name
->dos
.attrib
;
174 case RAW_FILEINFO_EA_SIZE
:
175 info
->ea_size
.out
.create_time
= nt_time_to_unix(name
->dos
.create_time
);
176 info
->ea_size
.out
.access_time
= nt_time_to_unix(name
->dos
.access_time
);
177 info
->ea_size
.out
.write_time
= nt_time_to_unix(name
->dos
.write_time
);
178 info
->ea_size
.out
.size
= name
->st
.st_size
;
179 info
->ea_size
.out
.alloc_size
= name
->dos
.alloc_size
;
180 info
->ea_size
.out
.attrib
= name
->dos
.attrib
;
181 info
->ea_size
.out
.ea_size
= name
->dos
.ea_size
;
184 case RAW_FILEINFO_EA_LIST
:
185 return pvfs_query_ea_list(pvfs
, req
, name
, fd
,
186 info
->ea_list
.in
.num_names
,
187 info
->ea_list
.in
.ea_names
,
190 case RAW_FILEINFO_ALL_EAS
:
191 return pvfs_query_all_eas(pvfs
, req
, name
, fd
, &info
->all_eas
.out
);
193 case RAW_FILEINFO_SMB2_ALL_EAS
: {
194 NTSTATUS status
= pvfs_query_all_eas(pvfs
, req
, name
, fd
, &info
->all_eas
.out
);
195 if (NT_STATUS_IS_OK(status
) &&
196 info
->all_eas
.out
.num_eas
== 0) {
197 return NT_STATUS_NO_EAS_ON_FILE
;
202 case RAW_FILEINFO_IS_NAME_VALID
:
205 case RAW_FILEINFO_BASIC_INFO
:
206 case RAW_FILEINFO_BASIC_INFORMATION
:
207 info
->basic_info
.out
.create_time
= name
->dos
.create_time
;
208 info
->basic_info
.out
.access_time
= name
->dos
.access_time
;
209 info
->basic_info
.out
.write_time
= name
->dos
.write_time
;
210 info
->basic_info
.out
.change_time
= name
->dos
.change_time
;
211 info
->basic_info
.out
.attrib
= name
->dos
.attrib
;
214 case RAW_FILEINFO_STANDARD_INFO
:
215 case RAW_FILEINFO_STANDARD_INFORMATION
:
216 info
->standard_info
.out
.alloc_size
= name
->dos
.alloc_size
;
217 info
->standard_info
.out
.size
= name
->st
.st_size
;
218 info
->standard_info
.out
.nlink
= name
->dos
.nlink
;
219 info
->standard_info
.out
.delete_pending
= 0; /* only for qfileinfo */
220 info
->standard_info
.out
.directory
=
221 (name
->dos
.attrib
& FILE_ATTRIBUTE_DIRECTORY
)? 1 : 0;
224 case RAW_FILEINFO_EA_INFO
:
225 case RAW_FILEINFO_EA_INFORMATION
:
226 info
->ea_info
.out
.ea_size
= name
->dos
.ea_size
;
229 case RAW_FILEINFO_NAME_INFO
:
230 case RAW_FILEINFO_NAME_INFORMATION
:
231 if (req
->ctx
->protocol
>= PROTOCOL_SMB2_02
) {
232 /* strange that SMB2 doesn't have this */
233 return NT_STATUS_NOT_SUPPORTED
;
235 info
->name_info
.out
.fname
.s
= name
->original_name
;
238 case RAW_FILEINFO_ALL_INFO
:
239 case RAW_FILEINFO_ALL_INFORMATION
:
240 info
->all_info
.out
.create_time
= name
->dos
.create_time
;
241 info
->all_info
.out
.access_time
= name
->dos
.access_time
;
242 info
->all_info
.out
.write_time
= name
->dos
.write_time
;
243 info
->all_info
.out
.change_time
= name
->dos
.change_time
;
244 info
->all_info
.out
.attrib
= name
->dos
.attrib
;
245 info
->all_info
.out
.alloc_size
= name
->dos
.alloc_size
;
246 info
->all_info
.out
.size
= name
->st
.st_size
;
247 info
->all_info
.out
.nlink
= name
->dos
.nlink
;
248 info
->all_info
.out
.delete_pending
= 0; /* only set by qfileinfo */
249 info
->all_info
.out
.directory
=
250 (name
->dos
.attrib
& FILE_ATTRIBUTE_DIRECTORY
)? 1 : 0;
251 info
->all_info
.out
.ea_size
= name
->dos
.ea_size
;
252 info
->all_info
.out
.fname
.s
= name
->original_name
;
255 case RAW_FILEINFO_ALT_NAME_INFO
:
256 case RAW_FILEINFO_ALT_NAME_INFORMATION
:
257 info
->name_info
.out
.fname
.s
= pvfs_short_name(pvfs
, name
, name
);
260 case RAW_FILEINFO_STREAM_INFO
:
261 case RAW_FILEINFO_STREAM_INFORMATION
:
262 return pvfs_stream_information(pvfs
, req
, name
, fd
, &info
->stream_info
.out
);
264 case RAW_FILEINFO_COMPRESSION_INFO
:
265 case RAW_FILEINFO_COMPRESSION_INFORMATION
:
266 info
->compression_info
.out
.compressed_size
= name
->st
.st_size
;
267 info
->compression_info
.out
.format
= 0;
268 info
->compression_info
.out
.unit_shift
= 0;
269 info
->compression_info
.out
.chunk_shift
= 0;
270 info
->compression_info
.out
.cluster_shift
= 0;
273 case RAW_FILEINFO_INTERNAL_INFORMATION
:
274 info
->internal_information
.out
.file_id
= name
->dos
.file_id
;
277 case RAW_FILEINFO_ACCESS_INFORMATION
:
278 info
->access_information
.out
.access_flags
= 0; /* only set by qfileinfo */
281 case RAW_FILEINFO_POSITION_INFORMATION
:
282 info
->position_information
.out
.position
= 0; /* only set by qfileinfo */
285 case RAW_FILEINFO_MODE_INFORMATION
:
286 info
->mode_information
.out
.mode
= 0; /* only set by qfileinfo */
289 case RAW_FILEINFO_ALIGNMENT_INFORMATION
:
290 info
->alignment_information
.out
.alignment_requirement
= 0;
293 case RAW_FILEINFO_NETWORK_OPEN_INFORMATION
:
294 info
->network_open_information
.out
.create_time
= name
->dos
.create_time
;
295 info
->network_open_information
.out
.access_time
= name
->dos
.access_time
;
296 info
->network_open_information
.out
.write_time
= name
->dos
.write_time
;
297 info
->network_open_information
.out
.change_time
= name
->dos
.change_time
;
298 info
->network_open_information
.out
.alloc_size
= name
->dos
.alloc_size
;
299 info
->network_open_information
.out
.size
= name
->st
.st_size
;
300 info
->network_open_information
.out
.attrib
= name
->dos
.attrib
;
303 case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION
:
304 info
->attribute_tag_information
.out
.attrib
= name
->dos
.attrib
;
305 info
->attribute_tag_information
.out
.reparse_tag
= 0;
308 case RAW_FILEINFO_SEC_DESC
:
309 return pvfs_acl_query(pvfs
, req
, name
, fd
, info
);
311 case RAW_FILEINFO_SMB2_ALL_INFORMATION
:
312 info
->all_info2
.out
.create_time
= name
->dos
.create_time
;
313 info
->all_info2
.out
.access_time
= name
->dos
.access_time
;
314 info
->all_info2
.out
.write_time
= name
->dos
.write_time
;
315 info
->all_info2
.out
.change_time
= name
->dos
.change_time
;
316 info
->all_info2
.out
.attrib
= name
->dos
.attrib
;
317 info
->all_info2
.out
.unknown1
= 0;
318 info
->all_info2
.out
.alloc_size
= name
->dos
.alloc_size
;
319 info
->all_info2
.out
.size
= name
->st
.st_size
;
320 info
->all_info2
.out
.nlink
= name
->dos
.nlink
;
321 info
->all_info2
.out
.delete_pending
= 0; /* only set by qfileinfo */
322 info
->all_info2
.out
.directory
=
323 (name
->dos
.attrib
& FILE_ATTRIBUTE_DIRECTORY
)? 1 : 0;
324 info
->all_info2
.out
.file_id
= name
->dos
.file_id
;
325 info
->all_info2
.out
.ea_size
= name
->dos
.ea_size
;
326 info
->all_info2
.out
.access_mask
= 0; /* only set by qfileinfo */
327 info
->all_info2
.out
.position
= 0; /* only set by qfileinfo */
328 info
->all_info2
.out
.mode
= 0; /* only set by qfileinfo */
329 info
->all_info2
.out
.alignment_requirement
= 0;
330 /* windows wants the full path on disk for this
331 result, but I really don't want to expose that on
332 the wire, so I'll give the path with a share
333 prefix, which is a good approximation */
334 info
->all_info2
.out
.fname
.s
= talloc_asprintf(req
, "\\%s\\%s",
336 name
->original_name
);
337 NT_STATUS_HAVE_NO_MEMORY(info
->all_info2
.out
.fname
.s
);
340 case RAW_FILEINFO_GENERIC
:
341 case RAW_FILEINFO_UNIX_BASIC
:
342 case RAW_FILEINFO_UNIX_INFO2
:
343 case RAW_FILEINFO_UNIX_LINK
:
344 return NT_STATUS_INVALID_LEVEL
;
347 return NT_STATUS_INVALID_LEVEL
;
351 return info on a pathname
353 NTSTATUS
pvfs_qpathinfo(struct ntvfs_module_context
*ntvfs
,
354 struct ntvfs_request
*req
, union smb_fileinfo
*info
)
356 struct pvfs_state
*pvfs
= talloc_get_type(ntvfs
->private_data
,
358 struct pvfs_filename
*name
;
361 /* resolve the cifs name to a posix name */
362 status
= pvfs_resolve_name(pvfs
, req
, info
->generic
.in
.file
.path
, PVFS_RESOLVE_STREAMS
, &name
);
363 if (!NT_STATUS_IS_OK(status
)) {
367 if (!name
->stream_exists
) {
368 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
371 status
= pvfs_can_stat(pvfs
, req
, name
);
372 if (!NT_STATUS_IS_OK(status
)) {
376 status
= pvfs_access_check_simple(pvfs
, req
, name
,
377 pvfs_fileinfo_access(info
));
378 if (!NT_STATUS_IS_OK(status
)) {
382 status
= pvfs_map_fileinfo(pvfs
, req
, name
, info
, -1);
388 query info on a open file
390 NTSTATUS
pvfs_qfileinfo(struct ntvfs_module_context
*ntvfs
,
391 struct ntvfs_request
*req
, union smb_fileinfo
*info
)
393 struct pvfs_state
*pvfs
= talloc_get_type(ntvfs
->private_data
,
396 struct pvfs_file_handle
*h
;
398 uint32_t access_needed
;
400 f
= pvfs_find_fd(pvfs
, req
, info
->generic
.in
.file
.ntvfs
);
402 return NT_STATUS_INVALID_HANDLE
;
406 access_needed
= pvfs_fileinfo_access(info
);
407 if ((f
->access_mask
& access_needed
) != access_needed
) {
408 return NT_STATUS_ACCESS_DENIED
;
411 /* update the file information */
412 status
= pvfs_resolve_name_handle(pvfs
, h
);
413 if (!NT_STATUS_IS_OK(status
)) {
417 status
= pvfs_map_fileinfo(pvfs
, req
, h
->name
, info
, h
->fd
);
419 /* a qfileinfo can fill in a bit more info than a qpathinfo -
420 now modify the levels that need to be fixed up */
421 switch (info
->generic
.level
) {
422 case RAW_FILEINFO_STANDARD_INFO
:
423 case RAW_FILEINFO_STANDARD_INFORMATION
:
424 if (pvfs_delete_on_close_set(pvfs
, h
)) {
425 info
->standard_info
.out
.delete_pending
= 1;
426 info
->standard_info
.out
.nlink
--;
430 case RAW_FILEINFO_ALL_INFO
:
431 case RAW_FILEINFO_ALL_INFORMATION
:
432 if (pvfs_delete_on_close_set(pvfs
, h
)) {
433 info
->all_info
.out
.delete_pending
= 1;
434 info
->all_info
.out
.nlink
--;
438 case RAW_FILEINFO_POSITION_INFORMATION
:
439 info
->position_information
.out
.position
= h
->position
;
442 case RAW_FILEINFO_ACCESS_INFORMATION
:
443 info
->access_information
.out
.access_flags
= f
->access_mask
;
446 case RAW_FILEINFO_MODE_INFORMATION
:
447 info
->mode_information
.out
.mode
= h
->mode
;
450 case RAW_FILEINFO_SMB2_ALL_INFORMATION
:
451 if (pvfs_delete_on_close_set(pvfs
, h
)) {
452 info
->all_info2
.out
.delete_pending
= 1;
453 info
->all_info2
.out
.nlink
--;
455 info
->all_info2
.out
.position
= h
->position
;
456 info
->all_info2
.out
.access_mask
= f
->access_mask
;
457 info
->all_info2
.out
.mode
= h
->mode
;