~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source3/libsmb/libsmb_stat.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

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