Coverage Report

Created: 2024-06-18 07:03

/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(struct fileinfo *a,struct fileinfo *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(struct fileinfo *a, struct fileinfo *b)
87
0
{
88
0
  return (strcmp(a->name,b->name));
89
0
} /* comp_names */
90
91
92
#if !defined(_WIN32)
93
94
static char *directory_file_name (char * dst, const char *src)
95
0
{
96
  /* Process as Unix format: just remove test the final slash. */
97
0
  char *end;
98
0
  DBUG_ASSERT(strlen(src) < (FN_REFLEN + 1));
99
100
0
  if (src[0] == 0)
101
0
    src= (char*) ".";                           /* Use empty as current */
102
0
  end= strnmov(dst, src, FN_REFLEN + 1);
103
0
  if (end[-1] != FN_LIBCHAR)
104
0
  {
105
0
    *end++= FN_LIBCHAR;                          /* Add last '/' */
106
0
    *end='\0';
107
0
  }
108
0
  return end;
109
0
}
110
111
MY_DIR  *my_dir(const char *path, myf MyFlags)
112
0
{
113
0
  MY_DIR_HANDLE *dirh;
114
0
  FILEINFO      finfo;
115
0
  DIR   *dirp;
116
0
  struct dirent *dp;
117
0
  char    tmp_path[FN_REFLEN + 2], *tmp_file;
118
0
  char  dirent_tmp[sizeof(struct dirent)+_POSIX_PATH_MAX+1];
119
120
0
  DBUG_ENTER("my_dir");
121
0
  DBUG_PRINT("my",("path: '%s' MyFlags: %lu",path,MyFlags));
122
123
0
  tmp_file= directory_file_name(tmp_path, path);
124
125
0
  if (!(dirp= opendir(tmp_path)))
126
0
  {
127
0
    my_errno= errno;
128
0
    goto err_open;
129
0
  }
130
131
0
  if (!(dirh= my_malloc(key_memory_MY_DIR, sizeof(*dirh),
132
0
                        MYF(MyFlags | MY_ZEROFILL))))
133
0
    goto err_alloc;
134
  
135
0
  if (my_init_dynamic_array(key_memory_MY_DIR, &dirh->array, sizeof(FILEINFO),
136
0
                            ENTRIES_START_SIZE, ENTRIES_INCREMENT,
137
0
                            MYF(MyFlags)))
138
0
    goto error;
139
  
140
0
  init_alloc_root(key_memory_MY_DIR, &dirh->root, NAMES_START_SIZE,
141
0
                  NAMES_START_SIZE, MYF(MyFlags));
142
143
0
  dp= (struct dirent*) dirent_tmp;
144
  
145
0
  while (!(READDIR(dirp,(struct dirent*) dirent_tmp,dp)))
146
0
  {
147
0
    MY_STAT statbuf, *mystat= 0;
148
    
149
0
    if (dp->d_name[0] == '.' &&
150
0
        (dp->d_name[1] == '\0' ||
151
0
         (dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
152
0
      continue;                               /* . or .. */
153
154
0
    if (MyFlags & MY_WANT_STAT)
155
0
    {
156
0
      mystat= &statbuf;
157
0
      bzero(mystat, sizeof(*mystat));
158
0
      (void) strmov(tmp_file, dp->d_name);
159
0
      (void) my_stat(tmp_path, mystat, MyFlags);
160
0
      if (!(mystat->st_mode & MY_S_IREAD))
161
0
        continue;
162
0
    }
163
164
0
    if (!(finfo.name= strdup_root(&dirh->root, dp->d_name)))
165
0
      goto error;
166
    
167
0
    if (mystat &&
168
0
        !((mystat= memdup_root(&dirh->root, mystat, sizeof(*mystat)))))
169
0
      goto error;
170
171
0
    finfo.mystat= mystat;
172
173
0
    if (push_dynamic(&dirh->array, (uchar*)&finfo))
174
0
      goto error;
175
0
  }
176
177
0
  (void) closedir(dirp);
178
  
179
0
  if (MyFlags & MY_WANT_SORT)
180
0
    sort_dynamic(&dirh->array, (qsort_cmp) comp_names);
181
182
0
  dirh->dir.dir_entry= dynamic_element(&dirh->array, 0, FILEINFO *);
183
0
  dirh->dir.number_of_files= dirh->array.elements;
184
  
185
0
  DBUG_RETURN(&dirh->dir);
186
187
0
error:
188
0
  my_dirend(&dirh->dir);
189
0
err_alloc:
190
0
  (void) closedir(dirp);
191
0
err_open:
192
0
  if (MyFlags & (MY_FAE | MY_WME))
193
0
    my_error(EE_DIR, MYF(ME_BELL), path, my_errno);
194
0
  DBUG_RETURN(NULL);
195
0
} /* my_dir */
196
197
198
#else
199
200
/*
201
*****************************************************************************
202
** Read long filename using windows rutines
203
*****************************************************************************
204
*/
205
206
MY_DIR  *my_dir(const char *path, myf MyFlags)
207
{
208
  MY_DIR_HANDLE *dirh= 0;
209
  FILEINFO      finfo;
210
  struct _finddata_t find;
211
  ushort  mode;
212
  char    tmp_path[FN_REFLEN], *tmp_file,attrib;
213
#ifdef _WIN64
214
  __int64       handle= -1;
215
#else
216
  long    handle= -1;
217
#endif
218
  DBUG_ENTER("my_dir");
219
  DBUG_PRINT("my",("path: '%s' MyFlags: %d",path,(int)MyFlags));
220
221
  /* Put LIB-CHAR as last path-character if not there */
222
  tmp_file=tmp_path;
223
  if (!*path)
224
    *tmp_file++ ='.';       /* From current dir */
225
  tmp_file= strnmov(tmp_file, path, FN_REFLEN-5);
226
  if (tmp_file[-1] == FN_DEVCHAR)
227
    *tmp_file++= '.';       /* From current dev-dir */
228
  if (tmp_file[-1] != FN_LIBCHAR)
229
    *tmp_file++ =FN_LIBCHAR;
230
  tmp_file[0]='*';        /* Windows needs this !??? */
231
  tmp_file[1]='.';
232
  tmp_file[2]='*';
233
  tmp_file[3]='\0';
234
235
  if (!(dirh= my_malloc(PSI_INSTRUMENT_ME, sizeof(*dirh), MyFlags | MY_ZEROFILL)))
236
    goto error;
237
  
238
  if (my_init_dynamic_array(PSI_INSTRUMENT_ME, &dirh->array, sizeof(FILEINFO),
239
                            ENTRIES_START_SIZE, ENTRIES_INCREMENT,
240
                            MYF(MyFlags)))
241
    goto error;
242
243
  init_alloc_root(PSI_INSTRUMENT_ME, &dirh->root, NAMES_START_SIZE, NAMES_START_SIZE,
244
                  MYF(MyFlags));
245
246
  if ((handle=_findfirst(tmp_path,&find)) == -1L)
247
  {
248
    DBUG_PRINT("info", ("findfirst returned error, errno: %d", errno));
249
    if  (errno != EINVAL)
250
      goto error;
251
    /*
252
      Could not read the directory, no read access.
253
      Probably because by "chmod -r".
254
      continue and return zero files in dir
255
    */
256
  }
257
  else
258
  {
259
    do
260
    {
261
      attrib= find.attrib;
262
      /*
263
        Do not show hidden and system files which Windows sometimes create.
264
        Note. Because Borland's findfirst() is called with the third
265
        argument = 0 hidden/system files are excluded from the search.
266
      */
267
      if (attrib & (_A_HIDDEN | _A_SYSTEM))
268
        continue;
269
270
      if (find.name[0] == '.' &&
271
          (find.name[1] == '\0' ||
272
           (find.name[1] == '.' && find.name[2] == '\0')))
273
        continue;                               /* . or .. */
274
275
      if (!(finfo.name= strdup_root(&dirh->root, find.name)))
276
        goto error;
277
      if (MyFlags & MY_WANT_STAT)
278
      {
279
        if (!(finfo.mystat= (MY_STAT*)alloc_root(&dirh->root, sizeof(MY_STAT))))
280
          goto error;
281
282
        bzero(finfo.mystat, sizeof(MY_STAT));
283
        finfo.mystat->st_size=find.size;
284
        mode= MY_S_IREAD;
285
        if (!(attrib & _A_RDONLY))
286
          mode|= MY_S_IWRITE;
287
        if (attrib & _A_SUBDIR)
288
          mode|= MY_S_IFDIR;
289
        finfo.mystat->st_mode= mode;
290
        finfo.mystat->st_mtime= ((uint32) find.time_write);
291
      }
292
      else
293
        finfo.mystat= NULL;
294
295
      if (push_dynamic(&dirh->array, (uchar*)&finfo))
296
        goto error;
297
    }
298
    while (_findnext(handle,&find) == 0);
299
    _findclose(handle);
300
  }
301
302
  if (MyFlags & MY_WANT_SORT)
303
    sort_dynamic(&dirh->array, (qsort_cmp) comp_names);
304
305
  dirh->dir.dir_entry= dynamic_element(&dirh->array, 0, FILEINFO *);
306
  dirh->dir.number_of_files= dirh->array.elements;
307
308
  DBUG_PRINT("exit", ("found %d files", dirh->dir.number_of_files));
309
  DBUG_RETURN(&dirh->dir);
310
error:
311
  my_errno=errno;
312
  if (handle != -1)
313
      _findclose(handle);
314
  my_dirend(&dirh->dir);
315
  if (MyFlags & (MY_FAE | MY_WME))
316
    my_error(EE_DIR,MYF(ME_BELL), path, errno);
317
  DBUG_RETURN(NULL);
318
} /* my_dir */
319
320
#endif /* _WIN32 */
321
322
/****************************************************************************
323
** File status
324
** Note that MY_STAT is assumed to be same as struct stat
325
****************************************************************************/ 
326
327
328
int my_fstat(File Filedes, MY_STAT *stat_area,
329
             myf MyFlags __attribute__((unused)))
330
0
{
331
0
  DBUG_ENTER("my_fstat");
332
0
  DBUG_PRINT("my",("fd: %d  MyFlags: %lu", Filedes, MyFlags));
333
#ifdef _WIN32
334
  DBUG_RETURN(my_win_fstat(Filedes, stat_area));
335
#elif defined HAVE_valgrind
336
  {
337
    int s= fstat(Filedes, stat_area);
338
    if (!s)
339
      MSAN_STAT_WORKAROUND(stat_area);
340
    DBUG_RETURN(s);
341
  }
342
#else
343
0
  DBUG_RETURN(fstat(Filedes, (struct stat *) stat_area));
344
0
#endif
345
0
}
346
347
348
MY_STAT *my_stat(const char *path, MY_STAT *stat_area, myf my_flags)
349
0
{
350
0
  int m_used;
351
0
  DBUG_ENTER("my_stat");
352
0
  DBUG_PRINT("my", ("path: '%s'  stat_area: %p  MyFlags: %lu", path,
353
0
                    stat_area, my_flags));
354
355
0
  if ((m_used= (stat_area == NULL)))
356
0
    if (!(stat_area= (MY_STAT *) my_malloc(key_memory_MY_STAT, sizeof(MY_STAT),
357
0
                                           my_flags)))
358
0
      goto error;
359
0
#ifndef _WIN32
360
0
  if (!stat((char *) path, (struct stat *) stat_area))
361
0
  {
362
0
    MSAN_STAT_WORKAROUND(stat_area);
363
0
    DBUG_RETURN(stat_area);
364
0
  }
365
#else
366
  if (!my_win_stat(path, stat_area))
367
    DBUG_RETURN(stat_area);
368
#endif
369
0
  DBUG_PRINT("error",("Got errno: %d from stat", errno));
370
0
  my_errno= errno;
371
0
  if (m_used)         /* Free if new area */
372
0
    my_free(stat_area);
373
374
0
error:
375
0
  if (my_flags & (MY_FAE+MY_WME))
376
0
  {
377
0
    my_error(EE_STAT, MYF(ME_BELL), path, my_errno);
378
0
    DBUG_RETURN((MY_STAT *) NULL);
379
0
  }
380
0
  DBUG_RETURN((MY_STAT *) NULL);
381
0
} /* my_stat */