LCOV - code coverage report
Current view: top level - source3/libsmb - libsmb_stat.c (source / functions) Hit Total Coverage
Test: coverage report for master 98b443d9 Lines: 85 211 40.3 %
Date: 2024-05-31 13:13:24 Functions: 4 6 66.7 %

          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             :                                                    &sectors_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             : }

Generated by: LCOV version 1.14