s3:idmap_ad: add support for ADS_AUTH_SASL_{STARTTLS,LDAPS}
[Samba.git] / source3 / libsmb / libsmb_stat.c
blobae18f5946474a0808dc66db7776a27aec1a83453
1 /*
2 Unix SMB/Netbios implementation.
3 SMB client library implementation
4 Copyright (C) Andrew Tridgell 1998
5 Copyright (C) Richard Sharpe 2000, 2002
6 Copyright (C) John Terpstra 2000
7 Copyright (C) Tom Jansen (Ninja ISD) 2002
8 Copyright (C) Derrell Lipman 2003-2008
9 Copyright (C) Jeremy Allison 2007, 2008
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 3 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "includes.h"
26 #include "libsmb/libsmb.h"
27 #include "libsmbclient.h"
28 #include "libsmb_internal.h"
29 #include "../libcli/smb/smbXcli_base.h"
30 #include "lib/util/time.h"
33 * Generate an inode number from file name for those things that need it
36 static ino_t generate_inode(const char *name)
38 if (name == NULL) {
39 return (ino_t)-1;
41 return (ino_t)str_checksum(name);
45 * Routine to put basic stat info into a stat structure ... Used by stat and
46 * fstat below.
49 void setup_stat(struct stat *st,
50 const char *fname,
51 off_t size,
52 int attr,
53 ino_t ino,
54 dev_t dev,
55 struct timespec access_time_ts,
56 struct timespec change_time_ts,
57 struct timespec write_time_ts)
59 st->st_mode = 0;
61 if (attr & FILE_ATTRIBUTE_DIRECTORY) {
62 st->st_mode = (S_IFDIR | 0555);
63 } else {
64 st->st_mode = (S_IFREG | 0444);
67 if (attr & FILE_ATTRIBUTE_ARCHIVE) {
68 st->st_mode |= S_IXUSR;
70 if (attr & FILE_ATTRIBUTE_SYSTEM) {
71 st->st_mode |= S_IXGRP;
73 if (attr & FILE_ATTRIBUTE_HIDDEN) {
74 st->st_mode |= S_IXOTH;
76 if (!(attr & FILE_ATTRIBUTE_READONLY)) {
77 st->st_mode |= S_IWUSR;
80 st->st_size = size;
81 #ifdef HAVE_STAT_ST_BLKSIZE
82 st->st_blksize = 512;
83 #endif
84 #ifdef HAVE_STAT_ST_BLOCKS
85 st->st_blocks = (size+511)/512;
86 #endif
87 #ifdef HAVE_STRUCT_STAT_ST_RDEV
88 st->st_rdev = 0;
89 #endif
90 st->st_uid = getuid();
91 st->st_gid = getgid();
93 if (attr & FILE_ATTRIBUTE_DIRECTORY) {
94 st->st_nlink = 2;
95 } else {
96 st->st_nlink = 1;
99 if (ino != 0) {
100 st->st_ino = ino;
101 } else {
102 st->st_ino = generate_inode(fname);
105 st->st_dev = dev;
107 st->st_atime = access_time_ts.tv_sec;
108 set_atimensec(st, access_time_ts.tv_nsec);
110 st->st_ctime = change_time_ts.tv_sec;
111 set_ctimensec(st, change_time_ts.tv_nsec);
113 st->st_mtime = write_time_ts.tv_sec;
114 set_mtimensec(st, write_time_ts.tv_nsec);
117 void setup_stat_from_stat_ex(const struct stat_ex *stex,
118 const char *fname,
119 struct stat *st)
121 st->st_atime = stex->st_ex_atime.tv_sec;
122 set_atimensec(st, stex->st_ex_atime.tv_nsec);
124 st->st_ctime = stex->st_ex_ctime.tv_sec;
125 set_ctimensec(st, stex->st_ex_ctime.tv_nsec);
127 st->st_mtime = stex->st_ex_mtime.tv_sec;
128 set_mtimensec(st, stex->st_ex_mtime.tv_nsec);
130 st->st_mode = stex->st_ex_mode;
131 st->st_size = stex->st_ex_size;
132 #ifdef HAVE_STAT_ST_BLKSIZE
133 st->st_blksize = 512;
134 #endif
135 #ifdef HAVE_STAT_ST_BLOCKS
136 st->st_blocks = (st->st_size + 511) / 512;
137 #endif
138 #ifdef HAVE_STRUCT_STAT_ST_RDEV
139 st->st_rdev = 0;
140 #endif
141 st->st_uid = stex->st_ex_uid;
142 st->st_gid = stex->st_ex_gid;
144 st->st_nlink = stex->st_ex_nlink;
146 if (stex->st_ex_ino == 0) {
147 st->st_ino = 0;
148 if (fname != NULL) {
149 st->st_ino = generate_inode(fname);
151 } else {
152 st->st_ino = stex->st_ex_ino;
155 st->st_dev = stex->st_ex_dev;
160 * Routine to stat a file given a name
164 SMBC_stat_ctx(SMBCCTX *context,
165 const char *fname,
166 struct stat *st)
168 SMBCSRV *srv = NULL;
169 char *server = NULL;
170 char *share = NULL;
171 char *user = NULL;
172 char *password = NULL;
173 char *workgroup = NULL;
174 char *path = NULL;
175 uint16_t port = 0;
176 NTSTATUS status;
177 TALLOC_CTX *frame = talloc_stackframe();
179 if (!context || !context->internal->initialized) {
180 errno = EINVAL; /* Best I can think of ... */
181 TALLOC_FREE(frame);
182 return -1;
185 if (!fname) {
186 errno = EINVAL;
187 TALLOC_FREE(frame);
188 return -1;
191 DEBUG(4, ("smbc_stat(%s)\n", fname));
193 if (SMBC_parse_path(frame,
194 context,
195 fname,
196 &workgroup,
197 &server,
198 &port,
199 &share,
200 &path,
201 &user,
202 &password,
203 NULL)) {
204 errno = EINVAL;
205 TALLOC_FREE(frame);
206 return -1;
209 if (!user || user[0] == (char)0) {
210 user = talloc_strdup(frame, smbc_getUser(context));
211 if (!user) {
212 errno = ENOMEM;
213 TALLOC_FREE(frame);
214 return -1;
218 srv = SMBC_server(frame, context, True,
219 server, port, share, &workgroup, &user, &password);
220 if (!srv) {
221 TALLOC_FREE(frame);
222 return -1; /* errno set by SMBC_server */
225 status = SMBC_getatr(context, srv, path, st);
226 if (!NT_STATUS_IS_OK(status)) {
227 TALLOC_FREE(frame);
228 errno = cli_status_to_errno(status);
229 return -1;
232 TALLOC_FREE(frame);
233 return 0;
237 * Routine to stat a file given an fd
241 SMBC_fstat_ctx(SMBCCTX *context,
242 SMBCFILE *file,
243 struct stat *st)
245 struct timespec change_time_ts;
246 struct timespec access_time_ts;
247 struct timespec write_time_ts;
248 off_t size;
249 uint32_t attr;
250 char *server = NULL;
251 char *share = NULL;
252 char *user = NULL;
253 char *password = NULL;
254 char *path = NULL;
255 char *targetpath = NULL;
256 struct cli_state *targetcli = NULL;
257 SMB_INO_T ino = 0;
258 uint16_t port = 0;
259 struct cli_credentials *creds = NULL;
260 TALLOC_CTX *frame = talloc_stackframe();
261 NTSTATUS status;
263 if (!context || !context->internal->initialized) {
264 errno = EINVAL;
265 TALLOC_FREE(frame);
266 return -1;
269 if (!SMBC_dlist_contains(context->internal->files, file)) {
270 errno = EBADF;
271 TALLOC_FREE(frame);
272 return -1;
275 if (!file->file) {
276 TALLOC_FREE(frame);
277 return smbc_getFunctionFstatdir(context)(context, file, st);
280 /*d_printf(">>>fstat: parsing %s\n", file->fname);*/
281 if (SMBC_parse_path(frame,
282 context,
283 file->fname,
284 NULL,
285 &server,
286 &port,
287 &share,
288 &path,
289 &user,
290 &password,
291 NULL)) {
292 errno = EINVAL;
293 TALLOC_FREE(frame);
294 return -1;
297 creds = context->internal->creds;
299 /*d_printf(">>>fstat: resolving %s\n", path);*/
300 status = cli_resolve_path(frame, "",
301 creds,
302 file->srv->cli, path,
303 &targetcli, &targetpath);
304 if (!NT_STATUS_IS_OK(status)) {
305 d_printf("Could not resolve %s\n", path);
306 errno = ENOENT;
307 TALLOC_FREE(frame);
308 return -1;
310 /*d_printf(">>>fstat: resolved path as %s\n", targetpath);*/
312 if (!NT_STATUS_IS_OK(cli_qfileinfo_basic(
313 targetcli, file->cli_fd, &attr, &size,
314 NULL,
315 &access_time_ts,
316 &write_time_ts,
317 &change_time_ts,
318 &ino))) {
319 errno = EINVAL;
320 TALLOC_FREE(frame);
321 return -1;
324 setup_stat(st,
325 path,
326 size,
327 attr,
328 ino,
329 file->srv->dev,
330 access_time_ts,
331 change_time_ts,
332 write_time_ts);
334 TALLOC_FREE(frame);
335 return 0;
340 * Routine to obtain file system information given a path
343 SMBC_statvfs_ctx(SMBCCTX *context,
344 char *path,
345 struct statvfs *st)
347 int ret;
348 bool bIsDir;
349 struct stat statbuf;
350 SMBCFILE * pFile;
351 TALLOC_CTX *frame = talloc_stackframe();
353 /* Determine if the provided path is a file or a folder */
354 if (SMBC_stat_ctx(context, path, &statbuf) < 0) {
355 TALLOC_FREE(frame);
356 return -1;
359 /* Is it a file or a directory? */
360 if (S_ISDIR(statbuf.st_mode)) {
361 /* It's a directory. */
362 if ((pFile = SMBC_opendir_ctx(context, path)) == NULL) {
363 TALLOC_FREE(frame);
364 return -1;
366 bIsDir = true;
367 } else if (S_ISREG(statbuf.st_mode)) {
368 /* It's a file. */
369 if ((pFile = SMBC_open_ctx(context, path,
370 O_RDONLY, 0)) == NULL) {
371 TALLOC_FREE(frame);
372 return -1;
374 bIsDir = false;
375 } else {
376 /* It's neither a file nor a directory. Not supported. */
377 TALLOC_FREE(frame);
378 errno = ENOSYS;
379 return -1;
382 /* Now we have an open file handle, so just use SMBC_fstatvfs */
383 ret = SMBC_fstatvfs_ctx(context, pFile, st);
385 /* Close the file or directory */
386 if (bIsDir) {
387 SMBC_closedir_ctx(context, pFile);
388 } else {
389 SMBC_close_ctx(context, pFile);
392 TALLOC_FREE(frame);
393 return ret;
398 * Routine to obtain file system information given an fd
402 SMBC_fstatvfs_ctx(SMBCCTX *context,
403 SMBCFILE *file,
404 struct statvfs *st)
406 unsigned long flags = 0;
407 uint32_t fs_attrs = 0;
408 struct cli_state *cli = file->srv->cli;
409 struct smbXcli_tcon *tcon;
410 TALLOC_CTX *frame = talloc_stackframe();
412 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
413 tcon = cli->smb2.tcon;
414 } else {
415 tcon = cli->smb1.tcon;
418 /* Initialize all fields (at least until we actually use them) */
419 ZERO_STRUCTP(st);
422 * The state of each flag is such that the same bits are unset as
423 * would typically be unset on a local file system on a POSIX OS. Thus
424 * the bit is on, for example, only for case-insensitive file systems
425 * since most POSIX file systems are case sensitive and fstatvfs()
426 * would typically return zero in these bits on such a local file
427 * system.
430 /* See if the server has UNIX CIFS support */
431 if (! SERVER_HAS_UNIX_CIFS(cli)) {
432 uint64_t total_allocation_units;
433 uint64_t caller_allocation_units;
434 uint64_t actual_allocation_units;
435 uint64_t sectors_per_allocation_unit;
436 uint64_t bytes_per_sector;
437 NTSTATUS status;
439 /* Nope. If size data is available... */
440 status = cli_get_fs_full_size_info(cli,
441 &total_allocation_units,
442 &caller_allocation_units,
443 &actual_allocation_units,
444 &sectors_per_allocation_unit,
445 &bytes_per_sector);
446 if (NT_STATUS_IS_OK(status)) {
448 /* ... then provide it */
449 st->f_bsize =
450 (unsigned long) bytes_per_sector;
451 #ifdef HAVE_FRSIZE
452 st->f_frsize =
453 (unsigned long) sectors_per_allocation_unit;
454 #endif
455 st->f_blocks =
456 (fsblkcnt_t) total_allocation_units;
457 st->f_bfree =
458 (fsblkcnt_t) actual_allocation_units;
459 st->f_bavail =
460 (fsblkcnt_t) caller_allocation_units;
463 flags |= SMBC_VFS_FEATURE_NO_UNIXCIFS;
464 } else {
465 uint32_t optimal_transfer_size;
466 uint32_t block_size;
467 uint64_t total_blocks;
468 uint64_t blocks_available;
469 uint64_t user_blocks_available;
470 uint64_t total_file_nodes;
471 uint64_t free_file_nodes;
472 uint64_t fs_identifier;
473 NTSTATUS status;
475 /* Has UNIXCIFS. If POSIX filesystem info is available... */
476 status = cli_get_posix_fs_info(cli,
477 &optimal_transfer_size,
478 &block_size,
479 &total_blocks,
480 &blocks_available,
481 &user_blocks_available,
482 &total_file_nodes,
483 &free_file_nodes,
484 &fs_identifier);
485 if (NT_STATUS_IS_OK(status)) {
487 /* ... then what's provided here takes precedence. */
488 st->f_bsize =
489 (unsigned long) block_size;
490 st->f_blocks =
491 (fsblkcnt_t) total_blocks;
492 st->f_bfree =
493 (fsblkcnt_t) blocks_available;
494 st->f_bavail =
495 (fsblkcnt_t) user_blocks_available;
496 st->f_files =
497 (fsfilcnt_t) total_file_nodes;
498 st->f_ffree =
499 (fsfilcnt_t) free_file_nodes;
500 #ifdef HAVE_FSID_INT
501 st->f_fsid =
502 (unsigned long) fs_identifier;
503 #endif
507 /* See if the share is case sensitive */
508 if (!NT_STATUS_IS_OK(cli_get_fs_attr_info(cli, &fs_attrs))) {
510 * We can't determine the case sensitivity of
511 * the share. We have no choice but to use the
512 * user-specified case sensitivity setting.
514 if (! smbc_getOptionCaseSensitive(context)) {
515 flags |= SMBC_VFS_FEATURE_CASE_INSENSITIVE;
517 } else {
518 if (! (fs_attrs & FILE_CASE_SENSITIVE_SEARCH)) {
519 flags |= SMBC_VFS_FEATURE_CASE_INSENSITIVE;
523 /* See if DFS is supported */
524 if (smbXcli_conn_dfs_supported(cli->conn) &&
525 smbXcli_tcon_is_dfs_share(tcon))
527 flags |= SMBC_VFS_FEATURE_DFS;
530 #if defined(HAVE_STATVFS_F_FLAG)
531 st->f_flag = flags;
532 #elif defined(HAVE_STATVFS_F_FLAGS)
533 st->f_flags = flags;
534 #endif
536 TALLOC_FREE(frame);
537 return 0;