Coverage Report

Created: 2025-07-23 06:50

/src/mysql-server/mysys/my_lib.cc
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (c) 2000, 2025, Oracle and/or its affiliates.
2
3
   This program is free software; you can redistribute it and/or modify
4
   it under the terms of the GNU General Public License, version 2.0,
5
   as published by the Free Software Foundation.
6
7
   This program is designed to work with certain software (including
8
   but not limited to OpenSSL) that is licensed under separate terms,
9
   as designated in a particular file or component or in included license
10
   documentation.  The authors of MySQL hereby grant you an additional
11
   permission to link the program and your derivative works with the
12
   separately licensed software that they have either included with
13
   the program or referenced in the documentation.
14
15
   Without limiting anything contained in the foregoing, this file,
16
   which is part of C Driver for MySQL (Connector/C), is also subject to the
17
   Universal FOSS Exception, version 1.0, a copy of which can be found at
18
   http://oss.oracle.com/licenses/universal-foss-exception.
19
20
   This program is distributed in the hope that it will be useful,
21
   but WITHOUT ANY WARRANTY; without even the implied warranty of
22
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23
   GNU General Public License, version 2.0, for more details.
24
25
   You should have received a copy of the GNU General Public License
26
   along with this program; if not, write to the Free Software
27
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
28
*/
29
30
/**
31
  @file mysys/my_lib.cc
32
*/
33
34
/* TODO: check for overrun of memory for names. */
35
36
#include <sys/stat.h>
37
#include <algorithm>
38
#include <cerrno>
39
#include <cstring>
40
#include <memory>
41
#include <new>
42
43
#include "m_string.h"
44
#include "my_alloc.h"
45
#include "my_dbug.h"
46
#include "my_dir.h" /* Structs used by my_dir,includes sys/types */
47
#include "my_inttypes.h"
48
#include "my_io.h"
49
#include "my_pointer_arithmetic.h"
50
#include "my_sys.h"
51
#include "my_thread_local.h"
52
#include "mysql/service_mysql_alloc.h"
53
#include "mysys/mysys_priv.h"
54
#include "mysys_err.h"
55
#include "prealloced_array.h"
56
#include "template_utils.h"
57
#if !defined(_WIN32)
58
#include <dirent.h>
59
#endif
60
61
/*
62
  Allocate space for 100 FILEINFO structs up-front.
63
*/
64
typedef Prealloced_array<FILEINFO, 100> Entries_array;
65
66
0
#define NAMES_START_SIZE 32768
67
68
/* We need this because program don't know with malloc we used */
69
70
0
void my_dirend(MY_DIR *buffer) {
71
0
  DBUG_TRACE;
72
0
  if (buffer != nullptr) {
73
0
    auto *array = pointer_cast<Entries_array *>(pointer_cast<char *>(buffer) +
74
0
                                                ALIGN_SIZE(sizeof(MY_DIR)));
75
0
    array->~Entries_array();
76
0
    ::destroy_at(pointer_cast<MEM_ROOT *>(pointer_cast<char *>(buffer) +
77
0
                                          ALIGN_SIZE(sizeof(MY_DIR)) +
78
0
                                          ALIGN_SIZE(sizeof(Entries_array))));
79
0
    my_free(buffer);
80
0
  }
81
0
} /* my_dirend */
82
83
#if !defined(_WIN32)
84
85
static char *directory_file_name(char *dst, const char *src);
86
87
0
MY_DIR *my_dir(const char *path, myf MyFlags) {
88
0
  char *buffer;
89
0
  MY_DIR *result = nullptr;
90
0
  FILEINFO finfo;
91
0
  Entries_array *dir_entries_storage;
92
0
  MEM_ROOT *names_storage;
93
0
  DIR *dirp;
94
0
  char tmp_path[FN_REFLEN + 2], *tmp_file;
95
0
  void *rawmem = nullptr;
96
97
0
  DBUG_TRACE;
98
0
  DBUG_PRINT("my", ("path: '%s' MyFlags: %d", path, MyFlags));
99
100
0
  dirp = opendir(directory_file_name(tmp_path, path));
101
0
  if (dirp == nullptr ||
102
0
      !(buffer = static_cast<char *>(
103
0
            my_malloc(key_memory_MY_DIR,
104
0
                      ALIGN_SIZE(sizeof(MY_DIR)) +
105
0
                          ALIGN_SIZE(sizeof(Entries_array)) + sizeof(MEM_ROOT),
106
0
                      MyFlags))))
107
0
    goto error;
108
109
0
  rawmem = pointer_cast<Entries_array *>(buffer + ALIGN_SIZE(sizeof(MY_DIR)));
110
0
  dir_entries_storage = new (rawmem) Entries_array(key_memory_MY_DIR);
111
0
  names_storage = new (buffer + ALIGN_SIZE(sizeof(MY_DIR)) +
112
0
                       ALIGN_SIZE(sizeof(Entries_array)))
113
0
      MEM_ROOT(key_memory_MY_DIR, NAMES_START_SIZE);
114
0
  ;
115
  /* MY_DIR structure is allocated and completely initialized at this point */
116
0
  result = (MY_DIR *)buffer;
117
118
0
  tmp_file = strend(tmp_path);
119
120
0
  for (const dirent *dp = readdir(dirp); dp; dp = readdir(dirp)) {
121
0
    if (!(finfo.name = strdup_root(names_storage, dp->d_name))) goto error;
122
123
0
    if (MyFlags & MY_WANT_STAT) {
124
0
      if (!(finfo.mystat = (MY_STAT *)names_storage->Alloc(sizeof(MY_STAT))))
125
0
        goto error;
126
127
0
      memset(finfo.mystat, 0, sizeof(MY_STAT));
128
0
      (void)my_stpcpy(tmp_file, dp->d_name);
129
0
      (void)my_stat(tmp_path, finfo.mystat, MyFlags);
130
0
      if (!(finfo.mystat->st_mode & MY_S_IREAD)) continue;
131
0
    } else
132
0
      finfo.mystat = nullptr;
133
134
0
    if (dir_entries_storage->push_back(finfo)) goto error;
135
0
  }
136
137
0
  (void)closedir(dirp);
138
139
0
  result->dir_entry = dir_entries_storage->begin();
140
0
  result->number_off_files = dir_entries_storage->size();
141
142
0
  if (!(MyFlags & MY_DONT_SORT))
143
0
    std::sort(result->dir_entry, result->dir_entry + result->number_off_files,
144
0
              [](const fileinfo &a, const fileinfo &b) {
145
0
                return strcmp(a.name, b.name) < 0;
146
0
              });
147
0
  return result;
148
149
0
error:
150
0
  set_my_errno(errno);
151
0
  if (dirp) (void)closedir(dirp);
152
0
  my_dirend(result);
153
0
  if (MyFlags & (MY_FAE | MY_WME)) {
154
0
    MyOsError(my_errno(), EE_DIR, MYF(0), path);
155
0
  }
156
0
  return nullptr;
157
0
}
158
159
/*
160
 * Convert from directory name to filename.
161
 * On UNIX, it's simple: just make sure there is a terminating /
162
163
 * Returns pointer to dst;
164
 */
165
166
0
static char *directory_file_name(char *dst, const char *src) {
167
  /* Process as Unix format: just remove test the final slash. */
168
0
  char *end;
169
0
  assert(strlen(src) < (FN_REFLEN + 1));
170
171
0
  if (src[0] == 0) src = "."; /* Use empty as current */
172
0
  end = my_stpnmov(dst, src, FN_REFLEN + 1);
173
0
  if (end[-1] != FN_LIBCHAR) {
174
0
    end[0] = FN_LIBCHAR; /* Add last '/' */
175
0
    end[1] = '\0';
176
0
  }
177
0
  return dst;
178
0
}
179
180
#else
181
182
/*
183
*****************************************************************************
184
** Read long filename using windows rutines
185
*****************************************************************************
186
*/
187
188
MY_DIR *my_dir(const char *path, myf MyFlags) {
189
  char *buffer;
190
  MY_DIR *result = nullptr;
191
  FILEINFO finfo;
192
  Entries_array *dir_entries_storage;
193
  MEM_ROOT *names_storage;
194
  struct _finddata_t find;
195
  ushort mode;
196
  char tmp_path[FN_REFLEN], *tmp_file, attrib;
197
  __int64 handle = -1;
198
  void *rawmem = nullptr;
199
200
  DBUG_TRACE;
201
  DBUG_PRINT("my", ("path: '%s' MyFlags: %d", path, MyFlags));
202
203
  /* Put LIB-CHAR as last path-character if not there */
204
  tmp_file = tmp_path;
205
  if (!*path) *tmp_file++ = '.'; /* From current dir */
206
  tmp_file = my_stpnmov(tmp_file, path, FN_REFLEN - 5);
207
  if (tmp_file[-1] == FN_DEVCHAR) *tmp_file++ = '.'; /* From current dev-dir */
208
  if (tmp_file[-1] != FN_LIBCHAR) *tmp_file++ = FN_LIBCHAR;
209
  tmp_file[0] = '*'; /* Windows needs this !??? */
210
  tmp_file[1] = '.';
211
  tmp_file[2] = '*';
212
  tmp_file[3] = '\0';
213
214
  if (!(buffer = static_cast<char *>(
215
            my_malloc(key_memory_MY_DIR,
216
                      ALIGN_SIZE(sizeof(MY_DIR)) +
217
                          ALIGN_SIZE(sizeof(Entries_array)) + sizeof(MEM_ROOT),
218
                      MyFlags))))
219
    goto error;
220
221
  rawmem = buffer + ALIGN_SIZE(sizeof(MY_DIR));
222
  dir_entries_storage = new (rawmem) Entries_array(key_memory_MY_DIR);
223
  names_storage = new (buffer + ALIGN_SIZE(sizeof(MY_DIR)) +
224
                       ALIGN_SIZE(sizeof(Entries_array)))
225
      MEM_ROOT(key_memory_MY_DIR, NAMES_START_SIZE);
226
227
  /* MY_DIR structure is allocated and completely initialized at this point */
228
  result = (MY_DIR *)buffer;
229
230
  if ((handle = _findfirst(tmp_path, &find)) == -1L) {
231
    DBUG_PRINT("info", ("findfirst returned error, errno: %d", errno));
232
    if (errno != EINVAL) goto error;
233
    /*
234
      Could not read the directory, no read access.
235
      Probably because by "chmod -r".
236
      continue and return zero files in dir
237
    */
238
  } else {
239
    do {
240
      attrib = find.attrib;
241
      /*
242
        Do not show hidden and system files which Windows sometimes create.
243
        Note. Because Borland's findfirst() is called with the third
244
        argument = 0 hidden/system files are excluded from the search.
245
      */
246
      if (attrib & (_A_HIDDEN | _A_SYSTEM)) continue;
247
      if (!(finfo.name = strdup_root(names_storage, find.name))) goto error;
248
      if (MyFlags & MY_WANT_STAT) {
249
        if (!(finfo.mystat = (MY_STAT *)names_storage->Alloc(sizeof(MY_STAT))))
250
          goto error;
251
252
        memset(finfo.mystat, 0, sizeof(MY_STAT));
253
        finfo.mystat->st_size = find.size;
254
        mode = MY_S_IREAD;
255
        if (!(attrib & _A_RDONLY)) mode |= MY_S_IWRITE;
256
        if (attrib & _A_SUBDIR) mode |= MY_S_IFDIR;
257
        finfo.mystat->st_mode = mode;
258
        finfo.mystat->st_mtime = ((uint32)find.time_write);
259
      } else
260
        finfo.mystat = nullptr;
261
262
      if (dir_entries_storage->push_back(finfo)) goto error;
263
    } while (_findnext(handle, &find) == 0);
264
265
    _findclose(handle);
266
  }
267
268
  result->dir_entry = dir_entries_storage->begin();
269
  result->number_off_files = dir_entries_storage->size();
270
271
  if (!(MyFlags & MY_DONT_SORT))
272
    std::sort(result->dir_entry, result->dir_entry + result->number_off_files,
273
              [](const fileinfo &a, const fileinfo &b) {
274
                return strcmp(a.name, b.name) < 0;
275
              });
276
  DBUG_PRINT("exit", ("found %d files", result->number_off_files));
277
  return result;
278
error:
279
  set_my_errno(errno);
280
  if (handle != -1) _findclose(handle);
281
  my_dirend(result);
282
  if (MyFlags & (MY_FAE | MY_WME)) {
283
    MyOsError(my_errno(), EE_DIR, MYF(0), path);
284
  }
285
  return nullptr;
286
}
287
288
#endif /* _WIN32 */
289
290
/****************************************************************************
291
** File status
292
** Note that MY_STAT is assumed to be same as struct stat
293
****************************************************************************/
294
295
0
int my_fstat(File Filedes, MY_STAT *stat_area) {
296
0
  DBUG_TRACE;
297
0
  DBUG_PRINT("my", ("fd: %d", Filedes));
298
#ifdef _WIN32
299
  return my_win_fstat(Filedes, stat_area);
300
#else
301
0
  return fstat(Filedes, stat_area);
302
0
#endif
303
0
}
304
305
2
MY_STAT *my_stat(const char *path, MY_STAT *stat_area, myf MyFlags) {
306
2
  DBUG_TRACE;
307
2
  assert(stat_area != nullptr);
308
2
  DBUG_PRINT("my", ("path: '%s'  stat_area: %p  MyFlags: %d", path, stat_area,
309
2
                    MyFlags));
310
311
2
#ifndef _WIN32
312
2
  if (!stat(path, stat_area)) return stat_area;
313
#else
314
  if (!my_win_stat(path, stat_area)) return stat_area;
315
#endif
316
317
2
  DBUG_PRINT("error", ("Got errno: %d from stat", errno));
318
2
  set_my_errno(errno);
319
320
2
  if (MyFlags & (MY_FAE | MY_WME)) {
321
0
    MyOsError(my_errno(), EE_STAT, MYF(0), path);
322
0
  }
323
2
  return nullptr;
324
2
}