Line data Source code
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
10 :
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.
15 :
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.
20 :
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/>.
23 : */
24 :
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"
31 :
32 : /*
33 : * Generate an inode number from file name for those things that need it
34 : */
35 :
36 103 : static ino_t generate_inode(const char *name)
37 : {
38 103 : if (name == NULL) {
39 0 : return (ino_t)-1;
40 : }
41 103 : return (ino_t)str_checksum(name);
42 : }
43 :
44 : /*
45 : * Routine to put basic stat info into a stat structure ... Used by stat and
46 : * fstat below.
47 : */
48 :
49 312 : 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)
58 : {
59 312 : st->st_mode = 0;
60 :
61 312 : if (attr & FILE_ATTRIBUTE_DIRECTORY) {
62 150 : st->st_mode = (S_IFDIR | 0555);
63 : } else {
64 162 : st->st_mode = (S_IFREG | 0444);
65 : }
66 :
67 312 : if (attr & FILE_ATTRIBUTE_ARCHIVE) {
68 62 : st->st_mode |= S_IXUSR;
69 : }
70 312 : if (attr & FILE_ATTRIBUTE_SYSTEM) {
71 0 : st->st_mode |= S_IXGRP;
72 : }
73 312 : if (attr & FILE_ATTRIBUTE_HIDDEN) {
74 4 : st->st_mode |= S_IXOTH;
75 : }
76 312 : if (!(attr & FILE_ATTRIBUTE_READONLY)) {
77 312 : st->st_mode |= S_IWUSR;
78 : }
79 :
80 312 : st->st_size = size;
81 : #ifdef HAVE_STAT_ST_BLKSIZE
82 312 : st->st_blksize = 512;
83 : #endif
84 : #ifdef HAVE_STAT_ST_BLOCKS
85 312 : st->st_blocks = (size+511)/512;
86 : #endif
87 : #ifdef HAVE_STRUCT_STAT_ST_RDEV
88 312 : st->st_rdev = 0;
89 : #endif
90 312 : st->st_uid = getuid();
91 312 : st->st_gid = getgid();
92 :
93 312 : if (attr & FILE_ATTRIBUTE_DIRECTORY) {
94 150 : st->st_nlink = 2;
95 : } else {
96 162 : st->st_nlink = 1;
97 : }
98 :
99 312 : if (ino != 0) {
100 209 : st->st_ino = ino;
101 : } else {
102 103 : st->st_ino = generate_inode(fname);
103 : }
104 :
105 312 : st->st_dev = dev;
106 :
107 312 : st->st_atime = access_time_ts.tv_sec;
108 312 : set_atimensec(st, access_time_ts.tv_nsec);
109 :
110 312 : st->st_ctime = change_time_ts.tv_sec;
111 312 : set_ctimensec(st, change_time_ts.tv_nsec);
112 :
113 312 : st->st_mtime = write_time_ts.tv_sec;
114 312 : set_mtimensec(st, write_time_ts.tv_nsec);
115 312 : }
116 :
117 : /*
118 : * Routine to stat a file given a name
119 : */
120 :
121 : int
122 12 : SMBC_stat_ctx(SMBCCTX *context,
123 : const char *fname,
124 : struct stat *st)
125 : {
126 12 : SMBCSRV *srv = NULL;
127 12 : char *server = NULL;
128 12 : char *share = NULL;
129 12 : char *user = NULL;
130 12 : char *password = NULL;
131 12 : char *workgroup = NULL;
132 12 : char *path = NULL;
133 12 : uint16_t port = 0;
134 0 : NTSTATUS status;
135 12 : TALLOC_CTX *frame = talloc_stackframe();
136 :
137 12 : if (!context || !context->internal->initialized) {
138 0 : errno = EINVAL; /* Best I can think of ... */
139 0 : TALLOC_FREE(frame);
140 0 : return -1;
141 : }
142 :
143 12 : if (!fname) {
144 0 : errno = EINVAL;
145 0 : TALLOC_FREE(frame);
146 0 : return -1;
147 : }
148 :
149 12 : DEBUG(4, ("smbc_stat(%s)\n", fname));
150 :
151 12 : if (SMBC_parse_path(frame,
152 : context,
153 : fname,
154 : &workgroup,
155 : &server,
156 : &port,
157 : &share,
158 : &path,
159 : &user,
160 : &password,
161 : NULL)) {
162 0 : errno = EINVAL;
163 0 : TALLOC_FREE(frame);
164 0 : return -1;
165 : }
166 :
167 12 : if (!user || user[0] == (char)0) {
168 0 : user = talloc_strdup(frame, smbc_getUser(context));
169 0 : if (!user) {
170 0 : errno = ENOMEM;
171 0 : TALLOC_FREE(frame);
172 0 : return -1;
173 : }
174 : }
175 :
176 12 : srv = SMBC_server(frame, context, True,
177 : server, port, share, &workgroup, &user, &password);
178 12 : if (!srv) {
179 0 : TALLOC_FREE(frame);
180 0 : return -1; /* errno set by SMBC_server */
181 : }
182 :
183 12 : status = SMBC_getatr(context, srv, path, st);
184 12 : if (!NT_STATUS_IS_OK(status)) {
185 4 : TALLOC_FREE(frame);
186 4 : errno = cli_status_to_errno(status);
187 4 : return -1;
188 : }
189 :
190 8 : TALLOC_FREE(frame);
191 8 : return 0;
192 : }
193 :
194 : /*
195 : * Routine to stat a file given an fd
196 : */
197 :
198 : int
199 68 : SMBC_fstat_ctx(SMBCCTX *context,
200 : SMBCFILE *file,
201 : struct stat *st)
202 : {
203 0 : struct timespec change_time_ts;
204 0 : struct timespec access_time_ts;
205 0 : struct timespec write_time_ts;
206 0 : off_t size;
207 0 : uint32_t attr;
208 68 : char *server = NULL;
209 68 : char *share = NULL;
210 68 : char *user = NULL;
211 68 : char *password = NULL;
212 68 : char *path = NULL;
213 68 : char *targetpath = NULL;
214 68 : struct cli_state *targetcli = NULL;
215 68 : SMB_INO_T ino = 0;
216 68 : uint16_t port = 0;
217 68 : struct cli_credentials *creds = NULL;
218 68 : TALLOC_CTX *frame = talloc_stackframe();
219 0 : NTSTATUS status;
220 :
221 68 : if (!context || !context->internal->initialized) {
222 0 : errno = EINVAL;
223 0 : TALLOC_FREE(frame);
224 0 : return -1;
225 : }
226 :
227 68 : if (!SMBC_dlist_contains(context->internal->files, file)) {
228 0 : errno = EBADF;
229 0 : TALLOC_FREE(frame);
230 0 : return -1;
231 : }
232 :
233 68 : if (!file->file) {
234 0 : TALLOC_FREE(frame);
235 0 : return smbc_getFunctionFstatdir(context)(context, file, st);
236 : }
237 :
238 : /*d_printf(">>>fstat: parsing %s\n", file->fname);*/
239 68 : if (SMBC_parse_path(frame,
240 : context,
241 68 : file->fname,
242 : NULL,
243 : &server,
244 : &port,
245 : &share,
246 : &path,
247 : &user,
248 : &password,
249 : NULL)) {
250 0 : errno = EINVAL;
251 0 : TALLOC_FREE(frame);
252 0 : return -1;
253 : }
254 :
255 68 : creds = context->internal->creds;
256 :
257 : /*d_printf(">>>fstat: resolving %s\n", path);*/
258 68 : status = cli_resolve_path(frame, "",
259 : creds,
260 68 : file->srv->cli, path,
261 : &targetcli, &targetpath);
262 68 : if (!NT_STATUS_IS_OK(status)) {
263 0 : d_printf("Could not resolve %s\n", path);
264 0 : errno = ENOENT;
265 0 : TALLOC_FREE(frame);
266 0 : return -1;
267 : }
268 : /*d_printf(">>>fstat: resolved path as %s\n", targetpath);*/
269 :
270 68 : if (!NT_STATUS_IS_OK(cli_qfileinfo_basic(
271 : targetcli, file->cli_fd, &attr, &size,
272 : NULL,
273 : &access_time_ts,
274 : &write_time_ts,
275 : &change_time_ts,
276 : &ino))) {
277 0 : errno = EINVAL;
278 0 : TALLOC_FREE(frame);
279 0 : return -1;
280 : }
281 :
282 68 : setup_stat(st,
283 : path,
284 : size,
285 : attr,
286 : ino,
287 68 : file->srv->dev,
288 : access_time_ts,
289 : change_time_ts,
290 : write_time_ts);
291 :
292 68 : TALLOC_FREE(frame);
293 68 : return 0;
294 : }
295 :
296 :
297 : /*
298 : * Routine to obtain file system information given a path
299 : */
300 : int
301 0 : SMBC_statvfs_ctx(SMBCCTX *context,
302 : char *path,
303 : struct statvfs *st)
304 : {
305 0 : int ret;
306 0 : bool bIsDir;
307 0 : struct stat statbuf;
308 0 : SMBCFILE * pFile;
309 0 : TALLOC_CTX *frame = talloc_stackframe();
310 :
311 : /* Determine if the provided path is a file or a folder */
312 0 : if (SMBC_stat_ctx(context, path, &statbuf) < 0) {
313 0 : TALLOC_FREE(frame);
314 0 : return -1;
315 : }
316 :
317 : /* Is it a file or a directory? */
318 0 : if (S_ISDIR(statbuf.st_mode)) {
319 : /* It's a directory. */
320 0 : if ((pFile = SMBC_opendir_ctx(context, path)) == NULL) {
321 0 : TALLOC_FREE(frame);
322 0 : return -1;
323 : }
324 0 : bIsDir = true;
325 0 : } else if (S_ISREG(statbuf.st_mode)) {
326 : /* It's a file. */
327 0 : if ((pFile = SMBC_open_ctx(context, path,
328 : O_RDONLY, 0)) == NULL) {
329 0 : TALLOC_FREE(frame);
330 0 : return -1;
331 : }
332 0 : bIsDir = false;
333 : } else {
334 : /* It's neither a file nor a directory. Not supported. */
335 0 : TALLOC_FREE(frame);
336 0 : errno = ENOSYS;
337 0 : return -1;
338 : }
339 :
340 : /* Now we have an open file handle, so just use SMBC_fstatvfs */
341 0 : ret = SMBC_fstatvfs_ctx(context, pFile, st);
342 :
343 : /* Close the file or directory */
344 0 : if (bIsDir) {
345 0 : SMBC_closedir_ctx(context, pFile);
346 : } else {
347 0 : SMBC_close_ctx(context, pFile);
348 : }
349 :
350 0 : TALLOC_FREE(frame);
351 0 : return ret;
352 : }
353 :
354 :
355 : /*
356 : * Routine to obtain file system information given an fd
357 : */
358 :
359 : int
360 0 : SMBC_fstatvfs_ctx(SMBCCTX *context,
361 : SMBCFILE *file,
362 : struct statvfs *st)
363 : {
364 0 : unsigned long flags = 0;
365 0 : uint32_t fs_attrs = 0;
366 0 : struct cli_state *cli = file->srv->cli;
367 0 : struct smbXcli_tcon *tcon;
368 0 : TALLOC_CTX *frame = talloc_stackframe();
369 :
370 0 : if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
371 0 : tcon = cli->smb2.tcon;
372 : } else {
373 0 : tcon = cli->smb1.tcon;
374 : }
375 :
376 : /* Initialize all fields (at least until we actually use them) */
377 0 : ZERO_STRUCTP(st);
378 :
379 : /*
380 : * The state of each flag is such that the same bits are unset as
381 : * would typically be unset on a local file system on a POSIX OS. Thus
382 : * the bit is on, for example, only for case-insensitive file systems
383 : * since most POSIX file systems are case sensitive and fstatvfs()
384 : * would typically return zero in these bits on such a local file
385 : * system.
386 : */
387 :
388 : /* See if the server has UNIX CIFS support */
389 0 : if (! SERVER_HAS_UNIX_CIFS(cli)) {
390 0 : uint64_t total_allocation_units;
391 0 : uint64_t caller_allocation_units;
392 0 : uint64_t actual_allocation_units;
393 0 : uint64_t sectors_per_allocation_unit;
394 0 : uint64_t bytes_per_sector;
395 0 : NTSTATUS status;
396 :
397 : /* Nope. If size data is available... */
398 0 : status = cli_get_fs_full_size_info(cli,
399 : &total_allocation_units,
400 : &caller_allocation_units,
401 : &actual_allocation_units,
402 : §ors_per_allocation_unit,
403 : &bytes_per_sector);
404 0 : if (NT_STATUS_IS_OK(status)) {
405 :
406 : /* ... then provide it */
407 0 : st->f_bsize =
408 : (unsigned long) bytes_per_sector;
409 : #ifdef HAVE_FRSIZE
410 0 : st->f_frsize =
411 : (unsigned long) sectors_per_allocation_unit;
412 : #endif
413 0 : st->f_blocks =
414 : (fsblkcnt_t) total_allocation_units;
415 0 : st->f_bfree =
416 : (fsblkcnt_t) actual_allocation_units;
417 0 : st->f_bavail =
418 : (fsblkcnt_t) caller_allocation_units;
419 : }
420 :
421 0 : flags |= SMBC_VFS_FEATURE_NO_UNIXCIFS;
422 : } else {
423 0 : uint32_t optimal_transfer_size;
424 0 : uint32_t block_size;
425 0 : uint64_t total_blocks;
426 0 : uint64_t blocks_available;
427 0 : uint64_t user_blocks_available;
428 0 : uint64_t total_file_nodes;
429 0 : uint64_t free_file_nodes;
430 0 : uint64_t fs_identifier;
431 0 : NTSTATUS status;
432 :
433 : /* Has UNIXCIFS. If POSIX filesystem info is available... */
434 0 : status = cli_get_posix_fs_info(cli,
435 : &optimal_transfer_size,
436 : &block_size,
437 : &total_blocks,
438 : &blocks_available,
439 : &user_blocks_available,
440 : &total_file_nodes,
441 : &free_file_nodes,
442 : &fs_identifier);
443 0 : if (NT_STATUS_IS_OK(status)) {
444 :
445 : /* ... then what's provided here takes precedence. */
446 0 : st->f_bsize =
447 0 : (unsigned long) block_size;
448 0 : st->f_blocks =
449 : (fsblkcnt_t) total_blocks;
450 0 : st->f_bfree =
451 : (fsblkcnt_t) blocks_available;
452 0 : st->f_bavail =
453 : (fsblkcnt_t) user_blocks_available;
454 0 : st->f_files =
455 : (fsfilcnt_t) total_file_nodes;
456 0 : st->f_ffree =
457 : (fsfilcnt_t) free_file_nodes;
458 : #ifdef HAVE_FSID_INT
459 0 : st->f_fsid =
460 : (unsigned long) fs_identifier;
461 : #endif
462 : }
463 : }
464 :
465 : /* See if the share is case sensitive */
466 0 : if (!NT_STATUS_IS_OK(cli_get_fs_attr_info(cli, &fs_attrs))) {
467 : /*
468 : * We can't determine the case sensitivity of
469 : * the share. We have no choice but to use the
470 : * user-specified case sensitivity setting.
471 : */
472 0 : if (! smbc_getOptionCaseSensitive(context)) {
473 0 : flags |= SMBC_VFS_FEATURE_CASE_INSENSITIVE;
474 : }
475 : } else {
476 0 : if (! (fs_attrs & FILE_CASE_SENSITIVE_SEARCH)) {
477 0 : flags |= SMBC_VFS_FEATURE_CASE_INSENSITIVE;
478 : }
479 : }
480 :
481 : /* See if DFS is supported */
482 0 : if (smbXcli_conn_dfs_supported(cli->conn) &&
483 0 : smbXcli_tcon_is_dfs_share(tcon))
484 : {
485 0 : flags |= SMBC_VFS_FEATURE_DFS;
486 : }
487 :
488 : #if defined(HAVE_STATVFS_F_FLAG)
489 0 : st->f_flag = flags;
490 : #elif defined(HAVE_STATVFS_F_FLAGS)
491 : st->f_flags = flags;
492 : #endif
493 :
494 0 : TALLOC_FREE(frame);
495 0 : return 0;
496 : }
|