LCOV - code coverage report
Current view: top level - source4/libcli - clilist.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 144 178 80.9 %
Date: 2024-04-21 15:09:00 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       39364 : 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         134 :         struct clilist_file_info finfo2;
      46             : 
      47       39364 :         if (!finfo) finfo = &finfo2;
      48       39364 :         ZERO_STRUCTP(finfo);
      49             : 
      50       39364 :         switch (level) {
      51           0 :         case RAW_SEARCH_DATA_STANDARD:
      52           0 :                 finfo->size = info->standard.size;
      53           0 :                 finfo->mtime = info->standard.write_time;
      54           0 :                 finfo->attrib = info->standard.attrib;
      55           0 :                 finfo->name = info->standard.name.s;
      56           0 :                 finfo->short_name = info->standard.name.s;
      57           0 :                 break;
      58             : 
      59       39364 :         case RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO:
      60       39364 :                 finfo->size = info->both_directory_info.size;
      61       39364 :                 finfo->mtime = nt_time_to_unix(info->both_directory_info.write_time);
      62       39364 :                 finfo->attrib = info->both_directory_info.attrib;
      63       39364 :                 finfo->short_name = info->both_directory_info.short_name.s;
      64       39364 :                 finfo->name = info->both_directory_info.name.s;
      65       39364 :                 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       39230 :         return true;
      73             : }
      74             : 
      75             : /* callback function used for trans2 search */
      76       39364 : static bool smbcli_list_new_callback(void *private_data, const union smb_search_data *file)
      77             : {
      78       39364 :         struct search_private *state = (struct search_private*) private_data;
      79         134 :         struct clilist_file_info *tdl;
      80             :  
      81             :         /* add file info to the dirlist pool */
      82       39364 :         tdl = talloc_realloc(state, 
      83             :                              state->dirlist,
      84             :                              struct clilist_file_info,
      85             :                              state->dirlist_len + 1);
      86       39364 :         if (!tdl) {
      87           0 :                 return false;
      88             :         }
      89       39364 :         state->dirlist = tdl;
      90       39364 :         state->dirlist_len++;
      91             : 
      92       39364 :         interpret_long_filename(state->data_level, file, &state->dirlist[state->total_received]);
      93             : 
      94       39364 :         state->last_name = state->dirlist[state->total_received].name;
      95       39364 :         state->total_received++;
      96       39364 :         state->ff_searchcount++;
      97             :         
      98       39364 :         return true;
      99             : }
     100             : 
     101        8710 : 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          88 :         union smb_search_first first_parms;
     107          88 :         union smb_search_next next_parms;
     108          88 :         struct search_private state;  /* for callbacks */
     109        8710 :         int received = 0;
     110        8710 :         bool first = true;
     111        8710 :         int max_matches = 512;
     112          88 :         char *mask;
     113        8710 :         int ff_eos = 0, i;
     114        8710 :         int ff_dir_handle=0;
     115             : 
     116             :         /* initialize state for search */
     117        8710 :         state.mem_ctx = talloc_init("smbcli_list_new");
     118        8710 :         state.dirlist_len = 0;
     119        8710 :         state.total_received = 0;
     120             :         
     121        8710 :         state.dirlist = talloc_array(state.mem_ctx, 
     122             :                                      struct clilist_file_info, 0);
     123        8710 :         mask = talloc_strdup(state.mem_ctx, Mask);
     124             : 
     125        8710 :         if (level == RAW_SEARCH_DATA_GENERIC) {
     126        8310 :                 if (tree->session->transport->negotiate.capabilities & CAP_NT_SMBS) {
     127        8222 :                         level = RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO;
     128             :                 } else {
     129           0 :                         level = RAW_SEARCH_DATA_STANDARD;
     130             :                 }
     131             :         }
     132        8710 :         state.data_level = level;
     133             : 
     134          88 :         while (1) {
     135        8736 :                 state.ff_searchcount = 0;
     136        8736 :                 if (first) {
     137          88 :                         NTSTATUS status;
     138             : 
     139        8710 :                         first_parms.t2ffirst.level = RAW_SEARCH_TRANS2;
     140        8710 :                         first_parms.t2ffirst.data_level = state.data_level;
     141        8710 :                         first_parms.t2ffirst.in.max_count = max_matches;
     142        8710 :                         first_parms.t2ffirst.in.search_attrib = attribute;
     143        8710 :                         first_parms.t2ffirst.in.pattern = mask;
     144        8710 :                         first_parms.t2ffirst.in.flags = FLAG_TRANS2_FIND_CLOSE_IF_END;
     145        8710 :                         first_parms.t2ffirst.in.storage_type = 0;
     146             :                         
     147        8710 :                         status = smb_raw_search_first(tree, 
     148             :                                                       state.mem_ctx, &first_parms,
     149             :                                                       (void*)&state, smbcli_list_new_callback);
     150        8710 :                         if (!NT_STATUS_IS_OK(status)) {
     151         641 :                                 talloc_free(state.mem_ctx);
     152         641 :                                 return -1;
     153             :                         }
     154             :                 
     155        8069 :                         ff_dir_handle = first_parms.t2ffirst.out.handle;
     156        8069 :                         ff_eos = first_parms.t2ffirst.out.end_of_search;
     157             :                         
     158        8069 :                         received = first_parms.t2ffirst.out.count;
     159       16034 :                         if (received <= 0) break;
     160        8069 :                         if (ff_eos) break;
     161          26 :                         first = false;
     162             :                 } else {
     163           0 :                         NTSTATUS status;
     164             : 
     165          26 :                         next_parms.t2fnext.level = RAW_SEARCH_TRANS2;
     166          26 :                         next_parms.t2fnext.data_level = state.data_level;
     167          26 :                         next_parms.t2fnext.in.max_count = max_matches;
     168          26 :                         next_parms.t2fnext.in.last_name = state.last_name;
     169          26 :                         next_parms.t2fnext.in.handle = ff_dir_handle;
     170          26 :                         next_parms.t2fnext.in.resume_key = 0;
     171          26 :                         next_parms.t2fnext.in.flags = FLAG_TRANS2_FIND_CLOSE_IF_END;
     172             :                         
     173          26 :                         status = smb_raw_search_next(tree, 
     174             :                                                      state.mem_ctx,
     175             :                                                      &next_parms,
     176             :                                                      (void*)&state, 
     177             :                                                      smbcli_list_new_callback);
     178             :                         
     179          26 :                         if (!NT_STATUS_IS_OK(status)) {
     180           0 :                                 return -1;
     181             :                         }
     182          26 :                         ff_eos = next_parms.t2fnext.out.end_of_search;
     183          26 :                         received = next_parms.t2fnext.out.count;
     184          52 :                         if (received <= 0) break;
     185          26 :                         if (ff_eos) break;
     186             :                 }
     187             :         }
     188             : 
     189       47433 :         for (i=0;i<state.total_received;i++) {
     190       39364 :                 fn(&state.dirlist[i], Mask, caller_state);
     191             :         }
     192             : 
     193        8069 :         talloc_free(state.mem_ctx);
     194             : 
     195        8069 :         return state.total_received;
     196             : }
     197             : 
     198             : /****************************************************************************
     199             :  Interpret a short filename structure.
     200             :  The length of the structure is returned.
     201             : ****************************************************************************/
     202       24024 : static bool interpret_short_filename(enum smb_search_data_level level,
     203             :                                      const union smb_search_data *info,
     204             :                                      struct clilist_file_info *finfo)
     205             : {
     206           0 :         struct clilist_file_info finfo2;
     207             : 
     208       24024 :         if (!finfo) finfo = &finfo2;
     209       24024 :         ZERO_STRUCTP(finfo);
     210             : 
     211       24024 :         switch (level) {
     212       24024 :         case RAW_SEARCH_DATA_SEARCH:
     213       24024 :                 finfo->mtime = info->search.write_time;
     214       24024 :                 finfo->size = info->search.size;
     215       24024 :                 finfo->attrib = info->search.attrib;
     216       24024 :                 finfo->name = info->search.name;
     217       24024 :                 finfo->short_name = info->search.name;
     218       24024 :                 break;
     219             : 
     220           0 :         default:
     221           0 :                 DEBUG(0,("Unhandled level %d in interpret_short_filename\n", (int)level));
     222           0 :                 return false;
     223             :         }
     224             :         
     225       24024 :         return true;
     226             : }
     227             : 
     228             : /* callback function used for smb_search */
     229       24024 : static bool smbcli_list_old_callback(void *private_data, const union smb_search_data *file)
     230             : {
     231       24024 :         struct search_private *state = (struct search_private*) private_data;
     232           0 :         struct clilist_file_info *tdl;
     233             :         
     234             :         /* add file info to the dirlist pool */
     235       24024 :         tdl = talloc_realloc(state,
     236             :                              state->dirlist,
     237             :                              struct clilist_file_info,
     238             :                              state->dirlist_len + 1);
     239             : 
     240       24024 :         if (!tdl) {
     241           0 :                 return false;
     242             :         }
     243       24024 :         state->dirlist = tdl;
     244       24024 :         state->dirlist_len++;
     245             : 
     246       24024 :         interpret_short_filename(state->data_level, file, &state->dirlist[state->total_received]);
     247             : 
     248       24024 :         state->total_received++;
     249       24024 :         state->ff_searchcount++;
     250       24024 :         state->id = file->search.id; /* return resume info */
     251             :         
     252       24024 :         return true;
     253             : }
     254             : 
     255          18 : int smbcli_list_old(struct smbcli_tree *tree, const char *Mask, uint16_t attribute, 
     256             :                  void (*fn)(struct clilist_file_info *, const char *, void *), 
     257             :                  void *caller_state)
     258             : {
     259           0 :         union smb_search_first first_parms;
     260           0 :         union smb_search_next next_parms;
     261           0 :         struct search_private state;  /* for callbacks */
     262          18 :         const int num_asked = 500;
     263          18 :         int received = 0;
     264          18 :         bool first = true;
     265           0 :         char *mask;
     266           0 :         int i;
     267             : 
     268             :         /* initialize state for search */
     269          18 :         state.mem_ctx = talloc_init("smbcli_list_old");
     270          18 :         state.dirlist_len = 0;
     271          18 :         state.total_received = 0;
     272          18 :         state.data_level = RAW_SEARCH_DATA_SEARCH;
     273             : 
     274          18 :         state.dirlist = talloc_array(state.mem_ctx, struct clilist_file_info,
     275             :                                      0);
     276          18 :         mask = talloc_strdup(state.mem_ctx, Mask);
     277             :   
     278           0 :         while (1) {
     279          78 :                 state.ff_searchcount = 0;
     280          78 :                 if (first) {
     281           0 :                         NTSTATUS status;
     282             : 
     283          18 :                         first_parms.search_first.level = RAW_SEARCH_SEARCH;
     284          18 :                         first_parms.search_first.data_level = RAW_SEARCH_DATA_SEARCH;
     285          18 :                         first_parms.search_first.in.max_count = num_asked;
     286          18 :                         first_parms.search_first.in.search_attrib = attribute;
     287          18 :                         first_parms.search_first.in.pattern = mask;
     288             :                         
     289          18 :                         status = smb_raw_search_first(tree, state.mem_ctx, 
     290             :                                                       &first_parms,
     291             :                                                       (void*)&state, 
     292             :                                                       smbcli_list_old_callback);
     293             : 
     294          18 :                         if (!NT_STATUS_IS_OK(status)) {
     295           0 :                                 talloc_free(state.mem_ctx);
     296           0 :                                 return -1;
     297             :                         }
     298             :                 
     299          18 :                         received = first_parms.search_first.out.count;
     300          18 :                         if (received <= 0) break;
     301          18 :                         first = false;
     302             :                 } else {
     303           0 :                         NTSTATUS status;
     304             : 
     305          60 :                         next_parms.search_next.level = RAW_SEARCH_SEARCH;
     306          60 :                         next_parms.search_next.data_level = RAW_SEARCH_DATA_SEARCH;
     307          60 :                         next_parms.search_next.in.max_count = num_asked;
     308          60 :                         next_parms.search_next.in.search_attrib = attribute;
     309          60 :                         next_parms.search_next.in.id = state.id;
     310             :                         
     311          60 :                         status = smb_raw_search_next(tree, state.mem_ctx,
     312             :                                                      &next_parms,
     313             :                                                      (void*)&state, 
     314             :                                                      smbcli_list_old_callback);
     315             : 
     316          60 :                         if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
     317           0 :                                 break;
     318             :                         }
     319          60 :                         if (!NT_STATUS_IS_OK(status)) {
     320           0 :                                 talloc_free(state.mem_ctx);
     321           0 :                                 return -1;
     322             :                         }
     323          60 :                         received = next_parms.search_next.out.count;
     324          60 :                         if (received <= 0) break;
     325             :                 }
     326             :         }
     327             : 
     328       24042 :         for (i=0;i<state.total_received;i++) {
     329       24024 :                 fn(&state.dirlist[i], Mask, caller_state);
     330             :         }
     331             : 
     332          18 :         talloc_free(state.mem_ctx);
     333             : 
     334          18 :         return state.total_received;
     335             : }
     336             : 
     337             : /****************************************************************************
     338             :  Do a directory listing, calling fn on each file found.
     339             :  This auto-switches between old and new style.
     340             : ****************************************************************************/
     341             : 
     342        8310 : int smbcli_list(struct smbcli_tree *tree, const char *Mask,uint16_t attribute, 
     343             :                 void (*fn)(struct clilist_file_info *, const char *, void *), void *state)
     344             : {
     345        8310 :         if (tree->session->transport->negotiate.protocol <= PROTOCOL_LANMAN1)
     346           0 :                 return smbcli_list_old(tree, Mask, attribute, fn, state);
     347        8310 :         return smbcli_list_new(tree, Mask, attribute, RAW_SEARCH_DATA_GENERIC, fn, state);
     348             : }

Generated by: LCOV version 1.14