Coverage Report

Created: 2023-12-08 06:59

/src/aspell/common/file_util.cpp
Line
Count
Source (jump to first uncovered line)
1
// This file is part of The New Aspell
2
// Copyright (C) 2001 by Kevin Atkinson under the GNU LGPL license
3
// version 2.0 or 2.1.  You should have received a copy of the LGPL
4
// license along with this library if you did not you can find
5
// it at http://www.gnu.org/.
6
7
#include "settings.h"
8
9
//#include "iostream.hpp"
10
11
#include "config.hpp"
12
#include "file_util.hpp"
13
#include "fstream.hpp"
14
#include "errors.hpp"
15
#include "string_list.hpp"
16
17
#ifdef USE_FILE_LOCKS
18
#  include <fcntl.h>
19
#  include <unistd.h>
20
#  include <sys/types.h>
21
#endif
22
23
#include <stdio.h>
24
#include <sys/stat.h>
25
#include <dirent.h>
26
27
#ifdef WIN32
28
29
#  include <io.h>
30
#  define ACCESS _access
31
#  include <windows.h>
32
#  include <winbase.h>
33
34
#else
35
36
#  include <unistd.h>
37
8.16k
#  define ACCESS access
38
39
#endif
40
41
42
namespace acommon {
43
44
  // Return false if file is already an absolute path and does not need
45
  // a directory prepended.
46
13.8k
  bool need_dir(ParmString file) {
47
13.8k
    if (file[0] == '/' || (file[0] == '.' && file[1] == '/')
48
#ifdef WIN32
49
        || (asc_isalpha(file[0]) && file[1] == ':')
50
        || file[0] == '\\' || (file[0] == '.' && file[1] == '\\')
51
#endif
52
13.8k
      )
53
5.21k
      return false;
54
8.64k
    else
55
8.64k
      return true;
56
13.8k
  }
57
58
11.0k
  String add_possible_dir(ParmString dir, ParmString file) {
59
11.0k
    if (need_dir(file)) {
60
7.36k
      String path;
61
7.36k
      path += dir;
62
7.36k
      path += '/';
63
7.36k
      path += file;
64
7.36k
      return path;
65
7.36k
    } else {
66
3.67k
      return file;
67
3.67k
    }
68
11.0k
  }
69
70
  String figure_out_dir(ParmString dir, ParmString file)
71
2.82k
  {
72
2.82k
    String temp;
73
2.82k
    int s = file.size() - 1;
74
34.0k
    while (s != -1 && file[s] != '/') --s;
75
2.82k
    if (need_dir(file)) {
76
1.28k
      temp += dir;
77
1.28k
      temp += '/';
78
1.28k
    }
79
2.82k
    if (s != -1) {
80
1.68k
      temp.append(file, s);
81
1.68k
    }
82
2.82k
    return temp;
83
2.82k
  }
84
85
0
  time_t get_modification_time(FStream & f) {
86
0
    struct stat s;
87
0
    fstat(f.file_no(), &s);
88
0
    return s.st_mtime;
89
0
  }
90
91
1.42k
  PosibErr<void> open_file_readlock(FStream & in, ParmString file) {
92
1.42k
    RET_ON_ERR(in.open(file, "r"));
93
0
#ifdef USE_FILE_LOCKS
94
0
    int fd = in.file_no();
95
0
    struct flock fl;
96
0
    fl.l_type   = F_RDLCK;
97
0
    fl.l_whence = SEEK_SET;
98
0
    fl.l_start  = 0;
99
0
    fl.l_len    = 0;
100
0
    fcntl(fd, F_SETLKW, &fl); // ignore errors
101
0
#endif
102
0
    return no_err;
103
1.42k
  }
104
105
0
  PosibErr<bool> open_file_writelock(FStream & inout, ParmString file) {
106
0
    typedef PosibErr<bool> Ret;
107
#ifndef USE_FILE_LOCKS
108
    bool exists = file_exists(file);
109
#endif
110
0
    {
111
0
     Ret pe = inout.open(file, "r+");
112
0
     if (pe.get_err() != 0)
113
0
       pe = inout.open(file, "w+");
114
0
     if (pe.has_err())
115
0
       return pe;
116
0
    }
117
0
#ifdef USE_FILE_LOCKS
118
0
    int fd = inout.file_no();
119
0
    struct flock fl;
120
0
    fl.l_type   = F_WRLCK;
121
0
    fl.l_whence = SEEK_SET;
122
0
    fl.l_start  = 0;
123
0
    fl.l_len    = 0;
124
0
    fcntl(fd, F_SETLKW, &fl); // ignore errors
125
0
    struct stat s;
126
0
    fstat(fd, &s);
127
0
    return s.st_size != 0;
128
#else
129
    return exists;
130
#endif
131
0
  }
132
133
0
  void truncate_file(FStream & f, ParmString name) {
134
0
#ifdef USE_FILE_LOCKS
135
0
    f.restart();
136
0
    ftruncate(f.file_no(),0);
137
#else
138
    f.close();
139
    f.open(name, "w+");
140
#endif
141
0
  }
142
143
0
  bool remove_file(ParmString name) {
144
0
    return remove(name) == 0;
145
0
  }
146
147
8.16k
  bool file_exists(ParmString name) {
148
8.16k
    return ACCESS(name, F_OK) == 0;
149
8.16k
  }
150
151
  bool rename_file(ParmString orig_name, ParmString new_name)
152
0
  {
153
0
    remove(new_name);
154
0
    return rename(orig_name, new_name) == 0;
155
0
  }
156
 
157
0
  const char * get_file_name(const char * path) {
158
0
    const char * file_name;
159
0
    if (path != 0) {
160
0
      file_name = strrchr(path,'/');
161
0
      if (file_name == 0)
162
0
        file_name = path;
163
0
    } else {
164
0
      file_name = 0;
165
0
    }
166
0
    return file_name;
167
0
  }
168
169
  unsigned find_file(const Config * config, const char * option, String & filename)
170
3.42k
  {
171
3.42k
    StringList sl;
172
3.42k
    config->retrieve_list(option, &sl);
173
3.42k
    return find_file(sl, filename);
174
3.42k
  }
175
176
  unsigned find_file(const StringList & sl, String & filename)
177
3.42k
  {
178
3.42k
    StringListEnumeration els = sl.elements_obj();
179
3.42k
    const char * dir;
180
3.42k
    String path;
181
7.35k
    while ( (dir = els.next()) != 0 ) 
182
3.93k
    {
183
3.93k
      path = dir;
184
3.93k
      if (path.empty()) continue;
185
3.90k
      if (path.back() != '/') path += '/';
186
3.90k
      unsigned dir_len = path.size();
187
3.90k
      path += filename;
188
3.90k
      if (file_exists(path)) {
189
0
        filename.swap(path);
190
0
        return dir_len;
191
0
      }
192
3.90k
    }
193
3.42k
    return 0;
194
3.42k
  }
195
196
  PathBrowser::PathBrowser(const StringList & sl, const char * suf)
197
    : dir_handle(0)
198
1.10k
  {
199
1.10k
    els = sl.elements();
200
1.10k
    suffix = suf;
201
1.10k
  }
202
203
  PathBrowser::~PathBrowser() 
204
1.10k
  {
205
1.10k
    delete els;
206
1.10k
    if (dir_handle) closedir((DIR *)dir_handle);
207
1.10k
  }
208
209
  const char * PathBrowser::next()
210
6.46k
  {
211
6.46k
    if (dir_handle == 0) goto get_next_dir;
212
83.8k
  begin: {
213
83.8k
      struct dirent * entry = readdir((DIR *)dir_handle);
214
83.8k
      if (entry == 0) goto try_again;
215
83.1k
      const char * name = entry->d_name;
216
83.1k
      unsigned name_len = strlen(name);
217
83.1k
      if (suffix.size() != 0 && 
218
83.1k
          !(name_len > suffix.size() 
219
83.1k
            && memcmp(name + name_len - suffix.size(), suffix.str(), suffix.size()) == 0))
220
77.7k
        goto begin;
221
5.35k
      path = dir;
222
5.35k
      if (path.back() != '/') path += '/';
223
5.35k
      path += name;
224
5.35k
    }
225
0
    return path.str();
226
1.54k
  try_again:
227
1.54k
    if (dir_handle) closedir((DIR *)dir_handle);
228
1.54k
    dir_handle = 0;
229
2.65k
  get_next_dir:
230
2.65k
    dir = els->next();
231
2.65k
    if (!dir) return 0;
232
1.54k
    dir_handle = opendir(dir);
233
1.54k
    if (dir_handle == 0) goto try_again;
234
734
    goto begin;
235
1.54k
  }
236
}