LCOV - code coverage report
Current view: top level - source3/libsmb - libsmb_stat.c (source / functions) Hit Total Coverage
Test: coverage report for fix-15632 9995c5c2 Lines: 84 233 36.1 %
Date: 2024-04-13 12:30:31 Functions: 4 7 57.1 %

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

Generated by: LCOV version 1.14