LCOV - code coverage report
Current view: top level - source4/libcli - clilist.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 150 163 92.0 %
Date: 2021-09-23 10:06:22 Functions: 7 7 100.0 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             :    client directory list routines
       4             :    Copyright (C) Andrew Tridgell 1994-2003
       5             :    Copyright (C) James Myers 2003 <myersjj@samba.org>
       6             :    
       7             :    This program is free software; you can redistribute it and/or modify
       8             :    it under the terms of the GNU General Public License as published by
       9             :    the Free Software Foundation; either version 3 of the License, or
      10             :    (at your option) any later version.
      11             :    
      12             :    This program is distributed in the hope that it will be useful,
      13             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :    GNU General Public License for more details.
      16             :    
      17             :    You should have received a copy of the GNU General Public License
      18             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      19             : */
      20             : 
      21             : #include "includes.h"
      22             : #include "libcli/libcli.h"
      23             : #include "libcli/raw/libcliraw.h"
      24             : #include "libcli/raw/raw_proto.h"
      25             : 
      26             : struct search_private {
      27             :         struct clilist_file_info *dirlist;
      28             :         TALLOC_CTX *mem_ctx;
      29             :         int dirlist_len;
      30             :         int ff_searchcount;  /* total received in 1 server trip */
      31             :         int total_received;  /* total received all together */
      32             :         enum smb_search_data_level data_level;
      33             :         const char *last_name;     /* used to continue trans2 search */
      34             :         struct smb_search_id id;   /* used for old-style search */
      35             : };
      36             : 
      37             : 
      38             : /****************************************************************************
      39             :  Interpret a long filename structure.
      40             : ****************************************************************************/
      41       24216 : static bool interpret_long_filename(enum smb_search_data_level level,
      42             :                                     const union smb_search_data *info,
      43             :                                     struct clilist_file_info *finfo)
      44             : {
      45             :         struct clilist_file_info finfo2;
      46             : 
      47       24216 :         if (!finfo) finfo = &finfo2;
      48       24216 :         ZERO_STRUCTP(finfo);
      49             : 
      50       24216 :         switch (level) {
      51          14 :         case RAW_SEARCH_DATA_STANDARD:
      52          14 :                 finfo->size = info->standard.size;
      53          14 :                 finfo->mtime = info->standard.write_time;
      54          14 :                 finfo->attrib = info->standard.attrib;
      55          14 :                 finfo->name = info->standard.name.s;
      56          14 :                 finfo->short_name = info->standard.name.s;
      57          14 :                 break;
      58             : 
      59       24202 :         case RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO:
      60       24202 :                 finfo->size = info->both_directory_info.size;
      61       24202 :                 finfo->mtime = nt_time_to_unix(info->both_directory_info.write_time);
      62       24202 :                 finfo->attrib = info->both_directory_info.attrib;
      63       24202 :                 finfo->short_name = info->both_directory_info.short_name.s;
      64       24202 :                 finfo->name = info->both_directory_info.name.s;
      65       24202 :                 break;
      66             : 
      67           0 :         default:
      68           0 :                 DEBUG(0,("Unhandled level %d in interpret_long_filename\n", (int)level));
      69           0 :                 return false;
      70             :         }
      71             : 
      72       24118 :         return true;
      73             : }
      74             : 
      75             : /* callback function used for trans2 search */
      76       24216 : static bool smbcli_list_new_callback(void *private_data, const union smb_search_data *file)
      77             : {
      78       24216 :         struct search_private *state = (struct search_private*) private_data;
      79             :         struct clilist_file_info *tdl;
      80             :  
      81             :         /* add file info to the dirlist pool */
      82       24216 :         tdl = talloc_realloc(state, 
      83             :                              state->dirlist,
      84             :                              struct clilist_file_info,
      85             :                              state->dirlist_len + 1);
      86       24216 :         if (!tdl) {
      87           0 :                 return false;
      88             :         }
      89       24216 :         state->dirlist = tdl;
      90       24216 :         state->dirlist_len++;
      91             : 
      92       24216 :         interpret_long_filename(state->data_level, file, &state->dirlist[state->total_received]);
      93             : 
      94       24216 :         state->last_name = state->dirlist[state->total_received].name;
      95       24216 :         state->total_received++;
      96       24216 :         state->ff_searchcount++;
      97             :         
      98       24216 :         return true;
      99             : }
     100             : 
     101        7734 : int smbcli_list_new(struct smbcli_tree *tree, const char *Mask, uint16_t attribute, 
     102             :                     enum smb_search_data_level level,
     103             :                     void (*fn)(struct clilist_file_info *, const char *, void *), 
     104             :                     void *caller_state)
     105             : {
     106             :         union smb_search_first first_parms;
     107             :         union smb_search_next next_parms;
     108             :         struct search_private state;  /* for callbacks */
     109        7734 :         int received = 0;
     110        7734 :         bool first = true;
     111        7734 :         int num_received = 0;
     112        7734 :         int max_matches = 512;
     113             :         char *mask;
     114        7734 :         int ff_eos = 0, i;
     115        7734 :         int ff_dir_handle=0;
     116             : 
     117             :         /* initialize state for search */
     118        7734 :         state.mem_ctx = talloc_init("smbcli_list_new");
     119        7734 :         state.dirlist_len = 0;
     120        7734 :         state.total_received = 0;
     121             :         
     122        7734 :         state.dirlist = talloc_array(state.mem_ctx, 
     123             :                                      struct clilist_file_info, 0);
     124        7734 :         mask = talloc_strdup(state.mem_ctx, Mask);
     125             : 
     126        7734 :         if (level == RAW_SEARCH_DATA_GENERIC) {
     127        7334 :                 if (tree->session->transport->negotiate.capabilities & CAP_NT_SMBS) {
     128        7287 :                         level = RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO;
     129             :                 } else {
     130           2 :                         level = RAW_SEARCH_DATA_STANDARD;
     131             :                 }
     132             :         }
     133        7734 :         state.data_level = level;
     134             : 
     135             :         while (1) {
     136        7745 :                 state.ff_searchcount = 0;
     137        7740 :                 if (first) {
     138             :                         NTSTATUS status;
     139             : 
     140        7734 :                         first_parms.t2ffirst.level = RAW_SEARCH_TRANS2;
     141        7734 :                         first_parms.t2ffirst.data_level = state.data_level;
     142        7734 :                         first_parms.t2ffirst.in.max_count = max_matches;
     143        7734 :                         first_parms.t2ffirst.in.search_attrib = attribute;
     144        7734 :                         first_parms.t2ffirst.in.pattern = mask;
     145        7734 :                         first_parms.t2ffirst.in.flags = FLAG_TRANS2_FIND_CLOSE_IF_END;
     146        7734 :                         first_parms.t2ffirst.in.storage_type = 0;
     147             :                         
     148        7734 :                         status = smb_raw_search_first(tree, 
     149             :                                                       state.mem_ctx, &first_parms,
     150             :                                                       (void*)&state, smbcli_list_new_callback);
     151        7734 :                         if (!NT_STATUS_IS_OK(status)) {
     152         199 :                                 talloc_free(state.mem_ctx);
     153         199 :                                 return -1;
     154             :                         }
     155             :                 
     156        7535 :                         ff_dir_handle = first_parms.t2ffirst.out.handle;
     157        7535 :                         ff_eos = first_parms.t2ffirst.out.end_of_search;
     158             :                         
     159        7535 :                         received = first_parms.t2ffirst.out.count;
     160       15019 :                         if (received <= 0) break;
     161        7535 :                         if (ff_eos) break;
     162           6 :                         first = false;
     163             :                 } else {
     164             :                         NTSTATUS status;
     165             : 
     166           6 :                         next_parms.t2fnext.level = RAW_SEARCH_TRANS2;
     167           6 :                         next_parms.t2fnext.data_level = state.data_level;
     168           6 :                         next_parms.t2fnext.in.max_count = max_matches;
     169           6 :                         next_parms.t2fnext.in.last_name = state.last_name;
     170           6 :                         next_parms.t2fnext.in.handle = ff_dir_handle;
     171           6 :                         next_parms.t2fnext.in.resume_key = 0;
     172           6 :                         next_parms.t2fnext.in.flags = FLAG_TRANS2_FIND_CLOSE_IF_END;
     173             :                         
     174           6 :                         status = smb_raw_search_next(tree, 
     175             :                                                      state.mem_ctx,
     176             :                                                      &next_parms,
     177             :                                                      (void*)&state, 
     178             :                                                      smbcli_list_new_callback);
     179             :                         
     180           6 :                         if (!NT_STATUS_IS_OK(status)) {
     181           0 :                                 return -1;
     182             :                         }
     183           6 :                         ff_eos = next_parms.t2fnext.out.end_of_search;
     184           6 :                         received = next_parms.t2fnext.out.count;
     185          12 :                         if (received <= 0) break;
     186           6 :                         if (ff_eos) break;
     187             :                 }
     188             :                 
     189           6 :                 num_received += received;
     190             :         }
     191             : 
     192       31706 :         for (i=0;i<state.total_received;i++) {
     193       24216 :                 fn(&state.dirlist[i], Mask, caller_state);
     194             :         }
     195             : 
     196        7535 :         talloc_free(state.mem_ctx);
     197             : 
     198        7535 :         return state.total_received;
     199             : }
     200             : 
     201             : /****************************************************************************
     202             :  Interpret a short filename structure.
     203             :  The length of the structure is returned.
     204             : ****************************************************************************/
     205       24038 : static bool interpret_short_filename(enum smb_search_data_level level,
     206             :                                      const union smb_search_data *info,
     207             :                                      struct clilist_file_info *finfo)
     208             : {
     209             :         struct clilist_file_info finfo2;
     210             : 
     211       24038 :         if (!finfo) finfo = &finfo2;
     212       24038 :         ZERO_STRUCTP(finfo);
     213             : 
     214       24038 :         switch (level) {
     215       24038 :         case RAW_SEARCH_DATA_SEARCH:
     216       24038 :                 finfo->mtime = info->search.write_time;
     217       24038 :                 finfo->size = info->search.size;
     218       24038 :                 finfo->attrib = info->search.attrib;
     219       24038 :                 finfo->name = info->search.name;
     220       24038 :                 finfo->short_name = info->search.name;
     221       24038 :                 break;
     222             : 
     223           0 :         default:
     224           0 :                 DEBUG(0,("Unhandled level %d in interpret_short_filename\n", (int)level));
     225           0 :                 return false;
     226             :         }
     227             :         
     228       24038 :         return true;
     229             : }
     230             : 
     231             : /* callback function used for smb_search */
     232       24038 : static bool smbcli_list_old_callback(void *private_data, const union smb_search_data *file)
     233             : {
     234       24038 :         struct search_private *state = (struct search_private*) private_data;
     235             :         struct clilist_file_info *tdl;
     236             :         
     237             :         /* add file info to the dirlist pool */
     238       24038 :         tdl = talloc_realloc(state,
     239             :                              state->dirlist,
     240             :                              struct clilist_file_info,
     241             :                              state->dirlist_len + 1);
     242             : 
     243       24038 :         if (!tdl) {
     244           0 :                 return false;
     245             :         }
     246       24038 :         state->dirlist = tdl;
     247       24038 :         state->dirlist_len++;
     248             : 
     249       24038 :         interpret_short_filename(state->data_level, file, &state->dirlist[state->total_received]);
     250             : 
     251       24038 :         state->total_received++;
     252       24038 :         state->ff_searchcount++;
     253       24038 :         state->id = file->search.id; /* return resume info */
     254             :         
     255       24038 :         return true;
     256             : }
     257             : 
     258          20 : int smbcli_list_old(struct smbcli_tree *tree, const char *Mask, uint16_t attribute, 
     259             :                  void (*fn)(struct clilist_file_info *, const char *, void *), 
     260             :                  void *caller_state)
     261             : {
     262             :         union smb_search_first first_parms;
     263             :         union smb_search_next next_parms;
     264             :         struct search_private state;  /* for callbacks */
     265          20 :         const int num_asked = 500;
     266          20 :         int received = 0;
     267          20 :         bool first = true;
     268          20 :         int num_received = 0;
     269             :         char *mask;
     270             :         int i;
     271             : 
     272             :         /* initialize state for search */
     273          20 :         state.mem_ctx = talloc_init("smbcli_list_old");
     274          20 :         state.dirlist_len = 0;
     275          20 :         state.total_received = 0;
     276          20 :         state.data_level = RAW_SEARCH_DATA_SEARCH;
     277             : 
     278          20 :         state.dirlist = talloc_array(state.mem_ctx, struct clilist_file_info,
     279             :                                      0);
     280          20 :         mask = talloc_strdup(state.mem_ctx, Mask);
     281             :   
     282             :         while (1) {
     283         133 :                 state.ff_searchcount = 0;
     284          82 :                 if (first) {
     285             :                         NTSTATUS status;
     286             : 
     287          20 :                         first_parms.search_first.level = RAW_SEARCH_SEARCH;
     288          20 :                         first_parms.search_first.data_level = RAW_SEARCH_DATA_SEARCH;
     289          20 :                         first_parms.search_first.in.max_count = num_asked;
     290          20 :                         first_parms.search_first.in.search_attrib = attribute;
     291          20 :                         first_parms.search_first.in.pattern = mask;
     292             :                         
     293          20 :                         status = smb_raw_search_first(tree, state.mem_ctx, 
     294             :                                                       &first_parms,
     295             :                                                       (void*)&state, 
     296             :                                                       smbcli_list_old_callback);
     297             : 
     298          20 :                         if (!NT_STATUS_IS_OK(status)) {
     299           0 :                                 talloc_free(state.mem_ctx);
     300           0 :                                 return -1;
     301             :                         }
     302             :                 
     303          20 :                         received = first_parms.search_first.out.count;
     304          20 :                         if (received <= 0) break;
     305          20 :                         first = false;
     306             :                 } else {
     307             :                         NTSTATUS status;
     308             : 
     309          62 :                         next_parms.search_next.level = RAW_SEARCH_SEARCH;
     310          62 :                         next_parms.search_next.data_level = RAW_SEARCH_DATA_SEARCH;
     311          62 :                         next_parms.search_next.in.max_count = num_asked;
     312          62 :                         next_parms.search_next.in.search_attrib = attribute;
     313          62 :                         next_parms.search_next.in.id = state.id;
     314             :                         
     315          62 :                         status = smb_raw_search_next(tree, state.mem_ctx,
     316             :                                                      &next_parms,
     317             :                                                      (void*)&state, 
     318             :                                                      smbcli_list_old_callback);
     319             : 
     320          62 :                         if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
     321          16 :                                 break;
     322             :                         }
     323          62 :                         if (!NT_STATUS_IS_OK(status)) {
     324           0 :                                 talloc_free(state.mem_ctx);
     325           0 :                                 return -1;
     326             :                         }
     327          62 :                         received = next_parms.search_next.out.count;
     328          62 :                         if (received <= 0) break;
     329             :                 }
     330             :                 
     331          62 :                 num_received += received;
     332             :         }
     333             : 
     334       24058 :         for (i=0;i<state.total_received;i++) {
     335       24038 :                 fn(&state.dirlist[i], Mask, caller_state);
     336             :         }
     337             : 
     338          20 :         talloc_free(state.mem_ctx);
     339             : 
     340          20 :         return state.total_received;
     341             : }
     342             : 
     343             : /****************************************************************************
     344             :  Do a directory listing, calling fn on each file found.
     345             :  This auto-switches between old and new style.
     346             : ****************************************************************************/
     347             : 
     348        7336 : int smbcli_list(struct smbcli_tree *tree, const char *Mask,uint16_t attribute, 
     349             :                 void (*fn)(struct clilist_file_info *, const char *, void *), void *state)
     350             : {
     351        7336 :         if (tree->session->transport->negotiate.protocol <= PROTOCOL_LANMAN1)
     352           2 :                 return smbcli_list_old(tree, Mask, attribute, fn, state);
     353        7334 :         return smbcli_list_new(tree, Mask, attribute, RAW_SEARCH_DATA_GENERIC, fn, state);
     354             : }

Generated by: LCOV version 1.13