Coverage Report

Created: 2025-06-13 07:09

/src/server/mysys/my_lib.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
2
   Copyright (c) 2008, 2022, MariaDB Corporation.
3
4
   This program is free software; you can redistribute it and/or modify
5
   it under the terms of the GNU General Public License as published by
6
   the Free Software Foundation; version 2 of the License.
7
8
   This program is distributed in the hope that it will be useful,
9
   but WITHOUT ANY WARRANTY; without even the implied warranty of
10
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
   GNU General Public License for more details.
12
13
   You should have received a copy of the GNU General Public License
14
   along with this program; if not, write to the Free Software
15
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1335  USA.
16
*/
17
18
/* TODO: check for overrun of memory for names. */
19
20
#include  "mysys_priv.h"
21
#include  <m_string.h>
22
#include  <my_dir.h>  /* Structs used by my_dir,includes sys/types */
23
#include  "mysys_err.h"
24
#if defined(HAVE_DIRENT_H)
25
# include <dirent.h>
26
#else
27
# define dirent direct
28
# if defined(HAVE_SYS_NDIR_H)
29
#  include <sys/ndir.h>
30
# endif
31
# if defined(HAVE_SYS_DIR_H)
32
#  include <sys/dir.h>
33
# endif
34
# if defined(HAVE_NDIR_H)
35
#  include <ndir.h>
36
# endif
37
# if defined(_WIN32)
38
# ifdef __BORLANDC__
39
# include <dir.h>
40
# endif
41
# endif
42
#endif
43
44
#if defined(HAVE_READDIR_R)
45
#define READDIR(A,B,C) ((errno=readdir_r(A,B,&C)) != 0 || !C)
46
#else
47
0
#define READDIR(A,B,C) (!(C=readdir(A)))
48
#endif
49
50
/*
51
  We are assuming that directory we are reading is either has less than 
52
  100 files and so can be read in one initial chunk or has more than 1000
53
  files and so big increment are suitable.
54
*/
55
#define ENTRIES_START_SIZE (8192/sizeof(FILEINFO))
56
#define ENTRIES_INCREMENT  (65536/sizeof(FILEINFO))
57
0
#define NAMES_START_SIZE   32768
58
59
60
static int  comp_names(const void *a, const void *b);
61
62
typedef struct {
63
  MY_DIR        dir;
64
  DYNAMIC_ARRAY array;
65
  MEM_ROOT      root;
66
} MY_DIR_HANDLE;
67
68
/* We need this because the caller doesn't know which malloc we've used */
69
70
void my_dirend(MY_DIR *dir)
71
0
{
72
0
  MY_DIR_HANDLE *dirh= (MY_DIR_HANDLE*) dir;
73
0
  DBUG_ENTER("my_dirend");
74
0
  if (dirh)
75
0
  {
76
0
    delete_dynamic(&dirh->array);
77
0
    free_root(&dirh->root, MYF(0));
78
0
    my_free(dirh);
79
0
  }
80
0
  DBUG_VOID_RETURN;
81
0
} /* my_dirend */
82
83
84
        /* Compare in sort of filenames */
85
86
static int comp_names(const void *a_, const void *b_)
87
0
{
88
0
  const struct fileinfo *a= a_;
89
0
  const struct fileinfo *b= b_;
90
0
  return (strcmp(a->name,b->name));
91
0
} /* comp_names */
92
93
94
#if !defined(_WIN32)
95
96
static char *directory_file_name (char * dst, const char *src)
97
0
{
98
  /* Process as Unix format: just remove test the final slash. */
99
0
  char *end;
100
0
  DBUG_ASSERT(strlen(src) < (FN_REFLEN + 1));
101
102
0
  if (src[0] == 0)
103
0
    src= (char*) ".";                           /* Use empty as current */
104
0
  end= strnmov(dst, src, FN_REFLEN + 1);
105
0
  if (end[-1] != FN_LIBCHAR)
106
0
  {
107
0
    *end++= FN_LIBCHAR;                          /* Add last '/' */
108
0
    *end='\0';
109
0
  }
110
0
  return end;
111
0
}
112
113
MY_DIR  *my_dir(const char *path, myf MyFlags)
114
0
{
115
0
  MY_DIR_HANDLE *dirh;
116
0
  FILEINFO      finfo;
117
0
  DIR   *dirp;
118
0
  struct dirent *dp;
119
0
  char    tmp_path[FN_REFLEN + 2], *tmp_file;
120
0
  char  dirent_tmp[sizeof(struct dirent)+_POSIX_PATH_MAX+1];
121
122
0
  DBUG_ENTER("my_dir");
123
0
  DBUG_PRINT("my",("path: '%s' MyFlags: %lu",path,MyFlags));
124
125
0
  tmp_file= directory_file_name(tmp_path, path);
126
127
0
  if (!(dirp= opendir(tmp_path)))
128
0
  {
129
0
    my_errno= errno;
130
0
    goto err_open;
131
0
  }
132
133
0
  if (!(dirh= my_malloc(key_memory_MY_DIR, sizeof(*dirh),
134
0
                        MYF(MyFlags | MY_ZEROFILL))))
135
0
    goto err_alloc;
136
  
137
0
  if (my_init_dynamic_array(key_memory_MY_DIR, &dirh->array, sizeof(FILEINFO),
138
0
                            ENTRIES_START_SIZE, ENTRIES_INCREMENT,
139
0
                            MYF(MyFlags)))
140
0
    goto error;
141
  
142
0
  init_alloc_root(key_memory_MY_DIR, &dirh->root, NAMES_START_SIZE,
143
0
                  NAMES_START_SIZE, MYF(MyFlags));
144
145
0
  dp= (struct dirent*) dirent_tmp;
146
  
147
0
  while (!(READDIR(dirp,(struct dirent*) dirent_tmp,dp)))
148
0
  {
149
0
    MY_STAT statbuf, *mystat= 0;
150
    
151
0
    if (dp->d_name[0] == '.' &&
152
0
        (dp->d_name[1] == '\0' ||
153
0
         (dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
154
0
      continue;                               /* . or .. */
155
156
0
    if (MyFlags & MY_WANT_STAT)
157
0
    {
158
0
      mystat= &statbuf;
159
0
      bzero(mystat, sizeof(*mystat));
160
0
      (void) strmov(tmp_file, dp->d_name);
161
0
      (void) my_stat(tmp_path, mystat, MyFlags);
162
0
      if (!(mystat->st_mode & MY_S_IREAD))
163
0
        continue;
164
0
    }
165
166
0
    if (!(finfo.name= strdup_root(&dirh->root, dp->d_name)))
167
0
      goto error;
168
    
169
0
    if (mystat &&
170
0
        !((mystat= memdup_root(&dirh->root, mystat, sizeof(*mystat)))))
171
0
      goto error;
172
173
0
    finfo.mystat= mystat;
174
175
0
    if (push_dynamic(&dirh->array, (uchar*)&finfo))
176
0
      goto error;
177
0
  }
178
179
0
  (void) closedir(dirp);
180
  
181
0
  if (MyFlags & MY_WANT_SORT)
182
0
    sort_dynamic(&dirh->array, (qsort_cmp) comp_names);
183
184
0
  dirh->dir.dir_entry= dynamic_element(&dirh->array, 0, FILEINFO *);
185
0
  dirh->dir.number_of_files= dirh->array.elements;
186
  
187
0
  DBUG_RETURN(&dirh->dir);
188
189
0
error:
190
0
  my_dirend(&dirh->dir);
191
0
err_alloc:
192
0
  (void) closedir(dirp);
193
0
err_open:
194
0
  if (MyFlags & (MY_FAE | MY_WME))
195
0
    my_error(EE_DIR, MYF(ME_BELL), path, my_errno);
196
0
  DBUG_RETURN(NULL);
197
0
} /* my_dir */
198
199
200
#else
201
202
/*
203
*****************************************************************************
204
** Read long filename using windows routines
205
*****************************************************************************
206
*/
207
208
MY_DIR  *my_dir(const char *path, myf MyFlags)
209
{
210
  MY_DIR_HANDLE *dirh= 0;
211
  FILEINFO      finfo;
212
  struct _finddata_t find;
213
  ushort  mode;
214
  char    tmp_path[FN_REFLEN], *tmp_file,attrib;
215
#ifdef _WIN64
216
  __int64       handle= -1;
217
#else
218
  long    handle= -1;
219
#endif
220
  DBUG_ENTER("my_dir");
221
  DBUG_PRINT("my",("path: '%s' MyFlags: %d",path,(int)MyFlags));
222
223
  /* Put LIB-CHAR as last path-character if not there */
224
  tmp_file=tmp_path;
225
  if (!*path)
226
    *tmp_file++ ='.';       /* From current dir */
227
  tmp_file= strnmov(tmp_file, path, FN_REFLEN-5);
228
  if (tmp_file[-1] == FN_DEVCHAR)
229
    *tmp_file++= '.';       /* From current dev-dir */
230
  if (tmp_file[-1] != FN_LIBCHAR)
231
    *tmp_file++ =FN_LIBCHAR;
232
  tmp_file[0]='*';        /* Windows needs this !??? */
233
  tmp_file[1]='.';
234
  tmp_file[2]='*';
235
  tmp_file[3]='\0';
236
237
  if (!(dirh= my_malloc(PSI_INSTRUMENT_ME, sizeof(*dirh), MyFlags | MY_ZEROFILL)))
238
    goto error;
239
  
240
  if (my_init_dynamic_array(PSI_INSTRUMENT_ME, &dirh->array, sizeof(FILEINFO),
241
                            ENTRIES_START_SIZE, ENTRIES_INCREMENT,
242
                            MYF(MyFlags)))
243
    goto error;
244
245
  init_alloc_root(PSI_INSTRUMENT_ME, &dirh->root, NAMES_START_SIZE, NAMES_START_SIZE,
246
                  MYF(MyFlags));
247
248
  if ((handle=_findfirst(tmp_path,&find)) == -1L)
249
  {
250
    DBUG_PRINT("info", ("findfirst returned error, errno: %d", errno));
251
    if  (errno != EINVAL)
252
      goto error;
253
    /*
254
      Could not read the directory, no read access.
255
      Probably because by "chmod -r".
256
      continue and return zero files in dir
257
    */
258
  }
259
  else
260
  {
261
    do
262
    {
263
      attrib= find.attrib;
264
      /*
265
        Do not show hidden and system files which Windows sometimes create.
266
        Note. Because Borland's findfirst() is called with the third
267
        argument = 0 hidden/system files are excluded from the search.
268
      */
269
      if (attrib & (_A_HIDDEN | _A_SYSTEM))
270
        continue;
271
272
      if (find.name[0] == '.' &&
273
          (find.name[1] == '\0' ||
274
           (find.name[1] == '.' && find.name[2] == '\0')))
275
        continue;                               /* . or .. */
276
277
      if (!(finfo.name= strdup_root(&dirh->root, find.name)))
278
        goto error;
279
      if (MyFlags & MY_WANT_STAT)
280
      {
281
        if (!(finfo.mystat= (MY_STAT*)alloc_root(&dirh->root, sizeof(MY_STAT))))
282
          goto error;
283
284
        bzero(finfo.mystat, sizeof(MY_STAT));
285
        finfo.mystat->st_size=find.size;
286
        mode= MY_S_IREAD;
287
        if (!(attrib & _A_RDONLY))
288
          mode|= MY_S_IWRITE;
289
        if (attrib & _A_SUBDIR)
290
          mode|= MY_S_IFDIR;
291
        finfo.mystat->st_mode= mode;
292
        finfo.mystat->st_mtime= ((uint32) find.time_write);
293
      }
294
      else
295
        finfo.mystat= NULL;
296
297
      if (push_dynamic(&dirh->array, (uchar*)&finfo))
298
        goto error;
299
    }
300
    while (_findnext(handle,&find) == 0);
301
    _findclose(handle);
302
  }
303
304
  if (MyFlags & MY_WANT_SORT)
305
    sort_dynamic(&dirh->array, (qsort_cmp) comp_names);
306
307
  dirh->dir.dir_entry= dynamic_element(&dirh->array, 0, FILEINFO *);
308
  dirh->dir.number_of_files= dirh->array.elements;
309
310
  DBUG_PRINT("exit", ("found %d files", dirh->dir.number_of_files));
311
  DBUG_RETURN(&dirh->dir);
312
error:
313
  my_errno=errno;
314
  if (handle != -1)
315
      _findclose(handle);
316
  my_dirend(&dirh->dir);
317
  if (MyFlags & (MY_FAE | MY_WME))
318
    my_error(EE_DIR,MYF(ME_BELL), path, errno);
319
  DBUG_RETURN(NULL);
320
} /* my_dir */
321
322
#endif /* _WIN32 */
323
324
/****************************************************************************
325
** File status
326
** Note that MY_STAT is assumed to be same as struct stat
327
****************************************************************************/ 
328
329
330
int my_fstat(File Filedes, MY_STAT *stat_area,
331
             myf MyFlags __attribute__((unused)))
332
0
{
333
0
  DBUG_ENTER("my_fstat");
334
0
  DBUG_PRINT("my",("fd: %d  MyFlags: %lu", Filedes, MyFlags));
335
#ifdef _WIN32
336
  DBUG_RETURN(my_win_fstat(Filedes, stat_area));
337
#elif defined HAVE_valgrind
338
  {
339
    int s= fstat(Filedes, stat_area);
340
    if (!s)
341
      MSAN_STAT_WORKAROUND(stat_area);
342
    DBUG_RETURN(s);
343
  }
344
#else
345
0
  DBUG_RETURN(fstat(Filedes, (struct stat *) stat_area));
346
0
#endif
347
0
}
348
349
350
MY_STAT *my_stat(const char *path, MY_STAT *stat_area, myf my_flags)
351
0
{
352
0
  int m_used;
353
0
  DBUG_ENTER("my_stat");
354
0
  DBUG_PRINT("my", ("path: '%s'  stat_area: %p  MyFlags: %lu", path,
355
0
                    stat_area, my_flags));
356
357
0
  if ((m_used= (stat_area == NULL)))
358
0
    if (!(stat_area= (MY_STAT *) my_malloc(key_memory_MY_STAT, sizeof(MY_STAT),
359
0
                                           my_flags)))
360
0
      goto error;
361
0
#ifndef _WIN32
362
0
  if (!stat((char *) path, (struct stat *) stat_area))
363
0
  {
364
0
    MSAN_STAT_WORKAROUND(stat_area);
365
0
    DBUG_RETURN(stat_area);
366
0
  }
367
#else
368
  if (!my_win_stat(path, stat_area))
369
    DBUG_RETURN(stat_area);
370
#endif
371
0
  DBUG_PRINT("error",("Got errno: %d from stat", errno));
372
0
  my_errno= errno;
373
0
  if (m_used)         /* Free if new area */
374
0
    my_free(stat_area);
375
376
0
error:
377
0
  if (my_flags & (MY_FAE+MY_WME))
378
0
  {
379
0
    my_error(EE_STAT, MYF(ME_BELL), path, my_errno);
380
0
    DBUG_RETURN((MY_STAT *) NULL);
381
0
  }
382
0
  DBUG_RETURN((MY_STAT *) NULL);
383
0
} /* my_stat */