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 eas
->eas
[i
].value
= ealist
->eas
[j
].value
;
114 reply to a RAW_FILEINFO_ALL_EAS call
116 static NTSTATUS
pvfs_query_all_eas(struct pvfs_state
*pvfs
, TALLOC_CTX
*mem_ctx
,
117 struct pvfs_filename
*name
, int fd
,
118 struct smb_ea_list
*eas
)
122 struct xattr_DosEAs
*ealist
= talloc(mem_ctx
, struct xattr_DosEAs
);
125 status
= pvfs_doseas_load(pvfs
, name
, fd
, ealist
);
126 if (!NT_STATUS_IS_OK(status
)) {
129 eas
->eas
= talloc_array(mem_ctx
, struct ea_struct
, ealist
->num_eas
);
130 if (eas
->eas
== NULL
) {
131 return NT_STATUS_NO_MEMORY
;
134 for (i
=0;i
<ealist
->num_eas
;i
++) {
135 eas
->eas
[eas
->num_eas
].flags
= 0;
136 eas
->eas
[eas
->num_eas
].name
.s
= ealist
->eas
[i
].name
;
137 eas
->eas
[eas
->num_eas
].value
= ealist
->eas
[i
].value
;
144 approximately map a struct pvfs_filename to a generic fileinfo struct
146 static NTSTATUS
pvfs_map_fileinfo(struct pvfs_state
*pvfs
,
147 struct ntvfs_request
*req
,
148 struct pvfs_filename
*name
, union smb_fileinfo
*info
,
151 switch (info
->generic
.level
) {
152 case RAW_FILEINFO_GETATTR
:
153 info
->getattr
.out
.attrib
= name
->dos
.attrib
;
154 info
->getattr
.out
.size
= name
->st
.st_size
;
155 info
->getattr
.out
.write_time
= nt_time_to_unix(name
->dos
.write_time
);
158 case RAW_FILEINFO_GETATTRE
:
159 case RAW_FILEINFO_STANDARD
:
160 info
->standard
.out
.create_time
= nt_time_to_unix(name
->dos
.create_time
);
161 info
->standard
.out
.access_time
= nt_time_to_unix(name
->dos
.access_time
);
162 info
->standard
.out
.write_time
= nt_time_to_unix(name
->dos
.write_time
);
163 info
->standard
.out
.size
= name
->st
.st_size
;
164 info
->standard
.out
.alloc_size
= name
->dos
.alloc_size
;
165 info
->standard
.out
.attrib
= name
->dos
.attrib
;
168 case RAW_FILEINFO_EA_SIZE
:
169 info
->ea_size
.out
.create_time
= nt_time_to_unix(name
->dos
.create_time
);
170 info
->ea_size
.out
.access_time
= nt_time_to_unix(name
->dos
.access_time
);
171 info
->ea_size
.out
.write_time
= nt_time_to_unix(name
->dos
.write_time
);
172 info
->ea_size
.out
.size
= name
->st
.st_size
;
173 info
->ea_size
.out
.alloc_size
= name
->dos
.alloc_size
;
174 info
->ea_size
.out
.attrib
= name
->dos
.attrib
;
175 info
->ea_size
.out
.ea_size
= name
->dos
.ea_size
;
178 case RAW_FILEINFO_EA_LIST
:
179 return pvfs_query_ea_list(pvfs
, req
, name
, fd
,
180 info
->ea_list
.in
.num_names
,
181 info
->ea_list
.in
.ea_names
,
184 case RAW_FILEINFO_ALL_EAS
:
185 return pvfs_query_all_eas(pvfs
, req
, name
, fd
, &info
->all_eas
.out
);
187 case RAW_FILEINFO_SMB2_ALL_EAS
: {
188 NTSTATUS status
= pvfs_query_all_eas(pvfs
, req
, name
, fd
, &info
->all_eas
.out
);
189 if (NT_STATUS_IS_OK(status
) &&
190 info
->all_eas
.out
.num_eas
== 0) {
191 return NT_STATUS_NO_EAS_ON_FILE
;
196 case RAW_FILEINFO_IS_NAME_VALID
:
199 case RAW_FILEINFO_BASIC_INFO
:
200 case RAW_FILEINFO_BASIC_INFORMATION
:
201 info
->basic_info
.out
.create_time
= name
->dos
.create_time
;
202 info
->basic_info
.out
.access_time
= name
->dos
.access_time
;
203 info
->basic_info
.out
.write_time
= name
->dos
.write_time
;
204 info
->basic_info
.out
.change_time
= name
->dos
.change_time
;
205 info
->basic_info
.out
.attrib
= name
->dos
.attrib
;
208 case RAW_FILEINFO_STANDARD_INFO
:
209 case RAW_FILEINFO_STANDARD_INFORMATION
:
210 info
->standard_info
.out
.alloc_size
= name
->dos
.alloc_size
;
211 info
->standard_info
.out
.size
= name
->st
.st_size
;
212 info
->standard_info
.out
.nlink
= name
->dos
.nlink
;
213 info
->standard_info
.out
.delete_pending
= 0; /* only for qfileinfo */
214 info
->standard_info
.out
.directory
=
215 (name
->dos
.attrib
& FILE_ATTRIBUTE_DIRECTORY
)? 1 : 0;
218 case RAW_FILEINFO_EA_INFO
:
219 case RAW_FILEINFO_EA_INFORMATION
:
220 info
->ea_info
.out
.ea_size
= name
->dos
.ea_size
;
223 case RAW_FILEINFO_NAME_INFO
:
224 case RAW_FILEINFO_NAME_INFORMATION
:
225 if (req
->ctx
->protocol
>= PROTOCOL_SMB2_02
) {
226 /* strange that SMB2 doesn't have this */
227 return NT_STATUS_NOT_SUPPORTED
;
229 info
->name_info
.out
.fname
.s
= name
->original_name
;
232 case RAW_FILEINFO_ALL_INFO
:
233 case RAW_FILEINFO_ALL_INFORMATION
:
234 info
->all_info
.out
.create_time
= name
->dos
.create_time
;
235 info
->all_info
.out
.access_time
= name
->dos
.access_time
;
236 info
->all_info
.out
.write_time
= name
->dos
.write_time
;
237 info
->all_info
.out
.change_time
= name
->dos
.change_time
;
238 info
->all_info
.out
.attrib
= name
->dos
.attrib
;
239 info
->all_info
.out
.alloc_size
= name
->dos
.alloc_size
;
240 info
->all_info
.out
.size
= name
->st
.st_size
;
241 info
->all_info
.out
.nlink
= name
->dos
.nlink
;
242 info
->all_info
.out
.delete_pending
= 0; /* only set by qfileinfo */
243 info
->all_info
.out
.directory
=
244 (name
->dos
.attrib
& FILE_ATTRIBUTE_DIRECTORY
)? 1 : 0;
245 info
->all_info
.out
.ea_size
= name
->dos
.ea_size
;
246 info
->all_info
.out
.fname
.s
= name
->original_name
;
249 case RAW_FILEINFO_ALT_NAME_INFO
:
250 case RAW_FILEINFO_ALT_NAME_INFORMATION
:
251 info
->name_info
.out
.fname
.s
= pvfs_short_name(pvfs
, name
, name
);
254 case RAW_FILEINFO_STREAM_INFO
:
255 case RAW_FILEINFO_STREAM_INFORMATION
:
256 return pvfs_stream_information(pvfs
, req
, name
, fd
, &info
->stream_info
.out
);
258 case RAW_FILEINFO_COMPRESSION_INFO
:
259 case RAW_FILEINFO_COMPRESSION_INFORMATION
:
260 info
->compression_info
.out
.compressed_size
= name
->st
.st_size
;
261 info
->compression_info
.out
.format
= 0;
262 info
->compression_info
.out
.unit_shift
= 0;
263 info
->compression_info
.out
.chunk_shift
= 0;
264 info
->compression_info
.out
.cluster_shift
= 0;
267 case RAW_FILEINFO_INTERNAL_INFORMATION
:
268 info
->internal_information
.out
.file_id
= name
->dos
.file_id
;
271 case RAW_FILEINFO_ACCESS_INFORMATION
:
272 info
->access_information
.out
.access_flags
= 0; /* only set by qfileinfo */
275 case RAW_FILEINFO_POSITION_INFORMATION
:
276 info
->position_information
.out
.position
= 0; /* only set by qfileinfo */
279 case RAW_FILEINFO_MODE_INFORMATION
:
280 info
->mode_information
.out
.mode
= 0; /* only set by qfileinfo */
283 case RAW_FILEINFO_ALIGNMENT_INFORMATION
:
284 info
->alignment_information
.out
.alignment_requirement
= 0;
287 case RAW_FILEINFO_NETWORK_OPEN_INFORMATION
:
288 info
->network_open_information
.out
.create_time
= name
->dos
.create_time
;
289 info
->network_open_information
.out
.access_time
= name
->dos
.access_time
;
290 info
->network_open_information
.out
.write_time
= name
->dos
.write_time
;
291 info
->network_open_information
.out
.change_time
= name
->dos
.change_time
;
292 info
->network_open_information
.out
.alloc_size
= name
->dos
.alloc_size
;
293 info
->network_open_information
.out
.size
= name
->st
.st_size
;
294 info
->network_open_information
.out
.attrib
= name
->dos
.attrib
;
297 case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION
:
298 info
->attribute_tag_information
.out
.attrib
= name
->dos
.attrib
;
299 info
->attribute_tag_information
.out
.reparse_tag
= 0;
302 case RAW_FILEINFO_SEC_DESC
:
303 return pvfs_acl_query(pvfs
, req
, name
, fd
, info
);
305 case RAW_FILEINFO_SMB2_ALL_INFORMATION
:
306 info
->all_info2
.out
.create_time
= name
->dos
.create_time
;
307 info
->all_info2
.out
.access_time
= name
->dos
.access_time
;
308 info
->all_info2
.out
.write_time
= name
->dos
.write_time
;
309 info
->all_info2
.out
.change_time
= name
->dos
.change_time
;
310 info
->all_info2
.out
.attrib
= name
->dos
.attrib
;
311 info
->all_info2
.out
.unknown1
= 0;
312 info
->all_info2
.out
.alloc_size
= name
->dos
.alloc_size
;
313 info
->all_info2
.out
.size
= name
->st
.st_size
;
314 info
->all_info2
.out
.nlink
= name
->dos
.nlink
;
315 info
->all_info2
.out
.delete_pending
= 0; /* only set by qfileinfo */
316 info
->all_info2
.out
.directory
=
317 (name
->dos
.attrib
& FILE_ATTRIBUTE_DIRECTORY
)? 1 : 0;
318 info
->all_info2
.out
.file_id
= name
->dos
.file_id
;
319 info
->all_info2
.out
.ea_size
= name
->dos
.ea_size
;
320 info
->all_info2
.out
.access_mask
= 0; /* only set by qfileinfo */
321 info
->all_info2
.out
.position
= 0; /* only set by qfileinfo */
322 info
->all_info2
.out
.mode
= 0; /* only set by qfileinfo */
323 info
->all_info2
.out
.alignment_requirement
= 0;
324 /* windows wants the full path on disk for this
325 result, but I really don't want to expose that on
326 the wire, so I'll give the path with a share
327 prefix, which is a good approximation */
328 info
->all_info2
.out
.fname
.s
= talloc_asprintf(req
, "\\%s\\%s",
330 name
->original_name
);
331 NT_STATUS_HAVE_NO_MEMORY(info
->all_info2
.out
.fname
.s
);
334 case RAW_FILEINFO_GENERIC
:
335 case RAW_FILEINFO_UNIX_BASIC
:
336 case RAW_FILEINFO_UNIX_INFO2
:
337 case RAW_FILEINFO_UNIX_LINK
:
338 return NT_STATUS_INVALID_LEVEL
;
341 return NT_STATUS_INVALID_LEVEL
;
345 return info on a pathname
347 NTSTATUS
pvfs_qpathinfo(struct ntvfs_module_context
*ntvfs
,
348 struct ntvfs_request
*req
, union smb_fileinfo
*info
)
350 struct pvfs_state
*pvfs
= talloc_get_type(ntvfs
->private_data
,
352 struct pvfs_filename
*name
;
355 /* resolve the cifs name to a posix name */
356 status
= pvfs_resolve_name(pvfs
, req
, info
->generic
.in
.file
.path
, PVFS_RESOLVE_STREAMS
, &name
);
357 if (!NT_STATUS_IS_OK(status
)) {
361 if (!name
->stream_exists
) {
362 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
365 status
= pvfs_can_stat(pvfs
, req
, name
);
366 if (!NT_STATUS_IS_OK(status
)) {
370 status
= pvfs_access_check_simple(pvfs
, req
, name
,
371 pvfs_fileinfo_access(info
));
372 if (!NT_STATUS_IS_OK(status
)) {
376 status
= pvfs_map_fileinfo(pvfs
, req
, name
, info
, -1);
382 query info on a open file
384 NTSTATUS
pvfs_qfileinfo(struct ntvfs_module_context
*ntvfs
,
385 struct ntvfs_request
*req
, union smb_fileinfo
*info
)
387 struct pvfs_state
*pvfs
= talloc_get_type(ntvfs
->private_data
,
390 struct pvfs_file_handle
*h
;
392 uint32_t access_needed
;
394 f
= pvfs_find_fd(pvfs
, req
, info
->generic
.in
.file
.ntvfs
);
396 return NT_STATUS_INVALID_HANDLE
;
400 access_needed
= pvfs_fileinfo_access(info
);
401 if ((f
->access_mask
& access_needed
) != access_needed
) {
402 return NT_STATUS_ACCESS_DENIED
;
405 /* update the file information */
406 status
= pvfs_resolve_name_handle(pvfs
, h
);
407 if (!NT_STATUS_IS_OK(status
)) {
411 status
= pvfs_map_fileinfo(pvfs
, req
, h
->name
, info
, h
->fd
);
413 /* a qfileinfo can fill in a bit more info than a qpathinfo -
414 now modify the levels that need to be fixed up */
415 switch (info
->generic
.level
) {
416 case RAW_FILEINFO_STANDARD_INFO
:
417 case RAW_FILEINFO_STANDARD_INFORMATION
:
418 if (pvfs_delete_on_close_set(pvfs
, h
)) {
419 info
->standard_info
.out
.delete_pending
= 1;
420 info
->standard_info
.out
.nlink
--;
424 case RAW_FILEINFO_ALL_INFO
:
425 case RAW_FILEINFO_ALL_INFORMATION
:
426 if (pvfs_delete_on_close_set(pvfs
, h
)) {
427 info
->all_info
.out
.delete_pending
= 1;
428 info
->all_info
.out
.nlink
--;
432 case RAW_FILEINFO_POSITION_INFORMATION
:
433 info
->position_information
.out
.position
= h
->position
;
436 case RAW_FILEINFO_ACCESS_INFORMATION
:
437 info
->access_information
.out
.access_flags
= f
->access_mask
;
440 case RAW_FILEINFO_MODE_INFORMATION
:
441 info
->mode_information
.out
.mode
= h
->mode
;
444 case RAW_FILEINFO_SMB2_ALL_INFORMATION
:
445 if (pvfs_delete_on_close_set(pvfs
, h
)) {
446 info
->all_info2
.out
.delete_pending
= 1;
447 info
->all_info2
.out
.nlink
--;
449 info
->all_info2
.out
.position
= h
->position
;
450 info
->all_info2
.out
.access_mask
= f
->access_mask
;
451 info
->all_info2
.out
.mode
= h
->mode
;