Switch to unified view

a b/src/readfile.cpp
1
/* Copyright (C) 2004 J.F.Dockes
2
 *   This program is free software; you can redistribute it and/or modify
3
 *   it under the terms of the GNU General Public License as published by
4
 *   the Free Software Foundation; either version 2 of the License, or
5
 *   (at your option) any later version.
6
 *
7
 *   This program is distributed in the hope that it will be useful,
8
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 *   GNU General Public License for more details.
11
 *
12
 *   You should have received a copy of the GNU General Public License
13
 *   along with this program; if not, write to the
14
 *   Free Software Foundation, Inc.,
15
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
16
 */
17
#ifndef TEST_READFILE
18
#ifdef BUILDING_RECOLL
19
#include "autoconfig.h"
20
#else
21
#include "config.h"
22
#endif
23
24
#include <errno.h>
25
#include <sys/types.h>
26
#ifdef _WIN32
27
#include "safefcntl.h"
28
#include "safesysstat.h"
29
#include "safeunistd.h"
30
#else
31
#define O_BINARY 0
32
#include <fcntl.h>
33
#include <sys/stat.h>
34
#include <unistd.h>
35
#endif
36
#include <string>
37
38
#include "readfile.h"
39
#include "smallut.h"
40
41
using std::string;
42
43
class FileToString : public FileScanDo {
44
public:
45
    FileToString(string& data) : m_data(data) {}
46
    string& m_data;
47
    bool init(size_t size, string *reason) {
48
        if (size > 0) {
49
            m_data.reserve(size);
50
        }
51
        return true;
52
    }
53
    bool data(const char *buf, int cnt, string *reason) {
54
        try {
55
            m_data.append(buf, cnt);
56
        } catch (...) {
57
            catstrerror(reason, "append", errno);
58
            return false;
59
        }
60
        return true;
61
    }
62
};
63
64
bool file_to_string(const string& fn, string& data, string *reason)
65
{
66
    return file_to_string(fn, data, 0, size_t(-1), reason);
67
}
68
bool file_to_string(const string& fn, string& data, off_t offs, size_t cnt,
69
                    string *reason)
70
{
71
    FileToString accum(data);
72
    return file_scan(fn, &accum, offs, cnt, reason);
73
}
74
75
bool file_scan(const string& fn, FileScanDo* doer, string *reason)
76
{
77
    return file_scan(fn, doer, 0, size_t(-1), reason);
78
}
79
80
const int RDBUFSZ = 8192;
81
// Note: the fstat() + reserve() (in init()) calls divide cpu usage almost by 2
82
// on both linux i586 and macosx (compared to just append())
83
// Also tried a version with mmap, but it's actually slower on the mac and not
84
// faster on linux.
85
bool file_scan(const string& fn, FileScanDo* doer, off_t startoffs,
86
               size_t cnttoread, string *reason)
87
{
88
    if (startoffs < 0) {
89
        *reason += " file_scan: negative startoffs not allowed";
90
        return false;
91
    }
92
93
    bool ret = false;
94
    bool noclosing = true;
95
    int fd = 0;
96
    struct stat st;
97
    // Initialize st_size: if fn.empty() , the fstat() call won't happen.
98
    st.st_size = 0;
99
100
    // If we have a file name, open it, else use stdin.
101
    if (!fn.empty()) {
102
        fd = open(fn.c_str(), O_RDONLY | O_BINARY);
103
        if (fd < 0 || fstat(fd, &st) < 0) {
104
            catstrerror(reason, "open/stat", errno);
105
            return false;
106
        }
107
        noclosing = false;
108
    }
109
110
#if defined O_NOATIME && O_NOATIME != 0
111
    if (fcntl(fd, F_SETFL, O_NOATIME) < 0) {
112
        // perror("fcntl");
113
    }
114
#endif
115
116
    if (cnttoread != (size_t) - 1 && cnttoread) {
117
        doer->init(cnttoread + 1, reason);
118
    } else if (st.st_size > 0) {
119
        doer->init(size_t(st.st_size + 1), reason);
120
    } else {
121
        doer->init(0, reason);
122
    }
123
124
    off_t curoffs = 0;
125
    if (startoffs > 0 && !fn.empty()) {
126
        if (lseek(fd, startoffs, SEEK_SET) != startoffs) {
127
            catstrerror(reason, "lseek", errno);
128
            return false;
129
        }
130
        curoffs = startoffs;
131
    }
132
133
    char buf[RDBUFSZ];
134
    size_t totread = 0;
135
    for (;;) {
136
        size_t toread = RDBUFSZ;
137
        if (startoffs > 0 && curoffs < startoffs) {
138
            toread = size_t(MIN(RDBUFSZ, startoffs - curoffs));
139
        }
140
141
        if (cnttoread != size_t(-1)) {
142
            toread = MIN(toread, cnttoread - totread);
143
        }
144
        ssize_t n = static_cast<ssize_t>(read(fd, buf, toread));
145
        if (n < 0) {
146
            catstrerror(reason, "read", errno);
147
            goto out;
148
        }
149
        if (n == 0) {
150
            break;
151
        }
152
153
        curoffs += n;
154
        if (curoffs - n < startoffs) {
155
            continue;
156
        }
157
158
        if (!doer->data(buf, n, reason)) {
159
            goto out;
160
        }
161
        totread += n;
162
        if (cnttoread > 0 && totread >= cnttoread) {
163
            break;
164
        }
165
    }
166
167
    ret = true;
168
out:
169
    if (fd >= 0 && !noclosing) {
170
        close(fd);
171
    }
172
    return ret;
173
}
174
175
#else // Test
176
#include "autoconfig.h"
177
178
#include <stdio.h>
179
#include <sys/types.h>
180
#include "safesysstat.h"
181
#include <stdlib.h>
182
183
#include <string>
184
#include <iostream>
185
using namespace std;
186
187
#include "readfile.h"
188
#include "fstreewalk.h"
189
190
using namespace std;
191
192
class myCB : public FsTreeWalkerCB {
193
public:
194
    FsTreeWalker::Status processone(const string& path,
195
                                    const struct stat *st,
196
                                    FsTreeWalker::CbFlag flg) {
197
        if (flg == FsTreeWalker::FtwDirEnter) {
198
            //cout << "[Entering " << path << "]" << endl;
199
        } else if (flg == FsTreeWalker::FtwDirReturn) {
200
            //cout << "[Returning to " << path << "]" << endl;
201
        } else if (flg == FsTreeWalker::FtwRegular) {
202
            //cout << path << endl;
203
            string s, reason;
204
            if (!file_to_string(path, s, &reason)) {
205
                cerr << "Failed: " << reason << " : " << path << endl;
206
            } else {
207
                //cout <<
208
                //"================================================" << endl;
209
                cout << path << endl;
210
                //      cout << s;
211
            }
212
            reason.clear();
213
        }
214
        return FsTreeWalker::FtwOk;
215
    }
216
};
217
218
static int     op_flags;
219
#define OPT_MOINS 0x1
220
#define OPT_c     0x2
221
#define OPT_o     0x4
222
223
static const char *thisprog;
224
static char usage [] =
225
    "trreadfile [-o offs] [-c cnt] topdirorfile\n\n"
226
    ;
227
static void
228
Usage(void)
229
{
230
    fprintf(stderr, "%s: usage:\n%s", thisprog, usage);
231
    exit(1);
232
}
233
234
int main(int argc, const char **argv)
235
{
236
    off_t offs = 0;
237
    size_t cnt = size_t(-1);
238
    thisprog = argv[0];
239
    argc--;
240
    argv++;
241
242
    while (argc > 0 && **argv == '-') {
243
        (*argv)++;
244
        if (!(**argv))
245
            /* Cas du "adb - core" */
246
        {
247
            Usage();
248
        }
249
        while (**argv)
250
            switch (*(*argv)++) {
251
            case 'c':
252
                op_flags |= OPT_c;
253
                if (argc < 2) {
254
                    Usage();
255
                }
256
                cnt = atoll(*(++argv));
257
                argc--;
258
                goto b1;
259
            case 'o':
260
                op_flags |= OPT_o;
261
                if (argc < 2) {
262
                    Usage();
263
                }
264
                offs = strtoull(*(++argv), 0, 0);
265
                argc--;
266
                goto b1;
267
            default:
268
                Usage();
269
                break;
270
            }
271
b1:
272
        argc--;
273
        argv++;
274
    }
275
276
    if (argc != 1) {
277
        Usage();
278
    }
279
    string top = *argv++;
280
    argc--;
281
    cerr << "filename " << top << " offs " << offs << " cnt " << cnt << endl;
282
283
    struct stat st;
284
    if (!top.empty() && stat(top.c_str(), &st) < 0) {
285
        perror("stat");
286
        exit(1);
287
    }
288
    if (!top.empty() && S_ISDIR(st.st_mode)) {
289
        FsTreeWalker walker;
290
        myCB cb;
291
        walker.walk(top, cb);
292
        if (walker.getErrCnt() > 0) {
293
            cout << walker.getReason();
294
        }
295
    } else {
296
        string s, reason;
297
        if (!file_to_string(top, s, offs, cnt, &reason)) {
298
            cerr << reason << endl;
299
            exit(1);
300
        } else {
301
            cout << s;
302
        }
303
    }
304
    exit(0);
305
}
306
#endif //TEST_READFILE