LCOV - code coverage report
Current view: top level - source4/torture/raw - qfsinfo.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 103 123 83.7 %
Date: 2024-04-21 15:09:00 Functions: 2 2 100.0 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             :    RAW_QFS_* individual test suite
       4             :    Copyright (C) Andrew Tridgell 2003
       5             :    
       6             :    This program is free software; you can redistribute it and/or modify
       7             :    it under the terms of the GNU General Public License as published by
       8             :    the Free Software Foundation; either version 3 of the License, or
       9             :    (at your option) any later version.
      10             :    
      11             :    This program is distributed in the hope that it will be useful,
      12             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :    GNU General Public License for more details.
      15             :    
      16             :    You should have received a copy of the GNU General Public License
      17             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      18             : */
      19             : 
      20             : #include "includes.h"
      21             : #include <math.h>
      22             : #include "libcli/libcli.h"
      23             : #include "torture/util.h"
      24             : #include "torture/basic/proto.h"
      25             : #include "torture/raw/proto.h"
      26             : 
      27             : 
      28             : static struct {
      29             :         const char *name;
      30             :         enum smb_fsinfo_level level;
      31             :         uint32_t capability_mask;
      32             :         NTSTATUS status;
      33             :         union smb_fsinfo fsinfo;
      34             : } levels[] = {
      35             :         {
      36             :                 .name = "DSKATTR",
      37             :                 .level = RAW_QFS_DSKATTR,
      38             :         },
      39             :         {
      40             :                 .name = "ALLOCATION",
      41             :                 .level = RAW_QFS_ALLOCATION,
      42             :         },
      43             :         {
      44             :                 .name = "VOLUME",
      45             :                 .level = RAW_QFS_VOLUME,
      46             :         },
      47             :         {
      48             :                 .name = "VOLUME_INFO",
      49             :                 .level = RAW_QFS_VOLUME_INFO,
      50             :         },
      51             :         {
      52             :                 .name = "SIZE_INFO",
      53             :                 .level = RAW_QFS_SIZE_INFO,
      54             :         },
      55             :         {
      56             :                 .name = "DEVICE_INFO",
      57             :                 .level = RAW_QFS_DEVICE_INFO,
      58             :         },
      59             :         {
      60             :                 .name = "ATTRIBUTE_INFO",
      61             :                 .level = RAW_QFS_ATTRIBUTE_INFO,
      62             :         },
      63             :         {
      64             :                 .name = "UNIX_INFO",
      65             :                 .level = RAW_QFS_UNIX_INFO,
      66             :                 .capability_mask = CAP_UNIX,
      67             :         },
      68             :         {
      69             :                 .name = "VOLUME_INFORMATION",
      70             :                 .level = RAW_QFS_VOLUME_INFORMATION,
      71             :         },
      72             :         {
      73             :                 .name = "SIZE_INFORMATION",
      74             :                 .level = RAW_QFS_SIZE_INFORMATION,
      75             :         },
      76             :         {
      77             :                 .name = "DEVICE_INFORMATION",
      78             :                 .level = RAW_QFS_DEVICE_INFORMATION,
      79             :         },
      80             :         {
      81             :                 .name = "ATTRIBUTE_INFORMATION",
      82             :                 .level = RAW_QFS_ATTRIBUTE_INFORMATION,
      83             :         },
      84             :         {
      85             :                 .name = "QUOTA_INFORMATION",
      86             :                 .level = RAW_QFS_QUOTA_INFORMATION,
      87             :         },
      88             :         {
      89             :                 .name = "FULL_SIZE_INFORMATION",
      90             :                 .level = RAW_QFS_FULL_SIZE_INFORMATION,
      91             :         },
      92             : #if 0
      93             :         /* w2k3 seems to no longer support this */
      94             :         {"OBJECTID_INFORMATION",  RAW_QFS_OBJECTID_INFORMATION, },
      95             : #endif
      96             :         { .name = NULL, },
      97             : };
      98             : 
      99             : 
     100             : /*
     101             :   find a level in the levels[] table
     102             : */
     103          23 : static union smb_fsinfo *find(const char *name)
     104             : {
     105           0 :         int i;
     106         159 :         for (i=0; levels[i].name; i++) {
     107         158 :                 if (strcmp(name, levels[i].name) == 0 &&
     108          22 :                     NT_STATUS_IS_OK(levels[i].status)) {
     109          22 :                         return &levels[i].fsinfo;
     110             :                 }
     111             :         }
     112           1 :         return NULL;
     113             : }
     114             : 
     115             : /* local macros to make the code below more readable */
     116             : #define VAL_EQUAL(n1, v1, n2, v2) do {if (s1->n1.out.v1 != s2->n2.out.v2) { \
     117             :         printf("%s/%s [%u] != %s/%s [%u] at %s(%d)\n", \
     118             :                #n1, #v1, (unsigned int)s1->n1.out.v1, \
     119             :                #n2, #v2, (unsigned int)s2->n2.out.v2, \
     120             :                __FILE__, __LINE__); \
     121             :         ret = false; \
     122             : }} while(0)
     123             : 
     124             : #define VAL_APPROX_EQUAL(n1, v1, n2, v2) do {if (abs((int)(s1->n1.out.v1) - (int)(s2->n2.out.v2)) > 0.1*s1->n1.out.v1) { \
     125             :         printf("%s/%s [%u] != %s/%s [%u] at %s(%d)\n", \
     126             :                #n1, #v1, (unsigned int)s1->n1.out.v1, \
     127             :                #n2, #v2, (unsigned int)s2->n2.out.v2, \
     128             :                __FILE__, __LINE__); \
     129             :         ret = false; \
     130             : }} while(0)
     131             : 
     132             : #define STR_EQUAL(n1, v1, n2, v2) do { \
     133             :        if (strcmp_safe(s1->n1.out.v1, s2->n2.out.v2)) { \
     134             :          printf("%s/%s [%s] != %s/%s [%s] at %s(%d)\n", \
     135             :                #n1, #v1, s1->n1.out.v1, \
     136             :                #n2, #v2, s2->n2.out.v2, \
     137             :                __FILE__, __LINE__); \
     138             :         ret = false; \
     139             : }} while(0)
     140             : 
     141             : #define STRUCT_EQUAL(n1, v1, n2, v2) do {if (memcmp(&s1->n1.out.v1,&s2->n2.out.v2,sizeof(s1->n1.out.v1))) { \
     142             :         printf("%s/%s != %s/%s at %s(%d)\n", \
     143             :                #n1, #v1, \
     144             :                #n2, #v2, \
     145             :                __FILE__, __LINE__); \
     146             :         ret = false; \
     147             : }} while(0)
     148             : 
     149             : /* used to find hints on unknown values - and to make sure 
     150             :    we zero-fill */
     151             : #define VAL_UNKNOWN(n1, v1) do {if (s1->n1.out.v1 != 0) { \
     152             :         printf("%s/%s non-zero unknown - %u (0x%x) at %s(%d)\n", \
     153             :                #n1, #v1, \
     154             :                (unsigned int)s1->n1.out.v1, \
     155             :                (unsigned int)s1->n1.out.v1, \
     156             :                __FILE__, __LINE__); \
     157             :         ret = false; \
     158             : }} while(0)
     159             : 
     160             : /* basic testing of all RAW_QFS_* calls 
     161             :    for each call we test that it succeeds, and where possible test 
     162             :    for consistency between the calls. 
     163             : 
     164             :    Some of the consistency tests assume that the target filesystem is
     165             :    quiescent, which is sometimes hard to achieve
     166             : */
     167           1 : bool torture_raw_qfsinfo(struct torture_context *torture, 
     168             :                          struct smbcli_state *cli)
     169             : {
     170           0 :         size_t i;
     171           1 :         bool ret = true;
     172           0 :         size_t count;
     173           0 :         union smb_fsinfo *s1, *s2;      
     174             : 
     175             :         /* scan all the levels, pulling the results */
     176          15 :         for (i=0; levels[i].name; i++) {
     177          14 :                 torture_comment(torture, "Running level %s\n", levels[i].name);
     178          14 :                 levels[i].fsinfo.generic.level = levels[i].level;
     179          14 :                 levels[i].status = smb_raw_fsinfo(cli->tree, torture, &levels[i].fsinfo);
     180             :         }
     181             : 
     182             :         /* check for completely broken levels */
     183          15 :         for (count=i=0; levels[i].name; i++) {
     184          14 :                 uint32_t cap = cli->transport->negotiate.capabilities;
     185             :                 /* see if this server claims to support this level */
     186          14 :                 if ((cap & levels[i].capability_mask) != levels[i].capability_mask) {
     187           1 :                         continue;
     188             :                 }
     189             :                 
     190          13 :                 if (!NT_STATUS_IS_OK(levels[i].status)) {
     191           0 :                         printf("ERROR: level %s failed - %s\n", 
     192             :                                levels[i].name, nt_errstr(levels[i].status));
     193           0 :                         count++;
     194             :                 }
     195             :         }
     196             : 
     197           1 :         if (count != 0) {
     198           0 :                 torture_comment(torture, "%zu levels failed\n", count);
     199           0 :                 torture_assert(torture, count > 13, "too many level failures - giving up");
     200             :         }
     201             : 
     202           1 :         torture_comment(torture, "check for correct aliases\n");
     203           1 :         s1 = find("SIZE_INFO");
     204           1 :         s2 = find("SIZE_INFORMATION");
     205           1 :         if (s1 && s2) {
     206           1 :                 VAL_EQUAL(size_info, total_alloc_units, size_info, total_alloc_units);
     207           1 :                 VAL_APPROX_EQUAL(size_info, avail_alloc_units, size_info, avail_alloc_units);
     208           1 :                 VAL_EQUAL(size_info, sectors_per_unit,  size_info, sectors_per_unit);
     209           1 :                 VAL_EQUAL(size_info, bytes_per_sector,  size_info, bytes_per_sector);
     210             :         }       
     211             : 
     212           1 :         s1 = find("DEVICE_INFO");
     213           1 :         s2 = find("DEVICE_INFORMATION");
     214           1 :         if (s1 && s2) {
     215           1 :                 VAL_EQUAL(device_info, device_type,     device_info, device_type);
     216           1 :                 VAL_EQUAL(device_info, characteristics, device_info, characteristics);
     217             :         }       
     218             : 
     219           1 :         s1 = find("VOLUME_INFO");
     220           1 :         s2 = find("VOLUME_INFORMATION");
     221           1 :         if (s1 && s2) {
     222           1 :                 STRUCT_EQUAL(volume_info, create_time,    volume_info, create_time);
     223           1 :                 VAL_EQUAL   (volume_info, serial_number,  volume_info, serial_number);
     224           1 :                 STR_EQUAL   (volume_info, volume_name.s,    volume_info, volume_name.s);
     225           1 :                 torture_comment(torture, "volume_info.volume_name = '%s'\n", s1->volume_info.out.volume_name.s);
     226             :         }       
     227             : 
     228           1 :         s1 = find("ATTRIBUTE_INFO");
     229           1 :         s2 = find("ATTRIBUTE_INFORMATION");
     230           1 :         if (s1 && s2) {
     231           1 :                 VAL_EQUAL(attribute_info, fs_attr,    
     232             :                           attribute_info, fs_attr);
     233           1 :                 VAL_EQUAL(attribute_info, max_file_component_length, 
     234             :                           attribute_info, max_file_component_length);
     235           1 :                 STR_EQUAL(attribute_info, fs_type.s, attribute_info, fs_type.s);
     236           1 :                 torture_comment(torture, "attribute_info.fs_type = '%s'\n", s1->attribute_info.out.fs_type.s);
     237             :         }       
     238             : 
     239           1 :         torture_comment(torture, "check for consistent disk sizes\n");
     240           1 :         s1 = find("DSKATTR");
     241           1 :         s2 = find("ALLOCATION");
     242           1 :         if (s1 && s2) {
     243           0 :                 double size1, size2;
     244           1 :                 double scale = s1->dskattr.out.blocks_per_unit * s1->dskattr.out.block_size;
     245           1 :                 size1 = 1.0 * 
     246           1 :                         s1->dskattr.out.units_total * 
     247           1 :                         s1->dskattr.out.blocks_per_unit * 
     248           1 :                         s1->dskattr.out.block_size / scale;
     249           1 :                 size2 = 1.0 *
     250           1 :                         s2->allocation.out.sectors_per_unit *
     251           1 :                         s2->allocation.out.total_alloc_units *
     252           1 :                         s2->allocation.out.bytes_per_sector / scale;
     253           1 :                 if (fabs(size1 - size2) > 1) {
     254           0 :                         printf("Inconsistent total size in DSKATTR and ALLOCATION - size1=%.0f size2=%.0f\n", 
     255             :                                size1, size2);
     256           0 :                         ret = false;
     257             :                 }
     258           1 :                 torture_comment(torture, "total disk = %.0f MB\n", size1*scale/1.0e6);
     259             :         }
     260             : 
     261           1 :         torture_comment(torture, "check consistent free disk space\n");
     262           1 :         s1 = find("DSKATTR");
     263           1 :         s2 = find("ALLOCATION");
     264           1 :         if (s1 && s2) {
     265           0 :                 double size1, size2;
     266           1 :                 double scale = s1->dskattr.out.blocks_per_unit * s1->dskattr.out.block_size;
     267           1 :                 size1 = 1.0 * 
     268           1 :                         s1->dskattr.out.units_free * 
     269           1 :                         s1->dskattr.out.blocks_per_unit * 
     270           1 :                         s1->dskattr.out.block_size / scale;
     271           1 :                 size2 = 1.0 *
     272           1 :                         s2->allocation.out.sectors_per_unit *
     273           1 :                         s2->allocation.out.avail_alloc_units *
     274           1 :                         s2->allocation.out.bytes_per_sector / scale;
     275           1 :                 if (fabs(size1 - size2) > 1) {
     276           0 :                         printf("Inconsistent avail size in DSKATTR and ALLOCATION - size1=%.0f size2=%.0f\n", 
     277             :                                size1, size2);
     278           0 :                         ret = false;
     279             :                 }
     280           1 :                 torture_comment(torture, "free disk = %.0f MB\n", size1*scale/1.0e6);
     281             :         }
     282             :         
     283           1 :         torture_comment(torture, "volume info consistency\n");
     284           1 :         s1 = find("VOLUME");
     285           1 :         s2 = find("VOLUME_INFO");
     286           1 :         if (s1 && s2) {
     287           1 :                 VAL_EQUAL(volume, serial_number,  volume_info, serial_number);
     288           1 :                 STR_EQUAL(volume, volume_name.s,  volume_info, volume_name.s);
     289             :         }       
     290             : 
     291             :         /* disk size consistency - notice that 'avail_alloc_units' maps to the caller
     292             :            available allocation units, not the total */
     293           1 :         s1 = find("SIZE_INFO");
     294           1 :         s2 = find("FULL_SIZE_INFORMATION");
     295           1 :         if (s1 && s2) {
     296           1 :                 VAL_EQUAL(size_info, total_alloc_units, full_size_information, total_alloc_units);
     297           1 :                 VAL_APPROX_EQUAL(size_info, avail_alloc_units, full_size_information, call_avail_alloc_units);
     298           1 :                 VAL_EQUAL(size_info, sectors_per_unit,  full_size_information, sectors_per_unit);
     299           1 :                 VAL_EQUAL(size_info, bytes_per_sector,  full_size_information, bytes_per_sector);
     300             :         }       
     301             : 
     302           1 :         printf("check for non-zero unknown fields\n");
     303           1 :         s1 = find("QUOTA_INFORMATION");
     304           1 :         if (s1) {
     305           1 :                 VAL_UNKNOWN(quota_information, unknown[0]);
     306           1 :                 VAL_UNKNOWN(quota_information, unknown[1]);
     307           1 :                 VAL_UNKNOWN(quota_information, unknown[2]);
     308             :         }
     309             : 
     310           1 :         s1 = find("OBJECTID_INFORMATION");
     311           1 :         if (s1) {
     312           0 :                 VAL_UNKNOWN(objectid_information, unknown[0]);
     313           0 :                 VAL_UNKNOWN(objectid_information, unknown[1]);
     314           0 :                 VAL_UNKNOWN(objectid_information, unknown[2]);
     315           0 :                 VAL_UNKNOWN(objectid_information, unknown[3]);
     316           0 :                 VAL_UNKNOWN(objectid_information, unknown[4]);
     317           0 :                 VAL_UNKNOWN(objectid_information, unknown[5]);
     318             :         }
     319             : 
     320             : 
     321             : #define STR_CHECK(sname, stype, field, flags) do { \
     322             :         s1 = find(sname); \
     323             :         if (s1) { \
     324             :                 if (s1->stype.out.field.s && wire_bad_flags(&s1->stype.out.field, flags, cli->transport)) { \
     325             :                         printf("(%d) incorrect string termination in %s/%s\n", \
     326             :                                __LINE__, #stype, #field); \
     327             :                         ret = false; \
     328             :                 } \
     329             :         }} while (0)
     330             : 
     331           1 :         torture_comment(torture, "check for correct termination\n");
     332             :         
     333           1 :         STR_CHECK("VOLUME",                volume,         volume_name, 0);
     334           1 :         STR_CHECK("VOLUME_INFO",           volume_info,    volume_name, STR_UNICODE);
     335           1 :         STR_CHECK("VOLUME_INFORMATION",    volume_info,    volume_name, STR_UNICODE);
     336           1 :         STR_CHECK("ATTRIBUTE_INFO",        attribute_info, fs_type, STR_UNICODE);
     337           1 :         STR_CHECK("ATTRIBUTE_INFORMATION", attribute_info, fs_type, STR_UNICODE);
     338             : 
     339           1 :         return ret;
     340             : }

Generated by: LCOV version 1.14