~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/pbxt/src/filesys_xt.cc

Merge Stewart.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (C) 2005 PrimeBase Technologies GmbH
2
 
 *
3
 
 * PrimeBase XT
4
 
 *
5
 
 * This program is free software; you can redistribute it and/or modify
6
 
 * it under the terms of the GNU General Public License as published by
7
 
 * the Free Software Foundation; either version 2 of the License, or
8
 
 * (at your option) any later version.
9
 
 *
10
 
 * This program is distributed in the hope that it will be useful,
11
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 
 * GNU General Public License for more details.
14
 
 *
15
 
 * You should have received a copy of the GNU General Public License
16
 
 * along with this program; if not, write to the Free Software
17
 
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
 
 *
19
 
 * 2005-01-12   Paul McCullagh
20
 
 *
21
 
 * H&G2JCtL
22
 
 */
23
 
 
24
 
#include "xt_config.h"
25
 
 
26
 
#ifndef XT_WIN
27
 
#include <unistd.h>
28
 
#include <dirent.h>
29
 
#include <sys/mman.h>
30
 
#endif
31
 
#include <stdio.h>
32
 
#include <sys/stat.h>
33
 
#include <fcntl.h>
34
 
#include <sys/types.h>
35
 
#include <ctype.h>
36
 
#include <string.h>
37
 
#include <errno.h>
38
 
 
39
 
#include "strutil_xt.h"
40
 
#include "pthread_xt.h"
41
 
#include "thread_xt.h"
42
 
#include "filesys_xt.h"
43
 
#include "memory_xt.h"
44
 
#include "cache_xt.h"
45
 
#include "sortedlist_xt.h"
46
 
#include "trace_xt.h"
47
 
 
48
 
#ifdef DEBUG
49
 
//#define DEBUG_TRACE_IO
50
 
//#define DEBUG_TRACE_AROUND
51
 
//#define DEBUG_TRACE_MAP_IO
52
 
//#define DEBUG_TRACE_FILES
53
 
//#define INJECT_WRITE_REMAP_ERROR
54
 
/* This is required to make testing on the Mac faster: */
55
 
/* It turns of full file sync. */
56
 
#define DEBUG_FAST_MAC
57
 
#endif
58
 
 
59
 
#if defined(DEBUG_TRACE_AROUND) || defined(DEBUG_TRACE_FILES)
60
 
//#define PRINTF                xt_ftracef
61
 
//#define PRINTF                xt_trace
62
 
#define PRINTF          printf
63
 
#endif
64
 
 
65
 
#ifdef INJECT_WRITE_REMAP_ERROR
66
 
#define INJECT_REMAP_FILE_SIZE                  1000000
67
 
#define INJECT_REMAP_FILE_TYPE                  "xtd"
68
 
#endif
69
 
 
70
 
#ifdef INJECT_FLUSH_FILE_ERROR
71
 
#define INJECT_FLUSH_FILE_SIZE                  10000000
72
 
#define INJECT_FLUSH_FILE_TYPE                  "dlog"
73
 
#endif
74
 
 
75
 
#ifdef INJECT_WRITE_FILE_ERROR
76
 
#define INJECT_WRITE_FILE_SIZE                  10000000
77
 
#define INJECT_WRITE_FILE_TYPE                  "dlog"
78
 
#define INJECT_ONCE_OFF
79
 
static xtBool   error_returned;
80
 
#endif
81
 
 
82
 
static off_t fs_seek_eof(XTThreadPtr self, XT_FD fd, XTFilePtr file);
83
 
static xtBool fs_map_file(XTFileMemMapPtr mm, XTFilePtr file, xtBool grow);
84
 
static xtBool fs_remap_file(XTOpenFilePtr map, off_t offset, size_t size, XTIOStatsPtr stat);
85
 
static xtBool fs_delete_heap_file(XTThreadPtr self, char *file_name);
86
 
static void fs_delete_all_heap_files(XTThreadPtr self);
87
 
static XTFileType fs_heap_file_exists(char *file_name, XTThreadPtr thread);
88
 
static xtBool fs_rename_heap_file(XTThreadPtr self, xtBool *all_ok, char *from_name, char *to_name);
89
 
 
90
 
/* ----------------------------------------------------------------------
91
 
 * Globals
92
 
 */
93
 
 
94
 
typedef struct FsGlobals {
95
 
        xt_mutex_type           *fsg_lock;                                              /* The xtPublic cache lock. */
96
 
        u_int                           fsg_current_id;
97
 
        XTSortedListPtr         fsg_open_files;
98
 
} FsGlobalsRec;
99
 
 
100
 
static FsGlobalsRec     fs_globals;
101
 
 
102
 
#ifdef XT_WIN
103
 
static int fs_get_win_error()
104
 
{
105
 
        return (int) GetLastError();
106
 
}
107
 
 
108
 
xtPublic void xt_get_win_message(char *buffer, size_t size, int err)
109
 
{
110
 
        FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err,
111
 
                MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
112
 
        buffer,
113
 
        size, NULL);
114
 
}
115
 
#endif
116
 
 
117
 
/* ----------------------------------------------------------------------
118
 
 * REWRITE UTLITIES
119
 
 */
120
 
 
121
 
static int rewrite_opt_comp(void *k, void *r)
122
 
{
123
 
        register off_t                          *key = (off_t *) k;
124
 
        register RewriteBlockPtr        rec = (RewriteBlockPtr) r;
125
 
 
126
 
        if (*key == rec->rb_offset)
127
 
                return 0;
128
 
        if (*key < rec->rb_offset)
129
 
                return -1;
130
 
        return 1;
131
 
}
132
 
 
133
 
static void *fs_rewrite_bsearch(void *key, register const void *base, size_t count, size_t size, size_t *idx, int (*compare)(void *key, void *rec))
134
 
{
135
 
        register size_t         i;
136
 
        register size_t         guess;
137
 
        register int            r;
138
 
 
139
 
        i = 0;
140
 
        while (i < count) {
141
 
                guess = (i + count - 1) >> 1;
142
 
                r = compare(key, ((char *) base) + guess * size);
143
 
                if (r == 0) {
144
 
                        *idx = guess;
145
 
                        return ((char *) base) + guess * size;
146
 
                }
147
 
                if (r < 0)
148
 
                        count = guess;
149
 
                else
150
 
                        i = guess + 1;
151
 
        }
152
 
 
153
 
        *idx = i;
154
 
        return NULL;
155
 
}
156
 
 
157
 
/* ----------------------------------------------------------------------
158
 
 * Open file list
159
 
 */
160
 
 
161
 
static XTFilePtr fs_new_file(char *file, XTFileType type)
162
 
{
163
 
        XTFilePtr file_ptr;
164
 
 
165
 
        if (!(file_ptr = (XTFilePtr) xt_calloc_ns(sizeof(XTFileRec))))
166
 
                return NULL;
167
 
 
168
 
        file_ptr->fil_type = type;
169
 
        if (!(file_ptr->fil_path = xt_dup_string(NULL, file))) {
170
 
                xt_free_ns(file_ptr);
171
 
                return NULL;
172
 
        }
173
 
 
174
 
        switch (file_ptr->fil_type) {
175
 
                case XT_FT_NONE:
176
 
                        break;
177
 
                case XT_FT_REWRITE_FLUSH:
178
 
                        if (!(file_ptr->x.fil_rewrite = (XTRewriteFlushPtr) xt_calloc_ns(sizeof(XTRewriteFlushRec)))) {
179
 
                                xt_free_ns(file_ptr->fil_path);
180
 
                                xt_free_ns(file_ptr);
181
 
                        }
182
 
                        xt_spinlock_init_with_autoname(NULL, &file_ptr->x.fil_rewrite->rf_lock);
183
 
                        RR_FLUSH_INIT_LOCK(NULL, &file_ptr->x.fil_rewrite->rf_write_lock);
184
 
                        xt_init_mutex_with_autoname(NULL, &file_ptr->x.fil_rewrite->rf_flush_lock);
185
 
                        file_ptr->x.fil_rewrite->rf_flush_offset_lo = 0xFFFFFFFF;
186
 
                        file_ptr->x.fil_rewrite->rf_flush_offset_hi = 0xFFFFFFFF;
187
 
                        break;
188
 
                case XT_FT_STANDARD:
189
 
                case XT_FT_MEM_MAP:
190
 
                case XT_FT_HEAP:
191
 
                        break;
192
 
        }
193
 
        
194
 
        file_ptr->fil_id = fs_globals.fsg_current_id++;
195
 
#ifdef DEBUG_TRACE_FILES
196
 
        PRINTF("%s: allocated file: (%d) %s\n", xt_get_self()->t_name, (int) file_ptr->fil_id, xt_last_2_names_of_path(file_ptr->fil_path));
197
 
#endif
198
 
        if (!fs_globals.fsg_current_id)
199
 
                fs_globals.fsg_current_id++;
200
 
        file_ptr->fil_filedes = XT_NULL_FD;
201
 
        file_ptr->fil_handle_count = 0;
202
 
 
203
 
        return file_ptr;
204
 
}
205
 
 
206
 
static void fs_close_fmap(XTThreadPtr self, XTFileMemMapPtr mm)
207
 
{
208
 
#ifdef XT_WIN
209
 
        if (mm->mm_start) {
210
 
                FlushViewOfFile(mm->mm_start, 0);
211
 
                UnmapViewOfFile(mm->mm_start);
212
 
                mm->mm_start = NULL;
213
 
        }
214
 
        if (mm->mm_mapdes != NULL) {
215
 
                CloseHandle(mm->mm_mapdes);
216
 
                mm->mm_mapdes = NULL;
217
 
        }
218
 
#else
219
 
        if (mm->mm_start) {
220
 
                msync( (char *)mm->mm_start, (size_t) mm->mm_length, MS_SYNC);
221
 
                munmap((caddr_t) mm->mm_start, (size_t) mm->mm_length);
222
 
                mm->mm_start = NULL;
223
 
        }
224
 
#endif
225
 
        FILE_MAP_FREE_LOCK(self, &mm->mm_lock);
226
 
        xt_free(self, mm);
227
 
}
228
 
 
229
 
static void fs_close_heap(XTThreadPtr self, XTFileHeapPtr fh)
230
 
{
231
 
        if (fh->fh_start) {
232
 
                xt_free(self, fh->fh_start);
233
 
                fh->fh_start = NULL;
234
 
                fh->fh_length = 0;
235
 
        }
236
 
        FILE_MAP_FREE_LOCK(self, &fh->fh_lock);
237
 
        xt_free(self, fh);
238
 
}
239
 
 
240
 
static void fs_free_file(XTThreadPtr self, void *XT_UNUSED(thunk), void *item)
241
 
{
242
 
        XTFilePtr       file_ptr = *((XTFilePtr *) item);
243
 
 
244
 
        if (file_ptr->fil_filedes != XT_NULL_FD) {
245
 
#ifdef DEBUG_TRACE_FILES
246
 
                PRINTF("%s: close file: (%d) %s\n", self->t_name, (int) file_ptr->fil_id, xt_last_2_names_of_path(file_ptr->fil_path));
247
 
#endif
248
 
#ifdef XT_WIN
249
 
                CloseHandle(file_ptr->fil_filedes);
250
 
#else
251
 
                close(file_ptr->fil_filedes);
252
 
#endif
253
 
                //PRINTF("close (FILE) %d %s\n", file_ptr->fil_filedes, file_ptr->fil_path);
254
 
                file_ptr->fil_filedes = XT_NULL_FD;
255
 
        }
256
 
 
257
 
        switch (file_ptr->fil_type) {
258
 
                case XT_FT_NONE:
259
 
                        break;
260
 
                case XT_FT_REWRITE_FLUSH:
261
 
                        if (file_ptr->x.fil_rewrite) {
262
 
                                xt_spinlock_free(NULL, &file_ptr->x.fil_rewrite->rf_lock);
263
 
                                RR_FLUSH_FREE_LOCK(NULL, &file_ptr->x.fil_rewrite->rf_write_lock);
264
 
                                xt_free_mutex(&file_ptr->x.fil_rewrite->rf_flush_lock);
265
 
                                xt_free(self, file_ptr->x.fil_rewrite);
266
 
                                file_ptr->x.fil_rewrite = NULL;
267
 
                        }
268
 
                        break;
269
 
                case XT_FT_STANDARD:
270
 
                        break;
271
 
                case XT_FT_MEM_MAP:
272
 
                        break;
273
 
                case XT_FT_HEAP:
274
 
                        if (file_ptr->x.fil_heap) {
275
 
                                fs_close_heap(self, file_ptr->x.fil_heap);
276
 
                                file_ptr->x.fil_heap = NULL;
277
 
                        }
278
 
                        break;
279
 
        }
280
 
 
281
 
#ifdef DEBUG_TRACE_FILES
282
 
        {
283
 
                XTThreadPtr thr = self;
284
 
 
285
 
                if (!thr)
286
 
                        thr = xt_get_self();
287
 
                PRINTF("%s: free file: (%d) %s\n", thr->t_name, (int) file_ptr->fil_id, 
288
 
                        file_ptr->fil_path ? xt_last_2_names_of_path(file_ptr->fil_path) : "?");
289
 
        }
290
 
#endif
291
 
 
292
 
        if (!file_ptr->fil_ref_count) {
293
 
                ASSERT_NS(!file_ptr->fil_handle_count);
294
 
                /* Flush any cache before this file is invalid: */
295
 
                if (file_ptr->fil_path) {
296
 
                        xt_free(self, file_ptr->fil_path);
297
 
                        file_ptr->fil_path = NULL;
298
 
                }
299
 
 
300
 
                xt_free(self, file_ptr);
301
 
        }
302
 
}
303
 
 
304
 
static int fs_comp_file(XTThreadPtr XT_UNUSED(self), register const void *XT_UNUSED(thunk), register const void *a, register const void *b)
305
 
{
306
 
        char            *file_name = (char *) a;
307
 
        XTFilePtr       file_ptr = *((XTFilePtr *) b);
308
 
 
309
 
        return strcmp(file_name, file_ptr->fil_path);
310
 
}
311
 
 
312
 
static int fs_comp_file_ci(XTThreadPtr XT_UNUSED(self), register const void *XT_UNUSED(thunk), register const void *a, register const void *b)
313
 
{
314
 
        char            *file_name = (char *) a;
315
 
        XTFilePtr       file_ptr = *((XTFilePtr *) b);
316
 
 
317
 
        return strcasecmp(file_name, file_ptr->fil_path);
318
 
}
319
 
 
320
 
/* ----------------------------------------------------------------------
321
 
 * init & exit
322
 
 */
323
 
 
324
 
xtPublic void xt_fs_init(XTThreadPtr self)
325
 
{
326
 
        fs_globals.fsg_open_files = xt_new_sortedlist(self,
327
 
                sizeof(XTFilePtr), 20, 20,
328
 
                pbxt_ignore_case ? fs_comp_file_ci : fs_comp_file,
329
 
                NULL, fs_free_file, TRUE, FALSE);
330
 
        fs_globals.fsg_lock = fs_globals.fsg_open_files->sl_lock;
331
 
        fs_globals.fsg_current_id = 1;
332
 
}
333
 
 
334
 
xtPublic void xt_fs_exit(XTThreadPtr self)
335
 
{
336
 
        if (fs_globals.fsg_open_files) {
337
 
                fs_delete_all_heap_files(self);
338
 
                xt_free_sortedlist(self, fs_globals.fsg_open_files);
339
 
                fs_globals.fsg_open_files = NULL;
340
 
        }
341
 
        fs_globals.fsg_lock = NULL;
342
 
        fs_globals.fsg_current_id = 0;
343
 
}
344
 
 
345
 
/* ----------------------------------------------------------------------
346
 
 * File operations
347
 
 */
348
 
 
349
 
static void fs_set_stats(XTThreadPtr self, char *path)
350
 
{
351
 
        char            super_path[PATH_MAX];
352
 
        struct stat     stats;
353
 
        char            *ptr;
354
 
 
355
 
        ptr = xt_last_name_of_path(path);
356
 
        if (ptr == path) 
357
 
                strcpy(super_path, ".");
358
 
        else {
359
 
                xt_strcpy(PATH_MAX, super_path, path);
360
 
 
361
 
                if ((ptr = xt_last_name_of_path(super_path)))
362
 
                        *ptr = 0;
363
 
        }
364
 
        if (stat(super_path, &stats) == -1)
365
 
                xt_throw_ferrno(XT_CONTEXT, errno, super_path);
366
 
 
367
 
        if (chmod(path, stats.st_mode) == -1)
368
 
                xt_throw_ferrno(XT_CONTEXT, errno, path);
369
 
 
370
 
        /*chown(path, stats.st_uid, stats.st_gid);*/
371
 
}
372
 
 
373
 
xtPublic char *xt_file_path(XTOpenFilePtr of)
374
 
{
375
 
        return of->fr_file->fil_path;
376
 
}
377
 
 
378
 
static xtBool fs_exists(char *path, XTThreadPtr thread)
379
 
{
380
 
        int err;
381
 
 
382
 
        err = access(path, F_OK);
383
 
        if (err == -1) {
384
 
                if (fs_heap_file_exists(path, thread) == XT_FT_HEAP)
385
 
                        return TRUE;
386
 
                return FALSE;
387
 
        }
388
 
        return TRUE;
389
 
}
390
 
 
391
 
xtBool xt_fs_exists(char *path)
392
 
{
393
 
        /*
394
 
         * Do no use xt_get_self() because this function call is required before
395
 
         * the self has been setup!
396
 
         *
397
 
         * #0  0x00002aaaab566d31 in xt_ha_thd_to_self (thd=0x11f5d7d0) at ha_pbxt.cc:669
398
 
         * #1  0x00002aaaab58068a in myxt_get_self () at myxt_xt.cc:3211
399
 
         * #2  0x00002aaaab5ab24b in xt_get_self () at thread_xt.cc:621
400
 
         * #3  0x00002aaaab562d71 in fs_heap_file_exists (file_name=0x40ae88d0 "/usr/local/mysql/var/pbxt/no-debug") at filesys_xt.cc:665
401
 
         * #4  0x00002aaaab562f52 in xt_fs_exists (path=0x40ae88d0 "/usr/local/mysql/var/pbxt/no-debug") at filesys_xt.cc:384
402
 
         * #5  0x00002aaaab54d703 in xt_lock_installation (self=0x11fbb490, installation_path=0xd3c620 "/usr/local/mysql/var/") at database_xt.cc:107
403
 
         * #6  0x00002aaaab5664c3 in pbxt_call_init (self=0x11fbb490) at ha_pbxt.cc:1013
404
 
         * #7  0x00002aaaab566876 in pbxt_init (p=0x11f4b7c0) at ha_pbxt.cc:1223
405
 
         * #8  0x00000000006a7f41 in ha_initialize_handlerton ()
406
 
         * #9  0x000000000072bdea in plugin_initialize ()
407
 
         * #10 0x000000000072eac6 in mysql_install_plugin ()
408
 
         * #11 0x00000000005c39a7 in mysql_execute_command ()
409
 
         * #12 0x00000000005cafd1 in mysql_parse ()
410
 
         * #13 0x00000000005cb3d3 in dispatch_command ()
411
 
         * #14 0x00000000005cc5d4 in do_command ()
412
 
         * #15 0x00000000005bce77 in handle_one_connection ()
413
 
         * #16 0x000000367a806367 in start_thread () from /lib64/libpthread.so.0
414
 
         * #17 0x0000003679cd2f7d in clone () from /lib64/libc.so.6\
415
 
         */
416
 
        return fs_exists(path, NULL);
417
 
}
418
 
 
419
 
/*
420
 
 * No error is generated if the file dose not exist.
421
 
 */
422
 
xtPublic xtBool xt_fs_delete(XTThreadPtr self, char *name)
423
 
{
424
 
#ifdef DEBUG_TRACE_FILES
425
 
        PRINTF("%s: DELETE FILE: %s\n", xt_get_self()->t_name, xt_last_2_names_of_path(name));
426
 
#endif
427
 
        /* {HEAP-FILE}
428
 
         * This reference count is +1 for the file exists!
429
 
         * It will be decremented on file delete!
430
 
         */
431
 
        if (fs_delete_heap_file(self, name))
432
 
                return OK;
433
 
 
434
 
#ifdef XT_WIN
435
 
        //PRINTF("delete %s\n", name);
436
 
        if (!DeleteFile(name)) {
437
 
                int err = fs_get_win_error();
438
 
 
439
 
                if (!XT_FILE_NOT_FOUND(err)) {
440
 
                        xt_throw_ferrno(XT_CONTEXT, err, name);
441
 
                        return FAILED;
442
 
                }
443
 
        }
444
 
#else
445
 
        if (unlink(name) == -1) {
446
 
                int err = errno;
447
 
 
448
 
                if (err != ENOENT) {
449
 
                        xt_throw_ferrno(XT_CONTEXT, err, name);
450
 
                        return FAILED;
451
 
                }
452
 
        }
453
 
#endif
454
 
        return OK;
455
 
}
456
 
 
457
 
xtPublic xtBool xt_fs_file_not_found(int err)
458
 
{
459
 
#ifdef XT_WIN
460
 
        return XT_FILE_NOT_FOUND(err);
461
 
#else
462
 
        return err == ENOENT;
463
 
#endif
464
 
}
465
 
 
466
 
xtPublic void xt_fs_move(struct XTThread *self, char *from_path, char *to_path)
467
 
{
468
 
        int             err;
469
 
        xtBool  ok;
470
 
 
471
 
#ifdef DEBUG_TRACE_FILES
472
 
        PRINTF("%s: MOVE FILE: %s --> %s\n", xt_get_self()->t_name, xt_last_2_names_of_path(from_path), xt_last_2_names_of_path(to_path));
473
 
#endif
474
 
 
475
 
        if (fs_rename_heap_file(self, &ok, from_path, to_path))
476
 
                return;
477
 
 
478
 
#ifdef XT_WIN
479
 
        if (!MoveFile(from_path, to_path))
480
 
                xt_throw_ferrno(XT_CONTEXT, fs_get_win_error(), from_path);
481
 
#else
482
 
        if (link(from_path, to_path) == -1) {
483
 
                err = errno;
484
 
                xt_throw_ferrno(XT_CONTEXT, err, from_path);
485
 
        }
486
 
 
487
 
        if (unlink(from_path) == -1) {
488
 
                err = errno;
489
 
                unlink(to_path);
490
 
                xt_throw_ferrno(XT_CONTEXT, err, from_path);
491
 
        }
492
 
#endif
493
 
}
494
 
 
495
 
xtPublic xtBool xt_fs_rename(XTThreadPtr self, char *from_path, char *to_path)
496
 
{
497
 
        int             err;
498
 
        xtBool  ok;
499
 
 
500
 
#ifdef DEBUG_TRACE_FILES
501
 
        PRINTF("%s: RENAME FILE: %s --> %s\n", xt_get_self()->t_name, xt_last_2_names_of_path(from_path), xt_last_2_names_of_path(to_path));
502
 
#endif
503
 
 
504
 
        if (fs_rename_heap_file(self, &ok, from_path, to_path))
505
 
                return ok;
506
 
 
507
 
        if (rename(from_path, to_path) == -1) {
508
 
                err = errno;
509
 
                xt_throw_ferrno(XT_CONTEXT, err, from_path);
510
 
                return FAILED;
511
 
        }
512
 
        return OK;
513
 
}
514
 
 
515
 
xtPublic xtBool xt_fs_stat(XTThreadPtr self, char *path, off_t *size, struct timespec *mod_time)
516
 
{
517
 
#ifdef XT_WIN
518
 
        HANDLE                                          fh;
519
 
        BY_HANDLE_FILE_INFORMATION      info;
520
 
        SECURITY_ATTRIBUTES                     sa = { sizeof(SECURITY_ATTRIBUTES), 0, 0 };
521
 
 
522
 
        fh = CreateFile(
523
 
                path,
524
 
                GENERIC_READ,
525
 
                FILE_SHARE_READ,
526
 
                &sa,
527
 
                OPEN_EXISTING,
528
 
                FILE_ATTRIBUTE_NORMAL,
529
 
                NULL);
530
 
        if (fh == INVALID_HANDLE_VALUE) {
531
 
                xt_throw_ferrno(XT_CONTEXT, fs_get_win_error(), path);
532
 
                return FAILED;
533
 
        }
534
 
 
535
 
        if (!GetFileInformationByHandle(fh, &info)) {
536
 
                CloseHandle(fh);
537
 
                xt_throw_ferrno(XT_CONTEXT, fs_get_win_error(), path);
538
 
                return FAILED;
539
 
        }
540
 
 
541
 
        CloseHandle(fh);
542
 
        if (size)
543
 
                *size = (off_t) info.nFileSizeLow | (((off_t) info.nFileSizeHigh) << 32);
544
 
        if (mod_time)
545
 
                mod_time->tv.ft = info.ftLastWriteTime;
546
 
#else
547
 
        struct stat sb;
548
 
 
549
 
        if (stat(path, &sb) == -1) {
550
 
                xt_throw_ferrno(XT_CONTEXT, errno, path);
551
 
                return FAILED;
552
 
        }
553
 
        if (size)
554
 
                *size = sb.st_size;
555
 
        if (mod_time) {
556
 
                mod_time->tv_sec = sb.st_mtime;
557
 
#ifdef XT_MAC
558
 
                /* This is the Mac OS X version: */
559
 
                mod_time->tv_nsec = sb.st_mtimespec.tv_nsec;
560
 
#else
561
 
#ifdef __USE_MISC
562
 
                /* This is the Linux version: */
563
 
                mod_time->tv_nsec = sb.st_mtim.tv_nsec;
564
 
#else
565
 
                /* Not supported? */
566
 
                mod_time->tv_nsec = 0;
567
 
#endif
568
 
#endif
569
 
        }
570
 
#endif
571
 
        return OK;
572
 
}
573
 
 
574
 
void xt_fs_mkdir(XTThreadPtr self, char *name)
575
 
{
576
 
        char path[PATH_MAX];
577
 
 
578
 
        xt_strcpy(PATH_MAX, path, name);
579
 
        xt_remove_dir_char(path);
580
 
 
581
 
#ifdef XT_WIN
582
 
        {
583
 
                SECURITY_ATTRIBUTES     sa = { sizeof(SECURITY_ATTRIBUTES), 0, 0 };
584
 
 
585
 
                if (!CreateDirectory(path, &sa))
586
 
                        xt_throw_ferrno(XT_CONTEXT, fs_get_win_error(), path);
587
 
        }
588
 
#else
589
 
        if (mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO) == -1)
590
 
                xt_throw_ferrno(XT_CONTEXT, errno, path);
591
 
 
592
 
        try_(a) {
593
 
                fs_set_stats(self, path);
594
 
        }
595
 
        catch_(a) {
596
 
                xt_fs_rmdir(NULL, name);
597
 
                throw_();
598
 
        }
599
 
        cont_(a);
600
 
#endif
601
 
}
602
 
 
603
 
void xt_fs_mkpath(XTThreadPtr self, char *path)
604
 
{
605
 
        char *ptr;
606
 
 
607
 
        if (fs_exists(path, self))
608
 
                return;
609
 
 
610
 
        if (!(ptr = (char *) xt_last_directory_of_path((c_char *) path)))
611
 
                return;
612
 
        if (ptr == path)
613
 
                return;
614
 
        ptr--;
615
 
        if (XT_IS_DIR_CHAR(*ptr)) {
616
 
                *ptr = 0;
617
 
                xt_fs_mkpath(self, path);
618
 
                *ptr = XT_DIR_CHAR;
619
 
                xt_fs_mkdir(self, path);
620
 
        }
621
 
}
622
 
 
623
 
xtBool xt_fs_rmdir(XTThreadPtr self, char *name)
624
 
{
625
 
        char path[PATH_MAX];
626
 
 
627
 
        xt_strcpy(PATH_MAX, path, name);
628
 
        xt_remove_dir_char(path);
629
 
 
630
 
#ifdef XT_WIN
631
 
        if (!RemoveDirectory(path)) {
632
 
                int err = fs_get_win_error();
633
 
 
634
 
                if (!XT_FILE_NOT_FOUND(err)) {
635
 
                        xt_throw_ferrno(XT_CONTEXT, err, path);
636
 
                        return FAILED;
637
 
                }
638
 
        }
639
 
#else
640
 
        if (rmdir(path) == -1) {
641
 
                int err = errno;
642
 
 
643
 
                if (err != ENOENT) {
644
 
                        xt_throw_ferrno(XT_CONTEXT, err, path);
645
 
                        return FAILED;
646
 
                }
647
 
        }
648
 
#endif
649
 
        return OK;
650
 
}
651
 
 
652
 
/* ----------------------------------------------------------------------
653
 
 * Open & Close operations
654
 
 */
655
 
 
656
 
xtPublic XTFilePtr xt_fs_get_file(XTThreadPtr self, char *file_name, XTFileType type)
657
 
{
658
 
        XTFilePtr       file_ptr, *file_pptr;
659
 
 
660
 
        xt_sl_lock(self, fs_globals.fsg_open_files);
661
 
        pushr_(xt_sl_unlock, fs_globals.fsg_open_files);
662
 
 
663
 
        if ((file_pptr = (XTFilePtr *) xt_sl_find(self, fs_globals.fsg_open_files, file_name)))
664
 
                file_ptr = *file_pptr;
665
 
        else {
666
 
                if (!(file_ptr = fs_new_file(file_name, type)))
667
 
                        xt_throw(self);
668
 
                xt_sl_insert(self, fs_globals.fsg_open_files, file_name, &file_ptr);
669
 
        }
670
 
        file_ptr->fil_ref_count++;
671
 
        freer_(); // xt_sl_unlock(fs_globals.fsg_open_files)
672
 
        return file_ptr;
673
 
}
674
 
 
675
 
xtPublic void xt_fs_release_file(XTThreadPtr self, XTFilePtr file_ptr)
676
 
{
677
 
        xt_sl_lock(self, fs_globals.fsg_open_files);
678
 
        pushr_(xt_sl_unlock, fs_globals.fsg_open_files);
679
 
 
680
 
        file_ptr->fil_ref_count--;
681
 
        if (!file_ptr->fil_ref_count) {
682
 
                xt_sl_delete(self, fs_globals.fsg_open_files, file_ptr->fil_path);
683
 
        }
684
 
 
685
 
        freer_(); // xt_ht_unlock(fs_globals.fsg_open_files)
686
 
}
687
 
 
688
 
static XTFileType fs_heap_file_exists(char *file_name, XTThreadPtr thread)
689
 
{
690
 
        XTFilePtr       *file_pptr;
691
 
        XTFileType      type;
692
 
 
693
 
        xt_sl_lock_ns(fs_globals.fsg_open_files, thread);
694
 
 
695
 
        if ((file_pptr = (XTFilePtr *) xt_sl_find(NULL, fs_globals.fsg_open_files, file_name)))
696
 
                type = (*file_pptr)->fil_type;
697
 
        else
698
 
                type = XT_FT_NONE;
699
 
 
700
 
        xt_sl_unlock_ns(fs_globals.fsg_open_files);
701
 
        return type;
702
 
}
703
 
 
704
 
/*
705
 
 * Return TRUE if the heap file exists!
706
 
 */
707
 
static xtBool fs_rename_heap_file(struct XTThread *self, xtBool *all_ok, char *from_name, char *to_name)
708
 
{
709
 
        XTFilePtr       from_ptr, to_ptr, *file_pptr;
710
 
 
711
 
        xt_sl_lock_ns(fs_globals.fsg_open_files, self);
712
 
 
713
 
        if ((file_pptr = (XTFilePtr *) xt_sl_find(NULL, fs_globals.fsg_open_files, from_name))) {
714
 
                from_ptr = *file_pptr;
715
 
                if (from_ptr->fil_type == XT_FT_HEAP) {
716
 
                        *all_ok = FALSE;
717
 
 
718
 
                        if (from_ptr->fil_ref_count > 1) {
719
 
                                xt_register_ferrno(XT_REG_CONTEXT, XT_FILE_IN_USE_ERR, from_name);
720
 
                                goto file_found;
721
 
                        }
722
 
 
723
 
                        /* Add the new one: */
724
 
                        if (!(to_ptr = fs_new_file(to_name, XT_FT_HEAP)))
725
 
                                goto file_found;
726
 
 
727
 
                        if (!xt_sl_insert(NULL, fs_globals.fsg_open_files, to_name, &to_ptr))
728
 
                                goto file_found;
729
 
 
730
 
                        /* Copy the data from to to: */
731
 
                        to_ptr->x.fil_heap = from_ptr->x.fil_heap;
732
 
                        from_ptr->x.fil_heap = NULL;
733
 
                        to_ptr->fil_ref_count++;
734
 
 
735
 
                        /* Remove the previous file: */
736
 
                        from_ptr->fil_ref_count--;
737
 
                        if (!from_ptr->fil_ref_count)
738
 
                                xt_sl_delete(NULL, fs_globals.fsg_open_files, from_name);
739
 
 
740
 
                        xt_sl_unlock_ns(fs_globals.fsg_open_files);
741
 
                        *all_ok = TRUE;
742
 
                        return TRUE;
743
 
                }
744
 
        }
745
 
 
746
 
        xt_sl_unlock_ns(fs_globals.fsg_open_files);
747
 
        return FALSE;
748
 
 
749
 
        file_found:
750
 
        xt_sl_unlock_ns(fs_globals.fsg_open_files);
751
 
        xt_throw(self);
752
 
        return TRUE;
753
 
}
754
 
 
755
 
/*
756
 
 * Return TRUE of this is a "heap" file.
757
 
 */
758
 
static xtBool fs_delete_heap_file(XTThreadPtr self, char *file_name)
759
 
{
760
 
        XTFilePtr       file_ptr, *file_pptr;
761
 
 
762
 
        xt_sl_lock_ns(fs_globals.fsg_open_files, self);
763
 
 
764
 
        if ((file_pptr = (XTFilePtr *) xt_sl_find(NULL, fs_globals.fsg_open_files, file_name))) {
765
 
                file_ptr = *file_pptr;
766
 
                if (file_ptr->fil_type == XT_FT_HEAP) {
767
 
                        file_ptr->fil_ref_count--;
768
 
                        if (!file_ptr->fil_ref_count)
769
 
                                xt_sl_delete(NULL, fs_globals.fsg_open_files, file_ptr->fil_path);
770
 
                        xt_sl_unlock_ns(fs_globals.fsg_open_files);
771
 
                        return TRUE;
772
 
                }
773
 
        }
774
 
 
775
 
        xt_sl_unlock_ns(fs_globals.fsg_open_files);
776
 
        return FALSE;
777
 
}
778
 
 
779
 
static void fs_delete_all_heap_files(XTThreadPtr self)
780
 
{
781
 
        XTFilePtr       file_ptr, *file_pptr;
782
 
        size_t          i = 0;
783
 
 
784
 
        xt_sl_lock(self, fs_globals.fsg_open_files);
785
 
        pushr_(xt_sl_unlock, fs_globals.fsg_open_files);
786
 
 
787
 
        for (;;) {
788
 
                if (!(file_pptr = (XTFilePtr *) xt_sl_item_at(fs_globals.fsg_open_files, i)))
789
 
                        break;
790
 
                file_ptr = *file_pptr;
791
 
                i++;
792
 
                if (file_ptr->fil_type == XT_FT_HEAP) {
793
 
                        file_ptr->fil_ref_count--;
794
 
                        if (!file_ptr->fil_ref_count) {
795
 
                                xt_sl_delete(self, fs_globals.fsg_open_files, file_ptr->fil_path);
796
 
                                i--;
797
 
                        }
798
 
                }
799
 
        }
800
 
 
801
 
        freer_(); // xt_sl_unlock(fs_globals.fsg_open_files)
802
 
}
803
 
 
804
 
static xtBool fs_open_file(XTThreadPtr self, XT_FD *fd, XTFilePtr file, int mode)
805
 
{
806
 
        int retried = FALSE;
807
 
 
808
 
#ifdef DEBUG_TRACE_FILES
809
 
        PRINTF("%s: OPEN FILE: (%d) %s\n", self->t_name, (int) file->fil_id, xt_last_2_names_of_path(file->fil_path));
810
 
#endif
811
 
        retry:
812
 
#ifdef XT_WIN
813
 
        SECURITY_ATTRIBUTES     sa = { sizeof(SECURITY_ATTRIBUTES), 0, 0 };
814
 
        DWORD                           flags;
815
 
 
816
 
        if (mode & XT_FS_EXCLUSIVE)
817
 
                flags = CREATE_NEW;
818
 
        else if (mode & XT_FS_CREATE)
819
 
                flags = OPEN_ALWAYS;
820
 
        else
821
 
                flags = OPEN_EXISTING;
822
 
 
823
 
        *fd = CreateFile(
824
 
                file->fil_path,
825
 
                mode & XT_FS_READONLY ? GENERIC_READ : (GENERIC_READ | GENERIC_WRITE),
826
 
                FILE_SHARE_READ | FILE_SHARE_WRITE,
827
 
                &sa,
828
 
                flags,
829
 
                FILE_FLAG_RANDOM_ACCESS,
830
 
                NULL);
831
 
        if (*fd == INVALID_HANDLE_VALUE) {
832
 
                int err = fs_get_win_error();
833
 
 
834
 
                if (!(mode & XT_FS_MISSING_OK) || !XT_FILE_NOT_FOUND(err)) {
835
 
                        if (!retried && (mode & XT_FS_MAKE_PATH) && XT_FILE_NOT_FOUND(err)) {
836
 
                                char path[PATH_MAX];
837
 
 
838
 
                                xt_strcpy(PATH_MAX, path, file->fil_path);
839
 
                                xt_remove_last_name_of_path(path);
840
 
                                xt_fs_mkpath(self, path);
841
 
                                retried = TRUE;
842
 
                                goto retry;
843
 
                        }
844
 
 
845
 
                        xt_throw_ferrno(XT_CONTEXT, err, file->fil_path);
846
 
                }
847
 
 
848
 
                /* File is missing, but don't throw an error. */
849
 
                return FAILED;
850
 
        }
851
 
        //PRINTF("open %d %s\n", *fd, file->fil_path);
852
 
        return OK;
853
 
#else
854
 
        int flags = 0;
855
 
 
856
 
        if (mode & XT_FS_READONLY)
857
 
                flags = O_RDONLY;
858
 
        else
859
 
                flags = O_RDWR;
860
 
        if (mode & XT_FS_CREATE)
861
 
                flags |= O_CREAT;
862
 
        if (mode & XT_FS_EXCLUSIVE)
863
 
                flags |= O_EXCL;
864
 
#ifdef O_DIRECT
865
 
        if (mode & XT_FS_DIRECT_IO)
866
 
                flags |= O_DIRECT;
867
 
#endif
868
 
 
869
 
        *fd = open(file->fil_path, flags, XT_MASK);
870
 
        if (*fd == -1) {
871
 
                int err = errno;
872
 
 
873
 
                if (!(mode & XT_FS_MISSING_OK) || err != ENOENT) {
874
 
                        if (!retried && (mode & XT_FS_MAKE_PATH) && err == ENOENT) {
875
 
                                char path[PATH_MAX];
876
 
 
877
 
                                xt_strcpy(PATH_MAX, path, file->fil_path);
878
 
                                xt_remove_last_name_of_path(path);
879
 
                                xt_fs_mkpath(self, path);
880
 
                                retried = TRUE;
881
 
                                goto retry;
882
 
                        }
883
 
 
884
 
                        xt_throw_ferrno(XT_CONTEXT, err, file->fil_path);
885
 
                }
886
 
 
887
 
                /* File is missing, but don't throw an error. */
888
 
                return FAILED;
889
 
        }
890
 
        ///PRINTF("open %d %s\n", *fd, file->fil_path);
891
 
        return OK;
892
 
#endif
893
 
}
894
 
 
895
 
xtPublic XTOpenFilePtr xt_open_file(XTThreadPtr self, char *file, XTFileType type, int mode, size_t grow_size)
896
 
{
897
 
        XTOpenFilePtr   of;
898
 
        XTFilePtr               fp;
899
 
 
900
 
        pushsr_(of, xt_close_file, (XTOpenFilePtr) xt_calloc(self, sizeof(XTOpenFileRec)));
901
 
        fp = xt_fs_get_file(self, file, type);
902
 
        of->of_type = type;
903
 
        of->fr_file = fp;
904
 
        of->fr_id = fp->fil_id;
905
 
 
906
 
        switch (type) {
907
 
                case XT_FT_NONE:
908
 
                        break;
909
 
                case XT_FT_REWRITE_FLUSH:
910
 
                case XT_FT_STANDARD:
911
 
                        of->x.of_filedes = XT_NULL_FD;
912
 
#ifdef XT_WIN
913
 
                        if (!fs_open_file(self, &of->of_filedes, fp, mode)) {
914
 
                                xt_close_file(self, of);
915
 
                                of = NULL;
916
 
                        }
917
 
#else
918
 
                        xtBool failed;
919
 
 
920
 
                        failed = FALSE;
921
 
                        if (fp->fil_filedes == -1) {
922
 
                                xt_sl_lock(self, fs_globals.fsg_open_files);
923
 
                                pushr_(xt_sl_unlock, fs_globals.fsg_open_files);
924
 
                                if (fp->fil_filedes == -1) {
925
 
                                        if (!fs_open_file(self, &fp->fil_filedes, fp, mode))
926
 
                                                failed = TRUE;
927
 
                                }
928
 
                                freer_(); // xt_ht_unlock(fs_globals.fsg_open_files)
929
 
                        }
930
 
 
931
 
                        if (failed) {
932
 
                                /* Close, but after we have release the fsg_open_files lock! */
933
 
                                xt_close_file(self, of);
934
 
                                of = NULL;
935
 
                        }
936
 
                        else
937
 
                                of->x.of_filedes = fp->fil_filedes;
938
 
#endif
939
 
                        break;
940
 
                case XT_FT_MEM_MAP:
941
 
                        xt_sl_lock(self, fs_globals.fsg_open_files);
942
 
                        pushr_(xt_sl_unlock, fs_globals.fsg_open_files);
943
 
 
944
 
                        if (fp->fil_filedes == XT_NULL_FD) {
945
 
                                if (!fs_open_file(self, &fp->fil_filedes, fp, mode)) {
946
 
                                        freer_(); // xt_ht_unlock(fs_globals.fsg_open_files)
947
 
                                        xt_close_file(self, of);
948
 
                                        of = NULL;
949
 
                                        goto exit;
950
 
                                }
951
 
                        }
952
 
 
953
 
                        fp->fil_handle_count++;
954
 
 
955
 
                        freer_(); // xt_ht_unlock(fs_globals.fsg_open_files)
956
 
 
957
 
                        if (!fp->x.fil_memmap) {
958
 
                                xt_sl_lock(self, fs_globals.fsg_open_files);
959
 
                                pushr_(xt_sl_unlock, fs_globals.fsg_open_files);
960
 
                                if (!fp->x.fil_memmap) {
961
 
                                        XTFileMemMapPtr mm;
962
 
 
963
 
                                        mm = (XTFileMemMapPtr) xt_calloc(self, sizeof(XTFileMemMapRec));
964
 
                                        pushr_(fs_close_fmap, mm);
965
 
 
966
 
#ifdef XT_WIN
967
 
                                        /* NULL is the value returned on error! */
968
 
                                        mm->mm_mapdes = NULL;
969
 
#endif
970
 
                                        FILE_MAP_INIT_LOCK(self, &mm->mm_lock);
971
 
                                        mm->mm_length = fs_seek_eof(self, fp->fil_filedes, fp);
972
 
                                        if (sizeof(size_t) == 4 && mm->mm_length >= (off_t) 0xFFFFFFFF)
973
 
                                                xt_throw_ixterr(XT_CONTEXT, XT_ERR_FILE_TOO_LONG, fp->fil_path);
974
 
                                        mm->mm_grow_size = grow_size;
975
 
 
976
 
                                        if (mm->mm_length < (off_t) grow_size) {
977
 
                                                mm->mm_length = (off_t) grow_size;
978
 
                                                if (!fs_map_file(mm, fp, TRUE))
979
 
                                                        xt_throw(self);
980
 
                                        }
981
 
                                        else {
982
 
                                                if (!fs_map_file(mm, fp, FALSE))
983
 
                                                        xt_throw(self);
984
 
                                        }
985
 
 
986
 
                                        popr_(); // Discard fs_close_fmap(mm)
987
 
                                        fp->x.fil_memmap = mm;
988
 
                                }
989
 
                                freer_(); // xt_ht_unlock(fs_globals.fsg_open_files)
990
 
                        }
991
 
                        of->x.mf_memmap = fp->x.fil_memmap;
992
 
                        break;
993
 
                case XT_FT_HEAP:
994
 
                        xt_sl_lock(self, fs_globals.fsg_open_files);
995
 
                        pushr_(xt_sl_unlock, fs_globals.fsg_open_files);
996
 
#ifdef DEBUG_TRACE_FILES
997
 
                        PRINTF("%s: OPEN HEAP: (%d) %s\n", self->t_name, (int) fp->fil_id, xt_last_2_names_of_path(fp->fil_path));
998
 
#endif
999
 
                        if (!fp->x.fil_heap) {
1000
 
                                XTFileHeapPtr fh;
1001
 
 
1002
 
                                if (!(mode & XT_FS_CREATE)) {
1003
 
                                        freer_(); // xt_ht_unlock(fs_globals.fsg_open_files)
1004
 
                                        if (!(mode & XT_FS_MISSING_OK))
1005
 
                                                xt_throw_ferrno(XT_CONTEXT, XT_FILE_NOT_FOUND_ERR, fp->fil_path);
1006
 
                                        xt_close_file(self, of);
1007
 
                                        of = NULL;
1008
 
                                        goto exit;
1009
 
                                }
1010
 
 
1011
 
                                fh = (XTFileHeapPtr) xt_calloc(self, sizeof(XTFileHeapRec));
1012
 
                                pushr_(xt_free, fh);
1013
 
 
1014
 
                                FILE_MAP_INIT_LOCK(self, &fh->fh_lock);
1015
 
                                fh->fh_grow_size = grow_size;
1016
 
 
1017
 
                                popr_(); // Discard xt_free(fh)
1018
 
                                fp->x.fil_heap = fh;
1019
 
                                
1020
 
                                /* {HEAP-FILE}
1021
 
                                 * This reference count is +1 for the file exists!
1022
 
                                 * It will be decremented on file delete!
1023
 
                                 */
1024
 
                                fp->fil_ref_count++;
1025
 
                        }
1026
 
                        freer_(); // xt_ht_unlock(fs_globals.fsg_open_files)
1027
 
                        of->x.of_heap = fp->x.fil_heap;
1028
 
                        break;
1029
 
        }
1030
 
 
1031
 
        exit:
1032
 
        popr_(); // Discard xt_close_file(of)
1033
 
        return of;
1034
 
}
1035
 
 
1036
 
xtPublic XTOpenFilePtr xt_open_file_ns(char *file, XTFileType type, int mode, size_t grow_size)
1037
 
{
1038
 
        XTThreadPtr             self = xt_get_self();
1039
 
        XTOpenFilePtr   of;
1040
 
 
1041
 
        try_(a) {
1042
 
                of = xt_open_file(self, file, type, mode, grow_size);
1043
 
        }
1044
 
        catch_(a) {
1045
 
                of = NULL;
1046
 
        }
1047
 
        cont_(a);
1048
 
        return of;
1049
 
}
1050
 
 
1051
 
xtPublic xtBool xt_open_file_ns(XTOpenFilePtr *fh, char *file, XTFileType type, int mode, size_t grow_size)
1052
 
{
1053
 
        XTThreadPtr             self = xt_get_self();
1054
 
        xtBool                  ok = TRUE;
1055
 
 
1056
 
        try_(a) {
1057
 
                *fh = xt_open_file(self, file, type, mode, grow_size);
1058
 
        }
1059
 
        catch_(a) {
1060
 
                ok = FALSE;
1061
 
        }
1062
 
        cont_(a);
1063
 
        return ok;
1064
 
}
1065
 
 
1066
 
xtPublic void xt_close_file(XTThreadPtr self, XTOpenFilePtr of)
1067
 
{
1068
 
        switch (of->of_type) {
1069
 
                case XT_FT_NONE:
1070
 
                        break;
1071
 
                case XT_FT_REWRITE_FLUSH:
1072
 
                case XT_FT_STANDARD:
1073
 
                        if (of->x.of_filedes != XT_NULL_FD) {
1074
 
#ifdef XT_WIN
1075
 
                                CloseHandle(of->of_filedes);
1076
 
#ifdef DEBUG_TRACE_FILES
1077
 
                                PRINTF("%s: close file: (%d) %s\n", self->t_name, (int) of->fr_file->fil_id, xt_last_2_names_of_path(of->fr_file->fil_path));
1078
 
#endif
1079
 
#else
1080
 
                                if (!of->fr_file || of->x.of_filedes != of->fr_file->fil_filedes) {
1081
 
                                        close(of->x.of_filedes);
1082
 
#ifdef DEBUG_TRACE_FILES
1083
 
                                        PRINTF("%s: close file: (%d) %s\n", self->t_name, (int) of->fr_file->fil_id, xt_last_2_names_of_path(of->fr_file->fil_path));
1084
 
#endif
1085
 
                                }
1086
 
#endif
1087
 
 
1088
 
                                of->x.of_filedes = XT_NULL_FD;
1089
 
                        }
1090
 
 
1091
 
                        if (of->fr_file) {
1092
 
                                xt_fs_release_file(self, of->fr_file);
1093
 
                                of->fr_file = NULL;
1094
 
                        }
1095
 
                        break;
1096
 
                case XT_FT_MEM_MAP:
1097
 
                        ASSERT_NS(!of->mf_slock_count);
1098
 
                        if (of->fr_file) {
1099
 
                                if (of->fr_file->x.fil_memmap) {
1100
 
                                        xt_sl_lock(self, fs_globals.fsg_open_files);
1101
 
                                        pushr_(xt_sl_unlock, fs_globals.fsg_open_files);
1102
 
                                        ASSERT_NS(of->fr_file->fil_handle_count > 0);           
1103
 
                                        of->fr_file->fil_handle_count--;
1104
 
                                        if (!of->fr_file->fil_handle_count) {
1105
 
                                                fs_close_fmap(self, of->fr_file->x.fil_memmap);
1106
 
                                                of->fr_file->x.fil_memmap = NULL;
1107
 
                                        }
1108
 
                                        freer_();
1109
 
                                }
1110
 
                                else {
1111
 
                                        ASSERT_NS(of->fr_file->fil_handle_count == 0);          
1112
 
                                        of->fr_file->fil_handle_count = 0;
1113
 
                                }
1114
 
                                
1115
 
                                xt_fs_release_file(self, of->fr_file);
1116
 
                                of->fr_file = NULL;
1117
 
                        }
1118
 
                        of->x.mf_memmap = NULL;
1119
 
                        break;
1120
 
                case XT_FT_HEAP:
1121
 
#ifdef DEBUG_TRACE_FILES
1122
 
                        PRINTF("%s: close heap: (%d) %s\n", self->t_name, (int) of->fr_file->fil_id, xt_last_2_names_of_path(of->fr_file->fil_path));
1123
 
#endif
1124
 
                        if (of->fr_file) {
1125
 
                                xt_fs_release_file(self, of->fr_file);
1126
 
                                of->fr_file = NULL;
1127
 
                        }
1128
 
                        of->x.of_heap = NULL;
1129
 
                        break;
1130
 
        }
1131
 
        xt_free(self, of);
1132
 
}
1133
 
 
1134
 
xtPublic xtBool xt_close_file_ns(XTOpenFilePtr of)
1135
 
{
1136
 
        XTThreadPtr self = xt_get_self();
1137
 
        xtBool          failed = FALSE;
1138
 
 
1139
 
        try_(a) {
1140
 
                xt_close_file(self, of);
1141
 
        }
1142
 
        catch_(a) {
1143
 
                failed = TRUE;
1144
 
        }
1145
 
        cont_(a);
1146
 
        return failed;
1147
 
}
1148
 
 
1149
 
/* ----------------------------------------------------------------------
1150
 
 * I/O operations
1151
 
 */
1152
 
 
1153
 
xtPublic xtBool xt_lock_file(struct XTThread *self, XTOpenFilePtr of)
1154
 
{
1155
 
        if (of->of_type != XT_FT_STANDARD && of->of_type != XT_FT_REWRITE_FLUSH) {
1156
 
                xt_throw_ixterr(XT_CONTEXT, XT_ERR_FILE_OP_NOT_SUPP, xt_file_path(of));
1157
 
                return FAILED;
1158
 
        }
1159
 
#ifdef XT_WIN
1160
 
        if (!LockFile(of->x.of_filedes, 0, 0, 512, 0)) {
1161
 
                int err = fs_get_win_error();
1162
 
                
1163
 
                if (err == ERROR_LOCK_VIOLATION ||
1164
 
                        err == ERROR_LOCK_FAILED)
1165
 
                        return FAILED;
1166
 
                
1167
 
                xt_throw_ferrno(XT_CONTEXT, err, xt_file_path(of));
1168
 
                return FAILED;
1169
 
        }
1170
 
        return OK;
1171
 
#else
1172
 
        if (lockf(of->x.of_filedes, F_TLOCK, 0) == 0)
1173
 
                return OK;
1174
 
        if (errno == EAGAIN)
1175
 
                return FAILED;
1176
 
        xt_throw_ferrno(XT_CONTEXT, errno, xt_file_path(of));
1177
 
        return FAILED;
1178
 
#endif
1179
 
}
1180
 
 
1181
 
xtPublic void xt_unlock_file(struct XTThread *self, XTOpenFilePtr of)
1182
 
{
1183
 
        if (of->of_type != XT_FT_STANDARD && of->of_type != XT_FT_REWRITE_FLUSH) {
1184
 
                xt_throw_ixterr(XT_CONTEXT, XT_ERR_FILE_OP_NOT_SUPP, xt_file_path(of));
1185
 
                return;
1186
 
        }
1187
 
#ifdef XT_WIN
1188
 
        if (!UnlockFile(of->x.of_filedes, 0, 0, 512, 0)) {
1189
 
                int err = fs_get_win_error();
1190
 
                
1191
 
                if (err != ERROR_NOT_LOCKED)
1192
 
                        xt_throw_ferrno(XT_CONTEXT, err, xt_file_path(of));
1193
 
        }
1194
 
#else
1195
 
        if (lockf(of->x.of_filedes, F_ULOCK, 0) == -1)
1196
 
                xt_throw_ferrno(XT_CONTEXT, errno, xt_file_path(of));
1197
 
#endif
1198
 
}
1199
 
 
1200
 
static off_t fs_seek_eof(XTThreadPtr self, XT_FD fd, XTFilePtr file)
1201
 
{
1202
 
#ifdef XT_WIN
1203
 
        DWORD                   result;
1204
 
        LARGE_INTEGER   lpFileSize;
1205
 
 
1206
 
        result = SetFilePointer(fd, 0, NULL, FILE_END);
1207
 
        if (result == 0xFFFFFFFF) {
1208
 
                xt_throw_ferrno(XT_CONTEXT, fs_get_win_error(), file->fil_path);
1209
 
                return (off_t) -1;
1210
 
        }
1211
 
 
1212
 
        if (!GetFileSizeEx(fd, &lpFileSize)) {
1213
 
                xt_throw_ferrno(XT_CONTEXT, fs_get_win_error(), file->fil_path);
1214
 
                return (off_t) -1;
1215
 
        }
1216
 
 
1217
 
        return lpFileSize.QuadPart;
1218
 
#else
1219
 
        off_t off;
1220
 
 
1221
 
        off = lseek(fd, 0, SEEK_END);
1222
 
        if (off == -1) {
1223
 
                xt_throw_ferrno(XT_CONTEXT, errno, file->fil_path);
1224
 
                return -1;
1225
 
        }
1226
 
 
1227
 
     return off;
1228
 
#endif
1229
 
}
1230
 
 
1231
 
xtPublic off_t xt_seek_eof_file(XTThreadPtr self, XTOpenFilePtr of)
1232
 
{
1233
 
        switch (of->of_type) {
1234
 
                case XT_FT_NONE:
1235
 
                        break;
1236
 
                case XT_FT_REWRITE_FLUSH:
1237
 
                case XT_FT_STANDARD:
1238
 
                        return fs_seek_eof(self, of->x.of_filedes, of->fr_file);
1239
 
                case XT_FT_MEM_MAP:
1240
 
                        return of->x.mf_memmap->mm_length;
1241
 
                case XT_FT_HEAP:
1242
 
                        return of->x.of_heap->fh_length;
1243
 
        }
1244
 
        return 0;
1245
 
}
1246
 
 
1247
 
xtPublic xtBool xt_set_eof_file(XTThreadPtr self, XTOpenFilePtr of, off_t offset)
1248
 
{
1249
 
        switch (of->of_type) {
1250
 
                case XT_FT_NONE:
1251
 
                        break;
1252
 
                case XT_FT_REWRITE_FLUSH:
1253
 
                case XT_FT_STANDARD:
1254
 
#ifdef XT_WIN
1255
 
                        LARGE_INTEGER liDistanceToMove;
1256
 
                        
1257
 
                        liDistanceToMove.QuadPart = offset;
1258
 
                        if (!SetFilePointerEx(of->of_filedes, liDistanceToMove, NULL, FILE_BEGIN)) {
1259
 
                                xt_throw_ferrno(XT_CONTEXT, fs_get_win_error(), xt_file_path(of));
1260
 
                                return FAILED;
1261
 
                        }
1262
 
 
1263
 
                        if (!SetEndOfFile(of->of_filedes)) {
1264
 
                                xt_throw_ferrno(XT_CONTEXT, fs_get_win_error(), xt_file_path(of));
1265
 
                                return FAILED;
1266
 
                        }
1267
 
#else
1268
 
                        if (ftruncate(of->x.of_filedes, offset) == -1) {
1269
 
                                xt_throw_ferrno(XT_CONTEXT, errno, xt_file_path(of));
1270
 
                                return FAILED;
1271
 
                        }
1272
 
#endif
1273
 
                        break;
1274
 
                case XT_FT_MEM_MAP:
1275
 
                        xt_throw_ixterr(XT_CONTEXT, XT_ERR_FILE_OP_NOT_SUPP, xt_file_path(of));
1276
 
                        break;
1277
 
                case XT_FT_HEAP:
1278
 
                        xt_throw_ixterr(XT_CONTEXT, XT_ERR_FILE_OP_NOT_SUPP, xt_file_path(of));
1279
 
                        break;
1280
 
        }
1281
 
        return OK;
1282
 
}
1283
 
 
1284
 
static xtBool fs_rewrite_file(XTOpenFilePtr of, off_t offset, size_t size, void *data, XTIOStatsPtr stat, XTThreadPtr XT_UNUSED(thread))
1285
 
{
1286
 
#ifdef XT_TIME_DISK_WRITES
1287
 
        xtWord8         s;
1288
 
#endif
1289
 
 
1290
 
#ifdef XT_WIN
1291
 
        LARGE_INTEGER   liDistanceToMove;
1292
 
        DWORD                   result;
1293
 
        
1294
 
        liDistanceToMove.QuadPart = offset;
1295
 
        if (!SetFilePointerEx(of->of_filedes, liDistanceToMove, NULL, FILE_BEGIN)) {
1296
 
                xt_register_ferrno(XT_REG_CONTEXT, fs_get_win_error(), xt_file_path(of));
1297
 
                return FAILED;
1298
 
        }
1299
 
 
1300
 
        if (!ReadFile(of->of_filedes, data, size, &result, NULL)) {
1301
 
                xt_register_ferrno(XT_REG_CONTEXT, fs_get_win_error(), xt_file_path(of));
1302
 
                return FAILED;
1303
 
        }
1304
 
 
1305
 
        if ((size_t) result < 4) {
1306
 
                xt_register_ferrno(XT_REG_CONTEXT, ERROR_HANDLE_EOF, xt_file_path(of));
1307
 
                return FAILED;
1308
 
        }
1309
 
 
1310
 
        ASSERT_NS(offset + size == (offset + result + 1023) / 1024 * 1024);
1311
 
        size = (size_t) result;
1312
 
 
1313
 
        stat->ts_read += (u_int) size;
1314
 
 
1315
 
#ifdef XT_TIME_DISK_WRITES
1316
 
        stat->ts_write_start = xt_trace_clock();
1317
 
#endif
1318
 
 
1319
 
        liDistanceToMove.QuadPart = offset;
1320
 
        if (!SetFilePointerEx(of->of_filedes, liDistanceToMove, NULL, FILE_BEGIN)) {
1321
 
                xt_register_ferrno(XT_REG_CONTEXT, fs_get_win_error(), xt_file_path(of));
1322
 
                goto failed;
1323
 
        }
1324
 
 
1325
 
        if (!WriteFile(of->of_filedes, data, size, &result, NULL)) {
1326
 
                xt_register_ferrno(XT_REG_CONTEXT, fs_get_win_error(), xt_file_path(of));
1327
 
                goto failed;
1328
 
        }
1329
 
 
1330
 
        if (result != size) {
1331
 
                xt_register_ferrno(XT_REG_CONTEXT, ERROR_HANDLE_EOF, xt_file_path(of));
1332
 
                goto failed;
1333
 
        }
1334
 
#else
1335
 
        ssize_t result_size;
1336
 
 
1337
 
        result_size = pread(of->x.of_filedes, data, size, offset);
1338
 
        if (result_size == -1) {
1339
 
                xt_register_ferrno(XT_REG_CONTEXT, errno, xt_file_path(of));
1340
 
                return FAILED;
1341
 
        }
1342
 
 
1343
 
        /* Read may not work because of rounding: */
1344
 
        ASSERT_NS(offset + size == (offset + result_size + 1023) / 1024 * 1024);
1345
 
        size = result_size;
1346
 
 
1347
 
        stat->ts_read += (u_int) size;
1348
 
 
1349
 
#ifdef XT_TIME_DISK_WRITES
1350
 
        stat->ts_write_start = xt_trace_clock();
1351
 
#endif
1352
 
 
1353
 
        result_size = pwrite(of->x.of_filedes, data, size, offset);
1354
 
        if (result_size == -1) {
1355
 
                xt_register_ferrno(XT_REG_CONTEXT, errno, xt_file_path(of));
1356
 
                goto failed;
1357
 
        }
1358
 
 
1359
 
        if ((size_t) result_size != size) {
1360
 
                xt_register_ferrno(XT_REG_CONTEXT, ESPIPE, xt_file_path(of));
1361
 
                goto failed;
1362
 
        }
1363
 
#endif
1364
 
 
1365
 
#ifdef XT_TIME_DISK_WRITES
1366
 
        s = stat->ts_write_start;
1367
 
        stat->ts_write_start = 0;
1368
 
        stat->ts_write_time += xt_trace_clock() - s;
1369
 
#endif
1370
 
        stat->ts_write += (u_int) size;
1371
 
        return OK;
1372
 
        
1373
 
        failed:
1374
 
#ifdef XT_TIME_DISK_WRITES
1375
 
        s = stat->ts_write_start;
1376
 
        stat->ts_write_start = 0;
1377
 
        stat->ts_write_time += xt_trace_clock() - s;
1378
 
#endif
1379
 
        return FAILED;
1380
 
}
1381
 
 
1382
 
xtPublic xtBool xt_pwrite_file(XTOpenFilePtr of, off_t offset, size_t size, void *data, XTIOStatsPtr stat, XTThreadPtr thread)
1383
 
{
1384
 
        xtThreadID      thd_id;
1385
 
#ifdef XT_TIME_DISK_WRITES
1386
 
        xtWord8         s;
1387
 
#endif
1388
 
 
1389
 
#if defined(DEBUG_TRACE_IO) || defined(DEBUG_TRACE_AROUND)
1390
 
        char    timef[50];
1391
 
        xtWord8 start = xt_trace_clock();
1392
 
#endif
1393
 
#ifdef DEBUG_TRACE_AROUND
1394
 
        if (xt_is_extension(of->fr_file->fil_path, "xti"))
1395
 
                PRINTF("%s %s write\n", xt_trace_clock_str(timef), thread->t_name);
1396
 
#endif
1397
 
#ifdef INJECT_WRITE_FILE_ERROR
1398
 
        if ((xt_is_extension(of->fr_file->fil_path, INJECT_WRITE_FILE_TYPE) ||
1399
 
                xt_starts_with(xt_last_name_of_path(of->fr_file->fil_path), INJECT_WRITE_FILE_TYPE))
1400
 
#ifdef INJECT_ONCE_OFF
1401
 
                && !error_returned
1402
 
#endif
1403
 
                )
1404
 
        {
1405
 
                if (xt_seek_eof_file(NULL, of) > INJECT_WRITE_FILE_SIZE) {
1406
 
                        error_returned = TRUE;
1407
 
                        xt_register_ferrno(XT_REG_CONTEXT, 30, of->fr_file->fil_path);
1408
 
                        return FAILED;
1409
 
                }
1410
 
        }
1411
 
#endif
1412
 
 
1413
 
        switch (of->of_type) {
1414
 
                case XT_FT_NONE:
1415
 
                        break;
1416
 
                case XT_FT_REWRITE_FLUSH:
1417
 
                        XTRewriteFlushPtr       rf;
1418
 
                        RewriteBlockPtr         rec;
1419
 
                        off_t                           block_offset;
1420
 
                        off_t                           block_size;
1421
 
                        size_t                          idx;
1422
 
                        xtWord8                         flush_offset;
1423
 
 
1424
 
                        rf = of->fr_file->x.fil_rewrite;
1425
 
 
1426
 
                        /* Round up and down by 1K */
1427
 
                        block_offset = offset / 1024 * 1024;
1428
 
                        block_size = ((offset + size + 1023) / 1024 * 1024) - block_offset;
1429
 
 
1430
 
                        xt_spinlock_lock(&rf->rf_lock);
1431
 
                        if ((rec = (RewriteBlockPtr) fs_rewrite_bsearch(&block_offset, rf->rf_blocks, rf->rf_block_count, sizeof(RewriteBlockRec), &idx, rewrite_opt_comp))) {
1432
 
                                if (block_size > rec->rb_size)
1433
 
                                        rec->rb_size = block_size;
1434
 
                                goto merge_right;
1435
 
                        }
1436
 
 
1437
 
                        if (idx == 0) {
1438
 
                                /* The offset is before the first entry. */
1439
 
                                if (idx < rf->rf_block_count) {
1440
 
                                        /* There is a first entry: */
1441
 
                                        rec = rf->rf_blocks;
1442
 
                                        if (rec->rb_offset - (block_offset + block_size) < XT_REWRITE_BLOCK_DISTANCE)
1443
 
                                                goto add_to_right;
1444
 
                                }
1445
 
 
1446
 
                                /* Add the first entry: */
1447
 
                                goto add_the_entry;
1448
 
                        }
1449
 
 
1450
 
                        /* Not the first entry: */
1451
 
                        idx--;
1452
 
                        rec = rf->rf_blocks + idx;
1453
 
 
1454
 
                        if (block_offset - (rec->rb_offset + rec->rb_size) < XT_REWRITE_BLOCK_DISTANCE) {
1455
 
                                /* Add to block on left: */
1456
 
                                block_size = (block_offset + block_size) - rec->rb_offset;
1457
 
                                if (block_size > rec->rb_size)
1458
 
                                        rec->rb_size = block_size;
1459
 
                                goto merge_right;
1460
 
                        }
1461
 
                        
1462
 
                        idx++;
1463
 
                        rec = rf->rf_blocks + idx;
1464
 
 
1465
 
                        if (idx < rf->rf_block_count && rec->rb_offset - (block_offset + block_size) < XT_REWRITE_BLOCK_DISTANCE)
1466
 
                                goto add_to_right;
1467
 
 
1468
 
                        add_the_entry:
1469
 
                        ASSERT_NS(rf->rf_block_count < XT_REWRITE_MAX_BLOCKS);
1470
 
                        rec = rf->rf_blocks + idx;
1471
 
                        memmove(rec+1, rec, (rf->rf_block_count - idx) * sizeof(RewriteBlockRec));
1472
 
                        rec->rb_offset = block_offset;
1473
 
                        rec->rb_size = block_size;
1474
 
                        rf->rf_block_count++;
1475
 
                        goto continue_write;
1476
 
 
1477
 
                        add_to_right:
1478
 
                        rec->rb_size += rec->rb_offset - block_offset;
1479
 
                        if (block_size > rec->rb_size)
1480
 
                                rec->rb_size = block_size;
1481
 
                        rec->rb_offset = block_offset;
1482
 
 
1483
 
                        merge_right:
1484
 
                        if (idx+1 < rf->rf_block_count) {
1485
 
                                /* There is a record right: */
1486
 
                                if (rec->rb_offset + rec->rb_size + XT_REWRITE_BLOCK_DISTANCE > (rec+1)->rb_offset) {
1487
 
                                        /* Merge and remove! */
1488
 
                                        block_size = (rec+1)->rb_size + ((rec+1)->rb_offset - rec->rb_offset);
1489
 
                                        if (block_size > rec->rb_size)
1490
 
                                                rec->rb_size = block_size;
1491
 
                                        rf->rf_block_count--;
1492
 
                                        assert(rf->rf_block_count > idx);
1493
 
                                        memmove(rec+1, rec+2, (rf->rf_block_count - idx - 1) * sizeof(RewriteBlockRec));
1494
 
                                }
1495
 
                        }
1496
 
                        continue_write:
1497
 
                        if (rf->rf_block_count == XT_REWRITE_MAX_BLOCKS) {
1498
 
                                /* Consolidate 2 blocks that are closest to each other in other to
1499
 
                                 * make space for another block:
1500
 
                                 */
1501
 
                                size_t  i;
1502
 
                                off_t   gap;
1503
 
                                off_t   min_gap = (off_t) -1;
1504
 
 
1505
 
                                rec = rf->rf_blocks;
1506
 
                                for (i=0; i<rf->rf_block_count-1; i++) {
1507
 
                                        gap = (rec+1)->rb_offset - (rec->rb_offset + rec->rb_size);
1508
 
                                        if (min_gap == (off_t) -1 || gap < min_gap) {
1509
 
                                                idx = i;
1510
 
                                                min_gap = gap;
1511
 
                                        }
1512
 
                                        rec++;
1513
 
                                }
1514
 
 
1515
 
                                /* Merge this with the next: */
1516
 
                                rec = rf->rf_blocks + idx;
1517
 
                                block_size = (rec+1)->rb_size + ((rec+1)->rb_offset - rec->rb_offset);
1518
 
                                if (block_size > rec->rb_size)
1519
 
                                        rec->rb_size = block_size;
1520
 
                                rf->rf_block_count--;
1521
 
                                ASSERT_NS(rf->rf_block_count > idx);
1522
 
                                memmove(rec+1, rec+2, (rf->rf_block_count - idx - 1) * sizeof(RewriteBlockRec));
1523
 
                        }
1524
 
                        xt_spinlock_unlock(&rf->rf_lock);
1525
 
                        RR_FLUSH_READ_LOCK(&rf->rf_write_lock, thread->t_id);
1526
 
                        
1527
 
                        /* Wait for flush to pass this point: */
1528
 
                        for (;;) {
1529
 
                                flush_offset = ((xtWord8) rf->rf_flush_offset_hi << 32) | rf->rf_flush_offset_lo;
1530
 
                                if ((xtWord8) offset < flush_offset)
1531
 
                                        break;
1532
 
                                xt_critical_wait();
1533
 
                        }
1534
 
#ifdef XT_TIME_DISK_WRITES
1535
 
                        stat->ts_write_start = xt_trace_clock();
1536
 
#endif
1537
 
#ifdef XT_WIN
1538
 
                        LARGE_INTEGER   liDistanceToMove;
1539
 
                        DWORD                   result;
1540
 
                        
1541
 
                        liDistanceToMove.QuadPart = offset;
1542
 
                        if (!SetFilePointerEx(of->of_filedes, liDistanceToMove, NULL, FILE_BEGIN)) {
1543
 
                                RR_FLUSH_UNLOCK(&rf->rf_write_lock, thread->t_id);
1544
 
                                xt_register_ferrno(XT_REG_CONTEXT, fs_get_win_error(), xt_file_path(of));
1545
 
                                goto failed;
1546
 
                        }
1547
 
 
1548
 
                        if (!WriteFile(of->of_filedes, data, size, &result, NULL)) {
1549
 
                                RR_FLUSH_UNLOCK(&rf->rf_write_lock, thread->t_id);
1550
 
                                xt_register_ferrno(XT_REG_CONTEXT, fs_get_win_error(), xt_file_path(of));
1551
 
                                goto failed;
1552
 
                        }
1553
 
 
1554
 
                        if (result != size) {
1555
 
                                RR_FLUSH_UNLOCK(&rf->rf_write_lock, thread->t_id);
1556
 
                                xt_register_ferrno(XT_REG_CONTEXT, ERROR_HANDLE_EOF, xt_file_path(of));
1557
 
                                goto failed;
1558
 
                        }
1559
 
#else
1560
 
                        ssize_t write_size;
1561
 
 
1562
 
                        write_size = pwrite(of->x.of_filedes, data, size, offset);
1563
 
                        if (write_size == -1) {
1564
 
                                RR_FLUSH_UNLOCK(&rf->rf_write_lock, thread->t_id);
1565
 
                                xt_register_ferrno(XT_REG_CONTEXT, errno, xt_file_path(of));
1566
 
                                goto failed;
1567
 
                        }
1568
 
 
1569
 
                        if ((size_t) write_size != size) {
1570
 
                                RR_FLUSH_UNLOCK(&rf->rf_write_lock, thread->t_id);
1571
 
                                xt_register_ferrno(XT_REG_CONTEXT, ESPIPE, xt_file_path(of));
1572
 
                                goto failed;
1573
 
                        }
1574
 
#endif
1575
 
                        RR_FLUSH_UNLOCK(&rf->rf_write_lock, thread->t_id);
1576
 
                        break;
1577
 
                case XT_FT_STANDARD:
1578
 
#ifdef XT_TIME_DISK_WRITES
1579
 
                        stat->ts_write_start = xt_trace_clock();
1580
 
#endif
1581
 
#ifdef XT_WIN
1582
 
                        LARGE_INTEGER   liDistanceToMove;
1583
 
                        DWORD                   result;
1584
 
                        
1585
 
                        liDistanceToMove.QuadPart = offset;
1586
 
                        if (!SetFilePointerEx(of->of_filedes, liDistanceToMove, NULL, FILE_BEGIN)) {
1587
 
                                xt_register_ferrno(XT_REG_CONTEXT, fs_get_win_error(), xt_file_path(of));
1588
 
                                goto failed;
1589
 
                        }
1590
 
 
1591
 
                        if (!WriteFile(of->of_filedes, data, size, &result, NULL)) {
1592
 
                                xt_register_ferrno(XT_REG_CONTEXT, fs_get_win_error(), xt_file_path(of));
1593
 
                                goto failed;
1594
 
                        }
1595
 
 
1596
 
                        if (result != size) {
1597
 
                                xt_register_ferrno(XT_REG_CONTEXT, ERROR_HANDLE_EOF, xt_file_path(of));
1598
 
                                goto failed;
1599
 
                        }
1600
 
#else
1601
 
                        write_size = pwrite(of->x.of_filedes, data, size, offset);
1602
 
                        if (write_size == -1) {
1603
 
                                xt_register_ferrno(XT_REG_CONTEXT, errno, xt_file_path(of));
1604
 
                                goto failed;
1605
 
                        }
1606
 
 
1607
 
                        if ((size_t) write_size != size) {
1608
 
                                xt_register_ferrno(XT_REG_CONTEXT, ESPIPE, xt_file_path(of));
1609
 
                                goto failed;
1610
 
                        }
1611
 
#endif
1612
 
                        break;
1613
 
                case XT_FT_MEM_MAP: {
1614
 
                        XTFileMemMapPtr mm = of->x.mf_memmap;
1615
 
 
1616
 
                        thd_id  = thread->t_id;
1617
 
                        ASSERT_NS(!of->mf_slock_count);
1618
 
                        FILE_MAP_READ_LOCK(&mm->mm_lock, thd_id);
1619
 
                        if (!mm->mm_start || offset + (off_t) size > mm->mm_length) {
1620
 
                                FILE_MAP_UNLOCK(&mm->mm_lock, thd_id);
1621
 
 
1622
 
                                FILE_MAP_WRITE_LOCK(&mm->mm_lock, thd_id);
1623
 
                                if (!fs_remap_file(of, offset, size, stat)) {
1624
 
                                        FILE_MAP_UNLOCK(&mm->mm_lock, thd_id);
1625
 
                                        return FAILED;
1626
 
                                }
1627
 
                        }
1628
 
 
1629
 
#ifdef XT_TIME_DISK_WRITES
1630
 
                        stat->ts_write_start = xt_trace_clock();
1631
 
#endif
1632
 
#ifdef XT_WIN
1633
 
                        __try
1634
 
                        {
1635
 
                                memcpy(mm->mm_start + offset, data, size);
1636
 
                        }
1637
 
                        // GetExceptionCode()== EXCEPTION_IN_PAGE_ERROR ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH
1638
 
                        __except(EXCEPTION_EXECUTE_HANDLER)
1639
 
                        {
1640
 
                                xt_register_ferrno(XT_REG_CONTEXT, GetExceptionCode(), xt_file_path(map));
1641
 
                                FILE_MAP_UNLOCK(&mm->mm_lock, thd_id);
1642
 
                                goto failed;
1643
 
                        }
1644
 
#else
1645
 
                        memcpy(mm->mm_start + offset, data, size);
1646
 
#endif
1647
 
 
1648
 
                        FILE_MAP_UNLOCK(&mm->mm_lock, thd_id);
1649
 
                        break;
1650
 
                }
1651
 
                case XT_FT_HEAP: {
1652
 
                        XTFileHeapPtr   fh = of->x.of_heap;
1653
 
 
1654
 
#ifdef XT_TIME_DISK_WRITES
1655
 
                        stat->ts_write_start = xt_trace_clock();
1656
 
#endif
1657
 
                        thd_id  = thread->t_id;
1658
 
                        ASSERT_NS(!of->mf_slock_count);
1659
 
                        FILE_MAP_READ_LOCK(&fh->fh_lock, thd_id);
1660
 
                        if (!fh->fh_start || offset + (off_t) size > fh->fh_length) {
1661
 
                                FILE_MAP_UNLOCK(&fh->fh_lock, thd_id);
1662
 
 
1663
 
                                FILE_MAP_WRITE_LOCK(&fh->fh_lock, thd_id);
1664
 
                                off_t new_len;
1665
 
 
1666
 
                                new_len = (((offset + size) / fh->fh_grow_size) + 1) * fh->fh_grow_size;
1667
 
                                if (!xt_realloc_ns((void **) &fh->fh_start, (size_t) new_len)) {
1668
 
                                        FILE_MAP_UNLOCK(&fh->fh_lock, thd_id);
1669
 
                                        goto failed;
1670
 
                                }
1671
 
                                fh->fh_length = new_len;
1672
 
                        }
1673
 
 
1674
 
                        memcpy(fh->fh_start + offset, data, size);
1675
 
 
1676
 
                        FILE_MAP_UNLOCK(&fh->fh_lock, thd_id);
1677
 
                        break;
1678
 
                }
1679
 
        }
1680
 
 
1681
 
#ifdef XT_TIME_DISK_WRITES
1682
 
        s = stat->ts_write_start;
1683
 
        stat->ts_write_start = 0;
1684
 
        stat->ts_write_time += xt_trace_clock() - s;
1685
 
#endif
1686
 
        stat->ts_write += (u_int) size;
1687
 
#ifdef DEBUG_TRACE_IO
1688
 
        xt_trace("/* %s */ pbxt_file_writ(\"%s\", %lu, %lu);\n", xt_trace_clock_diff(timef, start), of->fr_file->fil_path, (u_long) offset, (u_long) size);
1689
 
#endif
1690
 
#ifdef DEBUG_TRACE_AROUND
1691
 
        if (xt_is_extension(of->fr_file->fil_path, "xti"))
1692
 
                PRINTF("%s %s write (%d)\n", xt_trace_clock_str(timef), thread->t_name, (int) (xt_trace_clock() - start));
1693
 
#endif
1694
 
        return OK;
1695
 
        
1696
 
        failed:
1697
 
#ifdef XT_TIME_DISK_WRITES
1698
 
        s = stat->ts_write_start;
1699
 
        stat->ts_write_start = 0;
1700
 
        stat->ts_write_time += xt_trace_clock() - s;
1701
 
#endif
1702
 
        return FAILED;
1703
 
}
1704
 
 
1705
 
xtPublic xtBool xt_flush_file(XTOpenFilePtr of, XTIOStatsPtr stat, XTThreadPtr thread)
1706
 
{
1707
 
        xtWord8 s;
1708
 
 
1709
 
#if defined(DEBUG_TRACE_IO) || defined(DEBUG_TRACE_AROUND)
1710
 
        char    timef[50];
1711
 
        xtWord8 start = xt_trace_clock();
1712
 
#endif
1713
 
#ifdef DEBUG_TRACE_AROUND
1714
 
        if (xt_is_extension(of->fr_file->fil_path, "xti"))
1715
 
                PRINTF("%s %s FLUSH\n", xt_trace_clock_str(timef), thread->t_name);
1716
 
#endif
1717
 
#ifdef INJECT_FLUSH_FILE_ERROR
1718
 
        if ((xt_is_extension(of->fr_file->fil_path, INJECT_FLUSH_FILE_TYPE) ||
1719
 
                xt_starts_with(xt_last_name_of_path(of->fr_file->fil_path), INJECT_FLUSH_FILE_TYPE))) {
1720
 
                if (xt_seek_eof_file(NULL, of) > INJECT_FLUSH_FILE_SIZE) {
1721
 
                        xt_register_ferrno(XT_REG_CONTEXT, 30, of->fr_file->fil_path);
1722
 
                        return FAILED;
1723
 
                }
1724
 
        }
1725
 
#endif
1726
 
 
1727
 
        switch (of->of_type) {
1728
 
                case XT_FT_NONE:
1729
 
                        break;
1730
 
                case XT_FT_REWRITE_FLUSH:
1731
 
                        XTRewriteFlushPtr       rf;
1732
 
                        RewriteBlockPtr         rec;
1733
 
                        size_t                          i;
1734
 
                        off_t                           offset;
1735
 
                        off_t                           size;
1736
 
                        off_t                           tfer;
1737
 
 
1738
 
                        rf = of->fr_file->x.fil_rewrite;
1739
 
 
1740
 
                        xt_lock_mutex_ns(&rf->rf_flush_lock);
1741
 
 
1742
 
                        /* Re-write all areas written: */
1743
 
                        xt_spinlock_lock(&rf->rf_lock);
1744
 
                        rf->rf_flush_block_count = rf->rf_block_count;
1745
 
                        memcpy(rf->rf_flush_blocks, rf->rf_blocks, rf->rf_flush_block_count * sizeof(RewriteBlockRec));
1746
 
                        rf->rf_block_count = 0;
1747
 
                        xt_spinlock_unlock(&rf->rf_lock);
1748
 
 
1749
 
                        /* Update the flush offset: */
1750
 
                        /* This lock ensures that there are no more writers: */
1751
 
                        RR_FLUSH_WRITE_LOCK(&rf->rf_write_lock, thread->t_id);
1752
 
                        /* We use atomic operations to ensure write through cache: */
1753
 
                        xt_atomic_set4(&rf->rf_flush_offset_lo, 0);
1754
 
                        xt_atomic_set4(&rf->rf_flush_offset_hi, 0);
1755
 
                        RR_FLUSH_UNLOCK(&rf->rf_write_lock, thread->t_id);
1756
 
 
1757
 
                        rec = rf->rf_flush_blocks;
1758
 
                        for (i=0; i<rf->rf_flush_block_count; i++) {
1759
 
                                size = rec->rb_size;
1760
 
                                offset = rec->rb_offset;
1761
 
                                while (size) {
1762
 
                                        tfer = XT_REWRITE_BUFFER_SIZE;
1763
 
                                        if (tfer > size)
1764
 
                                                tfer = size;
1765
 
                                        if (!fs_rewrite_file(of, offset, (size_t) tfer, rf->rf_flush_buffer, stat, thread)) {
1766
 
                                                RR_FLUSH_WRITE_LOCK(&rf->rf_write_lock, thread->t_id);
1767
 
                                                xt_atomic_set4(&rf->rf_flush_offset_lo, 0xFFFFFFFF);
1768
 
                                                xt_atomic_set4(&rf->rf_flush_offset_hi, 0xFFFFFFFF);
1769
 
                                                RR_FLUSH_UNLOCK(&rf->rf_write_lock, thread->t_id);
1770
 
                                                xt_unlock_mutex_ns(&rf->rf_flush_lock);
1771
 
                                                goto failed;
1772
 
                                        }
1773
 
                                        offset += tfer;
1774
 
                                        /* Update the flush offset: */
1775
 
                                        xt_atomic_set4(&rf->rf_flush_offset_lo, offset & 0xFFFFFFFF);
1776
 
                                        if (sizeof(off_t) > 4)
1777
 
                                                xt_atomic_set4(&rf->rf_flush_offset_hi, (xtWord4) (((xtWord8) offset >> 32) & 0xFFFFFFFF));
1778
 
                                        
1779
 
                                        size -= tfer;
1780
 
                                }
1781
 
                                rec++;
1782
 
                        }
1783
 
                        
1784
 
                        RR_FLUSH_WRITE_LOCK(&rf->rf_write_lock, thread->t_id);
1785
 
                        xt_atomic_set4(&rf->rf_flush_offset_lo, 0xFFFFFFFF);
1786
 
                        xt_atomic_set4(&rf->rf_flush_offset_hi, 0xFFFFFFFF);
1787
 
                        RR_FLUSH_UNLOCK(&rf->rf_write_lock, thread->t_id);
1788
 
                        xt_unlock_mutex_ns(&rf->rf_flush_lock);
1789
 
                        /* No break required. */
1790
 
                case XT_FT_STANDARD:
1791
 
                        stat->ts_flush_start = xt_trace_clock();
1792
 
#ifdef XT_WIN
1793
 
                        if (!FlushFileBuffers(of->x.of_filedes)) {
1794
 
                                xt_register_ferrno(XT_REG_CONTEXT, fs_get_win_error(), xt_file_path(of));
1795
 
                                goto failed;
1796
 
                        }
1797
 
#else
1798
 
                        /* Mac OS X has problems with fsync. We had several cases of 
1799
 
                         *index corruption presumably because fsync didn't really 
1800
 
                         * flush index pages to disk. fcntl(F_FULLFSYNC) is considered 
1801
 
                         * more effective in such case.
1802
 
                         */
1803
 
#if defined(F_FULLFSYNC) && !defined(DEBUG_FAST_MAC)
1804
 
                        if (fcntl(of->x.of_filedes, F_FULLFSYNC, 0) == -1) {
1805
 
                                xt_register_ferrno(XT_REG_CONTEXT, errno, xt_file_path(of));
1806
 
                                goto failed;
1807
 
                        }
1808
 
#else
1809
 
                        if (fsync(of->x.of_filedes) == -1) {
1810
 
                                xt_register_ferrno(XT_REG_CONTEXT, errno, xt_file_path(of));
1811
 
                                goto failed;
1812
 
                        }
1813
 
 
1814
 
#endif
1815
 
#endif
1816
 
                        break;
1817
 
                case XT_FT_MEM_MAP: {
1818
 
                        XTFileMemMapPtr mm = of->x.mf_memmap;
1819
 
                        xtThreadID              thd_id = thread->t_id;
1820
 
 
1821
 
                        if (!of->mf_slock_count)
1822
 
                                FILE_MAP_READ_LOCK(&mm->mm_lock, thd_id);
1823
 
                        if (!mm->mm_start) {
1824
 
                                FILE_MAP_UNLOCK(&mm->mm_lock, thd_id);
1825
 
                                ASSERT_NS(!of->mf_slock_count);
1826
 
                                FILE_MAP_WRITE_LOCK(&mm->mm_lock, thd_id);
1827
 
                                if (!fs_remap_file(of, 0, 0, stat)) {
1828
 
                                        if (!of->mf_slock_count)
1829
 
                                                FILE_MAP_UNLOCK(&mm->mm_lock, thd_id);
1830
 
                                        return FAILED;
1831
 
                                }
1832
 
                        }
1833
 
                        stat->ts_flush_start = xt_trace_clock();
1834
 
#ifdef XT_WIN
1835
 
                        if (!FlushViewOfFile(mm->mm_start, 0)) {
1836
 
                                xt_register_ferrno(XT_REG_CONTEXT, fs_get_win_error(), xt_file_path(of));
1837
 
                                if (!of->mf_slock_count)
1838
 
                                        FILE_MAP_UNLOCK(&mm->mm_lock, thd_id);
1839
 
                                goto failed;
1840
 
                        }
1841
 
#else
1842
 
                        if (msync( (char *)mm->mm_start, (size_t) mm->mm_length, MS_SYNC) == -1) {
1843
 
                                xt_register_ferrno(XT_REG_CONTEXT, errno, xt_file_path(of));
1844
 
                                if (!of->mf_slock_count)
1845
 
                                        FILE_MAP_UNLOCK(&mm->mm_lock, thd_id);
1846
 
                                goto failed;
1847
 
                        }
1848
 
#endif
1849
 
                        if (!of->mf_slock_count)
1850
 
                                FILE_MAP_UNLOCK(&mm->mm_lock, thd_id);
1851
 
                        break;
1852
 
                }
1853
 
                case XT_FT_HEAP:
1854
 
                        stat->ts_flush_start = xt_trace_clock();
1855
 
                        break;
1856
 
        }
1857
 
 
1858
 
#ifdef DEBUG_TRACE_IO
1859
 
        xt_trace("/* %s */ pbxt_file_sync(\"%s\");\n", xt_trace_clock_diff(timef, start), of->fr_file->fil_path);
1860
 
#endif
1861
 
#ifdef DEBUG_TRACE_AROUND
1862
 
        if (xt_is_extension(of->fr_file->fil_path, "xti"))
1863
 
                PRINTF("%s %s FLUSH (%d)\n", xt_trace_clock_str(timef), thread->t_name, (int) (xt_trace_clock() - start));
1864
 
#endif
1865
 
        s = stat->ts_flush_start;
1866
 
        stat->ts_flush_start = 0;
1867
 
        stat->ts_flush_time += xt_trace_clock() - s;
1868
 
        stat->ts_flush++;
1869
 
        return OK;
1870
 
 
1871
 
        failed:
1872
 
        s = stat->ts_flush_start;
1873
 
        stat->ts_flush_start = 0;
1874
 
        stat->ts_flush_time += xt_trace_clock() - s;
1875
 
        return FAILED;
1876
 
}
1877
 
 
1878
 
xtPublic xtBool xt_pread_file_4(XTOpenFilePtr of, off_t offset, xtWord4 *value, XTIOStatsPtr stat, XTThreadPtr thread)
1879
 
{
1880
 
        xtThreadID      thd_id;
1881
 
#ifdef XT_TIME_DISK_READS
1882
 
        xtWord8         s;
1883
 
#endif
1884
 
 
1885
 
#ifdef DEBUG_TRACE_MAP_IO
1886
 
        xt_trace("/* %s */ pbxt_fmap_read_4(\"%s\", %lu, 4);\n", xt_trace_clock_diff(NULL), of->fr_file->fil_path, (u_long) offset);
1887
 
#endif
1888
 
        switch (of->of_type) {
1889
 
                case XT_FT_NONE:
1890
 
                        break;
1891
 
                case XT_FT_REWRITE_FLUSH:
1892
 
                case XT_FT_STANDARD:
1893
 
                        xtWord1                 data4[4];
1894
 
#ifdef XT_TIME_DISK_READS
1895
 
                        stat->ts_read_start = xt_trace_clock();
1896
 
#endif
1897
 
#ifdef XT_WIN
1898
 
                        LARGE_INTEGER   liDistanceToMove;
1899
 
                        DWORD                   result;
1900
 
 
1901
 
                        liDistanceToMove.QuadPart = offset;
1902
 
                        if (!SetFilePointerEx(of->of_filedes, liDistanceToMove, NULL, FILE_BEGIN)) {
1903
 
                                xt_register_ferrno(XT_REG_CONTEXT, fs_get_win_error(), xt_file_path(of));
1904
 
                                goto failed;
1905
 
                        }
1906
 
 
1907
 
                        if (!ReadFile(of->of_filedes, data, 4, &result, NULL)) {
1908
 
                                xt_register_ferrno(XT_REG_CONTEXT, fs_get_win_error(), xt_file_path(of));
1909
 
                                goto failed;
1910
 
                        }
1911
 
 
1912
 
                        if ((size_t) result < 4) {
1913
 
                                xt_register_ferrno(XT_REG_CONTEXT, ERROR_HANDLE_EOF, xt_file_path(of));
1914
 
                                goto failed;
1915
 
                        }
1916
 
#else
1917
 
                        ssize_t read_size;
1918
 
 
1919
 
                        read_size = pread(of->x.of_filedes, data4, 4, offset);
1920
 
                        if (read_size == -1) {
1921
 
                                xt_register_ferrno(XT_REG_CONTEXT, errno, xt_file_path(of));
1922
 
                                goto failed;
1923
 
                        }
1924
 
 
1925
 
                        /* Throw an error if read less than the minimum: */
1926
 
                        if ((size_t) read_size < 4) {
1927
 
                                xt_register_ferrno(XT_REG_CONTEXT, ESPIPE, xt_file_path(of));
1928
 
                                goto failed;
1929
 
                        }
1930
 
#endif
1931
 
                        *value = XT_GET_DISK_4(data4);
1932
 
                        break;
1933
 
                case XT_FT_MEM_MAP: {
1934
 
                        XTFileMemMapPtr mm = of->x.mf_memmap;
1935
 
 
1936
 
                        thd_id = thread->t_id;
1937
 
                        if (!of->mf_slock_count)
1938
 
                                FILE_MAP_READ_LOCK(&mm->mm_lock, thd_id);
1939
 
                        if (!mm->mm_start) {
1940
 
                                ASSERT_NS(!of->mf_slock_count);
1941
 
                                FILE_MAP_UNLOCK(&mm->mm_lock, thd_id);
1942
 
                                FILE_MAP_WRITE_LOCK(&mm->mm_lock, thd_id);
1943
 
                                if (!fs_remap_file(of, 0, 0, stat)) {
1944
 
                                        FILE_MAP_UNLOCK(&mm->mm_lock, thd_id);
1945
 
                                        return FAILED;
1946
 
                                }
1947
 
                        }
1948
 
                        if (offset >= mm->mm_length)
1949
 
                                *value = 0;
1950
 
                        else {
1951
 
                                xtWord1 *data;
1952
 
 
1953
 
                                data = mm->mm_start + offset;
1954
 
#ifdef XT_TIME_DISK_READS
1955
 
                                stat->ts_read_start = xt_trace_clock();
1956
 
#endif
1957
 
#ifdef XT_WIN
1958
 
                                __try
1959
 
                                {
1960
 
                                        *value = XT_GET_DISK_4(data);
1961
 
                                        // GetExceptionCode()== EXCEPTION_IN_PAGE_ERROR ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH
1962
 
                                }
1963
 
                                __except(EXCEPTION_EXECUTE_HANDLER)
1964
 
                                {
1965
 
                                        FILE_MAP_UNLOCK(&mm->mm_lock, thd_id);
1966
 
                                        xt_register_ferrno(XT_REG_CONTEXT, GetExceptionCode(), xt_file_path(of));
1967
 
                                        goto failed;
1968
 
                                }
1969
 
#else
1970
 
                                *value = XT_GET_DISK_4(data);
1971
 
#endif
1972
 
                        }
1973
 
 
1974
 
                        if (!of->mf_slock_count)
1975
 
                                FILE_MAP_UNLOCK(&mm->mm_lock, thd_id);
1976
 
                        break;
1977
 
                }
1978
 
                case XT_FT_HEAP: {
1979
 
                        XTFileHeapPtr   fh = of->x.of_heap;
1980
 
 
1981
 
                        thd_id = thread->t_id;
1982
 
 
1983
 
#ifdef XT_TIME_DISK_READS
1984
 
                        stat->ts_read_start = xt_trace_clock();
1985
 
#endif
1986
 
                        if (!of->mf_slock_count)
1987
 
                                FILE_MAP_READ_LOCK(&fh->fh_lock, thd_id);
1988
 
                        if (!fh->fh_start) {
1989
 
                                ASSERT_NS(!of->mf_slock_count);
1990
 
                                FILE_MAP_UNLOCK(&fh->fh_lock, thd_id);
1991
 
                                FILE_MAP_WRITE_LOCK(&fh->fh_lock, thd_id);
1992
 
                                if (!fs_remap_file(of, 0, 0, stat)) {
1993
 
                                        FILE_MAP_UNLOCK(&fh->fh_lock, thd_id);
1994
 
                                        goto failed;
1995
 
                                }
1996
 
                        }
1997
 
                        if (offset >= fh->fh_length)
1998
 
                                *value = 0;
1999
 
                        else {
2000
 
                                xtWord1 *data;
2001
 
 
2002
 
                                data = fh->fh_start + offset;
2003
 
                                *value = XT_GET_DISK_4(data);
2004
 
                        }
2005
 
                        if (!of->mf_slock_count)
2006
 
                                FILE_MAP_UNLOCK(&fh->fh_lock, thd_id);
2007
 
                        break;
2008
 
                }
2009
 
        }
2010
 
 
2011
 
#ifdef XT_TIME_DISK_READS
2012
 
        s = stat->ts_read_start;
2013
 
        stat->ts_read_start = 0;
2014
 
        stat->ts_read_time += xt_trace_clock() - s;
2015
 
#endif
2016
 
        stat->ts_read += 4;
2017
 
        return OK;
2018
 
 
2019
 
        failed:
2020
 
#ifdef XT_TIME_DISK_READS
2021
 
        s = stat->ts_read_start;
2022
 
        stat->ts_read_start = 0;
2023
 
        stat->ts_read_time += xt_trace_clock() - s;
2024
 
#endif
2025
 
        return FAILED;
2026
 
}
2027
 
 
2028
 
xtBool xt_pread_file(XTOpenFilePtr of, off_t offset, size_t size, size_t min_size, void *data, size_t *red_size, XTIOStatsPtr stat, XTThreadPtr thread)
2029
 
{
2030
 
        xtThreadID      thd_id;
2031
 
        size_t          tfer = 0;
2032
 
#ifdef XT_TIME_DISK_READS
2033
 
        xtWord8         s;
2034
 
#endif
2035
 
 
2036
 
#if defined(DEBUG_TRACE_IO) || defined(DEBUG_TRACE_AROUND)
2037
 
        char    timef[50];
2038
 
        xtWord8 start = xt_trace_clock();
2039
 
#endif
2040
 
#ifdef DEBUG_TRACE_AROUND
2041
 
        if (xt_is_extension(of->fr_file->fil_path, "xti"))
2042
 
                PRINTF("%s %s read\n", xt_trace_clock_str(timef), thread->t_name);
2043
 
#endif
2044
 
 
2045
 
        switch (of->of_type) {
2046
 
                case XT_FT_NONE:
2047
 
                        break;
2048
 
                case XT_FT_REWRITE_FLUSH:
2049
 
                case XT_FT_STANDARD:
2050
 
#ifdef XT_TIME_DISK_READS
2051
 
                        stat->ts_read_start = xt_trace_clock();
2052
 
#endif
2053
 
#ifdef XT_WIN
2054
 
                        LARGE_INTEGER   liDistanceToMove;
2055
 
                        DWORD                   result;
2056
 
 
2057
 
                        liDistanceToMove.QuadPart = offset;
2058
 
                        if (!SetFilePointerEx(of->of_filedes, liDistanceToMove, NULL, FILE_BEGIN)) {
2059
 
                                xt_register_ferrno(XT_REG_CONTEXT, fs_get_win_error(), xt_file_path(of));
2060
 
                                goto failed;
2061
 
                        }
2062
 
 
2063
 
                        if (!ReadFile(of->of_filedes, data, size, &result, NULL)) {
2064
 
                                xt_register_ferrno(XT_REG_CONTEXT, fs_get_win_error(), xt_file_path(of));
2065
 
                                goto failed;
2066
 
                        }
2067
 
 
2068
 
                        tfer = (size_t) result;
2069
 
#else
2070
 
                        ssize_t                 result;
2071
 
 
2072
 
                        result = pread(of->x.of_filedes, data, size, offset);
2073
 
                        if (result == -1) {
2074
 
                                xt_register_ferrno(XT_REG_CONTEXT, errno, xt_file_path(of));
2075
 
                                goto failed;
2076
 
                        }
2077
 
 
2078
 
                        tfer = (size_t) result;
2079
 
#endif
2080
 
                        break;
2081
 
                case XT_FT_MEM_MAP: {
2082
 
                        XTFileMemMapPtr mm = of->x.mf_memmap;
2083
 
 
2084
 
                        thd_id = thread->t_id;
2085
 
                        /* NOTE!! The file map may already be locked,
2086
 
                         * by a call to xt_lock_fmap_ptr()!
2087
 
                         *
2088
 
                         * 20.05.2009: This problem should be fixed now with mf_slock_count!
2089
 
                         *
2090
 
                         * This can occur during a sequential scan:
2091
 
                         * xt_pread_fmap()  Line 1330
2092
 
                         * XTTabCache::tc_read_direct()  Line 361
2093
 
                         * XTTabCache::xt_tc_read()  Line 220
2094
 
                         * xt_tab_get_rec_data()
2095
 
                         * tab_visible()  Line 2412
2096
 
                         * xt_tab_seq_next()  Line 4068
2097
 
                         *
2098
 
                         * And occurs during the following test:
2099
 
                         * create table t1 ( a int not null, b int not null) ;
2100
 
                         * --disable_query_log
2101
 
                         * insert into t1 values (1,1),(2,2),(3,3),(4,4);
2102
 
                         * let $1=19;
2103
 
                         * set @d=4;
2104
 
                         * while ($1)
2105
 
                         * {
2106
 
                         *   eval insert into t1 select a+@d,b+@d from t1;
2107
 
                         *   eval set @d=@d*2;
2108
 
                         *   dec $1;
2109
 
                         * }
2110
 
                         * 
2111
 
                         * --enable_query_log
2112
 
                         * alter table t1 add index i1(a);
2113
 
                         * delete from t1 where a > 2000000;
2114
 
                         * create table t2 like t1;
2115
 
                         * insert into t2 select * from t1;
2116
 
                         *
2117
 
                         * As a result, the slock must be able to handle
2118
 
                         * nested calls to lock/unlock.
2119
 
                         */
2120
 
                        if (!of->mf_slock_count)
2121
 
                                FILE_MAP_READ_LOCK(&mm->mm_lock, thd_id);
2122
 
                        tfer = size;
2123
 
                        if (!mm->mm_start) {
2124
 
                                FILE_MAP_UNLOCK(&mm->mm_lock, thd_id);
2125
 
                                ASSERT_NS(!of->mf_slock_count);
2126
 
                                FILE_MAP_WRITE_LOCK(&mm->mm_lock, thd_id);
2127
 
                                if (!fs_remap_file(of, 0, 0, stat)) {
2128
 
                                        if (!of->mf_slock_count)
2129
 
                                                FILE_MAP_UNLOCK(&mm->mm_lock, thd_id);
2130
 
                                        return FAILED;
2131
 
                                }
2132
 
                        }
2133
 
                        if (offset >= mm->mm_length)
2134
 
                                tfer = 0;
2135
 
                        else {
2136
 
                                if (mm->mm_length - offset < (off_t) tfer)
2137
 
                                        tfer = (size_t) (mm->mm_length - offset);
2138
 
#ifdef XT_TIME_DISK_READS
2139
 
                                stat->ts_read_start = xt_trace_clock();
2140
 
#endif
2141
 
#ifdef XT_WIN
2142
 
                                __try
2143
 
                                {
2144
 
                                        memcpy(data, mm->mm_start + offset, tfer);
2145
 
                                        // GetExceptionCode()== EXCEPTION_IN_PAGE_ERROR ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH
2146
 
                                }
2147
 
                                __except(EXCEPTION_EXECUTE_HANDLER)
2148
 
                                {
2149
 
                                        if (!of->mf_slock_count)
2150
 
                                                FILE_MAP_UNLOCK(&mm->mm_lock, thd_id);
2151
 
                                        xt_register_ferrno(XT_REG_CONTEXT, GetExceptionCode(), xt_file_path(of));
2152
 
                                        goto failed;
2153
 
                                }
2154
 
#else
2155
 
                                memcpy(data, mm->mm_start + offset, tfer);
2156
 
#endif
2157
 
                        }
2158
 
                        if (!of->mf_slock_count)
2159
 
                                FILE_MAP_UNLOCK(&mm->mm_lock, thd_id);
2160
 
                        break;
2161
 
                }
2162
 
                case XT_FT_HEAP: {
2163
 
                        XTFileHeapPtr   fh = of->x.of_heap;
2164
 
 
2165
 
#ifdef XT_TIME_DISK_READS
2166
 
                        stat->ts_read_start = xt_trace_clock();
2167
 
#endif
2168
 
                        thd_id  = thread->t_id;
2169
 
                        if (!of->mf_slock_count)
2170
 
                                FILE_MAP_READ_LOCK(&fh->fh_lock, thd_id);
2171
 
                        tfer = size;
2172
 
                        if (offset >= fh->fh_length)
2173
 
                                tfer = 0;
2174
 
                        else {
2175
 
                                if (fh->fh_length - offset < (off_t) tfer)
2176
 
                                        tfer = (size_t) (fh->fh_length - offset);
2177
 
                                memcpy(data, fh->fh_start + offset, tfer);
2178
 
                        }
2179
 
                        if (!of->mf_slock_count)
2180
 
                                FILE_MAP_UNLOCK(&fh->fh_lock, thd_id);
2181
 
                        break;
2182
 
                }
2183
 
        }
2184
 
 
2185
 
#ifdef XT_TIME_DISK_READS
2186
 
        s = stat->ts_read_start;
2187
 
        stat->ts_read_start = 0;
2188
 
        stat->ts_read_time += xt_trace_clock() - s;
2189
 
#endif
2190
 
        stat->ts_read += tfer;
2191
 
 
2192
 
        /* Throw an error if read less than the minimum: */
2193
 
        if (tfer < min_size)
2194
 
                return xt_register_ferrno(XT_REG_CONTEXT, ESPIPE, xt_file_path(of));
2195
 
        if (red_size)
2196
 
                *red_size = tfer;
2197
 
#ifdef DEBUG_TRACE_IO
2198
 
        xt_trace("/* %s */ pbxt_file_read(\"%s\", %lu, %lu);\n", xt_trace_clock_diff(timef, start), of->fr_file->fil_path, (u_long) offset, (u_long) size);
2199
 
#endif
2200
 
#ifdef DEBUG_TRACE_AROUND
2201
 
        if (xt_is_extension(of->fr_file->fil_path, "xti"))
2202
 
                PRINTF("%s %s read (%d)\n", xt_trace_clock_str(timef), thread->t_name, (int) (xt_trace_clock() - start));
2203
 
#endif
2204
 
        return OK;
2205
 
 
2206
 
        failed:
2207
 
#ifdef XT_TIME_DISK_READS
2208
 
        s = stat->ts_read_start;
2209
 
        stat->ts_read_start = 0;
2210
 
        stat->ts_read_time += xt_trace_clock() - s;
2211
 
#endif
2212
 
        return FAILED;
2213
 
}
2214
 
 
2215
 
xtPublic xtBool xt_lock_file_ptr(XTOpenFilePtr of, xtWord1 **data, off_t offset, size_t size, XTIOStatsPtr stat, XTThreadPtr thread)
2216
 
{
2217
 
        switch (of->of_type) {
2218
 
                case XT_FT_NONE:
2219
 
                        break;
2220
 
                case XT_FT_REWRITE_FLUSH:
2221
 
                case XT_FT_STANDARD:
2222
 
                        size_t red_size;
2223
 
                
2224
 
                        if (!*data) {
2225
 
                                if (!(*data = (xtWord1 *) xt_malloc_ns(size)))
2226
 
                                        return FAILED;
2227
 
                        }
2228
 
 
2229
 
                        if (!xt_pread_file(of, offset, size, 0, *data, &red_size, stat, thread))
2230
 
                                return FAILED;
2231
 
                        
2232
 
                        //if (red_size < size)
2233
 
                        //      memset();
2234
 
                        break;
2235
 
                case XT_FT_MEM_MAP: {
2236
 
                        XTFileMemMapPtr mm = of->x.mf_memmap;
2237
 
                        xtThreadID              thd_id = thread->t_id;
2238
 
 
2239
 
                        if (!of->mf_slock_count)
2240
 
                                FILE_MAP_READ_LOCK(&mm->mm_lock, thd_id);
2241
 
                        of->mf_slock_count++;
2242
 
                        if (!mm->mm_start) {
2243
 
                                FILE_MAP_UNLOCK(&mm->mm_lock, thd_id);
2244
 
                                ASSERT_NS(of->mf_slock_count == 1);
2245
 
                                FILE_MAP_WRITE_LOCK(&mm->mm_lock, thd_id);
2246
 
                                if (!fs_remap_file(of, 0, 0, stat)) {
2247
 
                                        of->mf_slock_count--;
2248
 
                                        if (!of->mf_slock_count)
2249
 
                                                FILE_MAP_UNLOCK(&mm->mm_lock, thd_id);
2250
 
                                        return FAILED;
2251
 
                                }
2252
 
                        }
2253
 
                        if (offset >= mm->mm_length) {
2254
 
                                of->mf_slock_count--;
2255
 
                                if (!of->mf_slock_count)
2256
 
                                        FILE_MAP_UNLOCK(&mm->mm_lock, thd_id);
2257
 
                                return FAILED;
2258
 
                        }
2259
 
                        
2260
 
                        if (offset + (off_t) size > mm->mm_length)
2261
 
                                stat->ts_read += (u_int) (offset + (off_t) size - mm->mm_length);
2262
 
                        else
2263
 
                                stat->ts_read += size;
2264
 
                        *data = mm->mm_start + offset;
2265
 
                        break;
2266
 
                }
2267
 
                case XT_FT_HEAP: {
2268
 
                        XTFileHeapPtr   fh = of->x.of_heap;
2269
 
                        xtThreadID              thd_id = thread->t_id;
2270
 
 
2271
 
                        if (!of->mf_slock_count)
2272
 
                                FILE_MAP_READ_LOCK(&fh->fh_lock, thd_id);
2273
 
                        of->mf_slock_count++;
2274
 
                        if (!fh->fh_start) {
2275
 
                                FILE_MAP_UNLOCK(&fh->fh_lock, thd_id);
2276
 
                                ASSERT_NS(of->mf_slock_count == 1);
2277
 
                                FILE_MAP_WRITE_LOCK(&fh->fh_lock, thd_id);
2278
 
                                if (!fs_remap_file(of, 0, 0, stat)) {
2279
 
                                        of->mf_slock_count--;
2280
 
                                        if (!of->mf_slock_count)
2281
 
                                                FILE_MAP_UNLOCK(&fh->fh_lock, thd_id);
2282
 
                                        return FAILED;
2283
 
                                }
2284
 
                        }
2285
 
                        if (offset >= fh->fh_length) {
2286
 
                                of->mf_slock_count--;
2287
 
                                if (!of->mf_slock_count)
2288
 
                                        FILE_MAP_UNLOCK(&fh->fh_lock, thd_id);
2289
 
                                return FAILED;
2290
 
                        }
2291
 
                        
2292
 
                        if (offset + (off_t) size > fh->fh_length)
2293
 
                                stat->ts_read += (u_int) (offset + (off_t) size - fh->fh_length);
2294
 
                        else
2295
 
                                stat->ts_read += size;
2296
 
                        *data = fh->fh_start + offset;
2297
 
                        break;
2298
 
                }
2299
 
        }
2300
 
 
2301
 
        return OK;
2302
 
}
2303
 
 
2304
 
// Depending on platform 'thread->t_id' may not be used by FILE_MAP_UNLOCK().
2305
 
xtPublic void xt_unlock_file_ptr(XTOpenFilePtr of, xtWord1 *data, XTThreadPtr thread __attribute__((unused)))
2306
 
{
2307
 
        switch (of->of_type) {
2308
 
                case XT_FT_NONE:
2309
 
                        break;
2310
 
                case XT_FT_REWRITE_FLUSH:
2311
 
                case XT_FT_STANDARD:
2312
 
                        if (data)
2313
 
                                xt_free_ns(data);
2314
 
                        break;
2315
 
                case XT_FT_MEM_MAP:
2316
 
                        of->mf_slock_count--;
2317
 
                        if (!of->mf_slock_count)
2318
 
                                FILE_MAP_UNLOCK(&of->x.mf_memmap->mm_lock, thread->t_id);
2319
 
                        break;
2320
 
                case XT_FT_HEAP:
2321
 
                        of->mf_slock_count--;
2322
 
                        if (!of->mf_slock_count)
2323
 
                                FILE_MAP_UNLOCK(&of->x.of_heap->fh_lock, thread->t_id);
2324
 
                        break;
2325
 
        }
2326
 
}
2327
 
 
2328
 
/* ----------------------------------------------------------------------
2329
 
 * Directory operations
2330
 
 */
2331
 
 
2332
 
/*
2333
 
 * The filter may contain one '*' as wildcard.
2334
 
 */
2335
 
XTOpenDirPtr xt_dir_open(XTThreadPtr self, c_char *path, c_char *filter)
2336
 
{
2337
 
        XTOpenDirPtr    od;
2338
 
 
2339
 
#ifdef XT_SOLARIS
2340
 
        /* see the comment in filesys_xt.h */
2341
 
        size_t sz = pathconf(path, _PC_NAME_MAX) + sizeof(XTOpenDirRec) + 1;
2342
 
#else
2343
 
        size_t sz = sizeof(XTOpenDirRec);
2344
 
#endif
2345
 
        pushsr_(od, xt_dir_close, (XTOpenDirPtr) xt_calloc(self, sz));
2346
 
 
2347
 
#ifdef XT_WIN
2348
 
        size_t                  len;
2349
 
 
2350
 
        od->od_handle = XT_NULL_FD;
2351
 
 
2352
 
        // path = path\(filter | *)
2353
 
        len = strlen(path) + 1 + (filter ? strlen(filter) : 1) + 1;
2354
 
        od->od_path = (char *) xt_malloc(self, len);
2355
 
 
2356
 
        strcpy(od->od_path, path);
2357
 
        xt_add_dir_char(len, od->od_path);
2358
 
        if (filter)
2359
 
                strcat(od->od_path, filter);
2360
 
        else
2361
 
                strcat(od->od_path, "*");
2362
 
#else
2363
 
        od->od_path = xt_dup_string(self, path);
2364
 
 
2365
 
        if (filter)
2366
 
                od->od_filter = xt_dup_string(self, filter);
2367
 
 
2368
 
        od->od_dir = opendir(path);
2369
 
        if (!od->od_dir)
2370
 
                xt_throw_ferrno(XT_CONTEXT, errno, path);
2371
 
#endif
2372
 
        popr_(); // Discard xt_dir_close(od)
2373
 
        return od;
2374
 
}
2375
 
 
2376
 
void xt_dir_close(XTThreadPtr self, XTOpenDirPtr od)
2377
 
{
2378
 
        if (od) {
2379
 
#ifdef XT_WIN
2380
 
                if (od->od_handle != XT_NULL_FD) {
2381
 
                        FindClose(od->od_handle);
2382
 
                        od->od_handle = XT_NULL_FD;
2383
 
                }
2384
 
#else
2385
 
                if (od->od_dir) {
2386
 
                        closedir(od->od_dir);
2387
 
                        od->od_dir = NULL;
2388
 
                }
2389
 
                if (od->od_filter) {
2390
 
                        xt_free(self, od->od_filter);
2391
 
                        od->od_filter = NULL;
2392
 
                }
2393
 
#endif
2394
 
                if (od->od_path) {
2395
 
                        xt_free(self, od->od_path);
2396
 
                        od->od_path = NULL;
2397
 
                }
2398
 
                xt_free(self, od);
2399
 
        }
2400
 
}
2401
 
 
2402
 
#ifdef XT_WIN
2403
 
xtBool xt_dir_next(XTThreadPtr self, XTOpenDirPtr od)
2404
 
{
2405
 
        int err = 0;
2406
 
 
2407
 
        if (od->od_handle == INVALID_HANDLE_VALUE) {
2408
 
                od->od_handle = FindFirstFile(od->od_path, &od->od_data);
2409
 
                if (od->od_handle == INVALID_HANDLE_VALUE)
2410
 
                        err = fs_get_win_error();
2411
 
        }
2412
 
        else {
2413
 
                if (!FindNextFile(od->od_handle, &od->od_data))
2414
 
                        err = fs_get_win_error();
2415
 
        }
2416
 
 
2417
 
        if (err) {
2418
 
                if (err != ERROR_NO_MORE_FILES) {
2419
 
                        if (err == ERROR_FILE_NOT_FOUND) {
2420
 
                                char path[PATH_MAX];
2421
 
 
2422
 
                                xt_strcpy(PATH_MAX, path, od->od_path);
2423
 
                                xt_remove_last_name_of_path(path);
2424
 
                                if (!fs_exists(path, self))
2425
 
                                        xt_throw_ferrno(XT_CONTEXT, err, path);
2426
 
                        }
2427
 
                        else
2428
 
                                xt_throw_ferrno(XT_CONTEXT, err, od->od_path);
2429
 
                }
2430
 
                return FAILED;
2431
 
        }
2432
 
 
2433
 
        return OK;
2434
 
}
2435
 
#else
2436
 
static xtBool fs_match_filter(c_char *name, c_char *filter)
2437
 
{
2438
 
        while (*name && *filter) {
2439
 
                if (*filter == '*') {
2440
 
                        if (filter[1] == *name)
2441
 
                                filter++;
2442
 
                        else
2443
 
                                name++;
2444
 
                }
2445
 
                else {
2446
 
                        if (*name != *filter)
2447
 
                                return FALSE;
2448
 
                        name++;
2449
 
                        filter++;
2450
 
                }
2451
 
        }
2452
 
        if (!*name) {
2453
 
                if (!*filter || (*filter == '*' && !filter[1]))
2454
 
                        return TRUE;
2455
 
        }
2456
 
        return FALSE;
2457
 
}
2458
 
 
2459
 
xtBool xt_dir_next(XTThreadPtr self, XTOpenDirPtr od)
2460
 
{
2461
 
        int                             err;
2462
 
        struct dirent   *result;
2463
 
 
2464
 
        for (;;) {
2465
 
                err = readdir_r(od->od_dir, &od->od_entry, &result);
2466
 
                if (err) {
2467
 
                        xt_throw_ferrno(XT_CONTEXT, err, od->od_path);
2468
 
                        return FAILED;
2469
 
                }
2470
 
                if (!result)
2471
 
                        break;
2472
 
                /* Filter out '.' and '..': */
2473
 
                if (od->od_entry.d_name[0] == '.') {
2474
 
                        if (od->od_entry.d_name[1] == '.') {
2475
 
                                if (od->od_entry.d_name[2] == '\0')
2476
 
                                        continue;
2477
 
                        }
2478
 
                        else {
2479
 
                                if (od->od_entry.d_name[1] == '\0')
2480
 
                                        continue;
2481
 
                        }
2482
 
                }
2483
 
                if (!od->od_filter)
2484
 
                        break;
2485
 
                if (fs_match_filter(od->od_entry.d_name, od->od_filter))
2486
 
                        break;
2487
 
        }
2488
 
        return result ? TRUE : FALSE;
2489
 
}
2490
 
#endif
2491
 
 
2492
 
char *xt_dir_name(XTThreadPtr XT_UNUSED(self), XTOpenDirPtr od)
2493
 
{
2494
 
#ifdef XT_WIN
2495
 
        return od->od_data.cFileName;
2496
 
#else
2497
 
        return od->od_entry.d_name;
2498
 
#endif
2499
 
}
2500
 
 
2501
 
xtBool xt_dir_is_file(XTThreadPtr self, XTOpenDirPtr od)
2502
 
{
2503
 
        (void) self;
2504
 
#ifdef XT_WIN
2505
 
        if (od->od_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
2506
 
                return FALSE;
2507
 
#elif defined(XT_SOLARIS)
2508
 
        char path[PATH_MAX];
2509
 
        struct stat sb;
2510
 
 
2511
 
        xt_strcpy(PATH_MAX, path, od->od_path);
2512
 
        xt_add_dir_char(PATH_MAX, path);
2513
 
        xt_strcat(PATH_MAX, path, od->od_entry.d_name);
2514
 
 
2515
 
        if (stat(path, &sb) == -1) {
2516
 
                xt_throw_ferrno(XT_CONTEXT, errno, path);
2517
 
                return FAILED;
2518
 
        }
2519
 
 
2520
 
        if ( sb.st_mode & S_IFDIR )
2521
 
                return FALSE;
2522
 
#else
2523
 
        if (od->od_entry.d_type & DT_DIR)
2524
 
                return FALSE;
2525
 
#endif
2526
 
        return TRUE;
2527
 
}
2528
 
 
2529
 
off_t xt_dir_file_size(XTThreadPtr self, XTOpenDirPtr od)
2530
 
{
2531
 
#ifdef XT_WIN
2532
 
        return (off_t) od->od_data.nFileSizeLow | (((off_t) od->od_data.nFileSizeHigh) << 32);
2533
 
#else
2534
 
        char    path[PATH_MAX];
2535
 
        off_t   size;
2536
 
 
2537
 
        xt_strcpy(PATH_MAX, path, od->od_path);
2538
 
        xt_add_dir_char(PATH_MAX, path);
2539
 
        xt_strcat(PATH_MAX, path, od->od_entry.d_name);
2540
 
        if (!xt_fs_stat(self, path, &size, NULL))
2541
 
                return -1;
2542
 
        return size;
2543
 
#endif
2544
 
}
2545
 
 
2546
 
/* ----------------------------------------------------------------------
2547
 
 * File mapping operations
2548
 
 */
2549
 
 
2550
 
static xtBool fs_map_file(XTFileMemMapPtr mm, XTFilePtr file, xtBool grow)
2551
 
{
2552
 
#ifdef INJECT_WRITE_REMAP_ERROR
2553
 
        if (xt_is_extension(file->fil_path, INJECT_REMAP_FILE_TYPE)) {
2554
 
                if (mm->mm_length > INJECT_REMAP_FILE_SIZE) {
2555
 
                        xt_register_ferrno(XT_REG_CONTEXT, 30, file->fil_path);
2556
 
                        return FAILED;
2557
 
                }
2558
 
        }
2559
 
#endif
2560
 
        ASSERT_NS(!mm->mm_start);
2561
 
#ifdef XT_WIN
2562
 
        /* This will grow the file to the given size: */
2563
 
        mm->mm_mapdes = CreateFileMapping(file->fil_filedes, NULL, PAGE_READWRITE, (DWORD) (mm->mm_length >> 32), (DWORD) mm->mm_length, NULL);
2564
 
        if (mm->mm_mapdes == NULL) {
2565
 
                xt_register_ferrno(XT_REG_CONTEXT, fs_get_win_error(), file->fil_path);
2566
 
                return FAILED;
2567
 
        }
2568
 
 
2569
 
        mm->mm_start = (xtWord1 *) MapViewOfFile(mm->mm_mapdes, FILE_MAP_WRITE, 0, 0, 0);
2570
 
        if (!mm->mm_start) {
2571
 
                CloseHandle(mm->mm_mapdes);
2572
 
                mm->mm_mapdes = NULL;
2573
 
                xt_register_ferrno(XT_REG_CONTEXT, fs_get_win_error(), file->fil_path);
2574
 
                return FAILED;
2575
 
        }
2576
 
#else
2577
 
        if (grow) {
2578
 
                char data[2];
2579
 
 
2580
 
                if (pwrite(file->fil_filedes, data, 1, mm->mm_length - 1) == -1) {
2581
 
                        xt_register_ferrno(XT_REG_CONTEXT, errno, file->fil_path);
2582
 
                        return FAILED;
2583
 
                }
2584
 
        }
2585
 
 
2586
 
        /* Remap: */
2587
 
        mm->mm_start = (xtWord1 *) mmap(0, (size_t) mm->mm_length, PROT_READ | PROT_WRITE, MAP_SHARED, file->fil_filedes, 0);
2588
 
        if (mm->mm_start == MAP_FAILED) {
2589
 
                mm->mm_start = NULL;
2590
 
                xt_register_ferrno(XT_REG_CONTEXT, errno, file->fil_path);
2591
 
                return FAILED;
2592
 
        }
2593
 
#endif
2594
 
        return OK;
2595
 
}
2596
 
 
2597
 
static xtBool fs_remap_file(XTOpenFilePtr map, off_t offset, size_t size, XTIOStatsPtr stat)
2598
 
{
2599
 
        off_t                   new_size = 0;
2600
 
        XTFileMemMapPtr mm = map->x.mf_memmap;
2601
 
        xtWord8                 s;
2602
 
 
2603
 
        if (offset + (off_t) size > mm->mm_length) {
2604
 
                /* Expand the file: */
2605
 
                new_size = (mm->mm_length + (off_t) mm->mm_grow_size) / (off_t) mm->mm_grow_size;
2606
 
                new_size *= mm->mm_grow_size;
2607
 
                while (new_size < offset + (off_t) size)
2608
 
                        new_size += mm->mm_grow_size;
2609
 
 
2610
 
                if (sizeof(size_t) == 4 && new_size >= (off_t) 0xFFFFFFFF) {
2611
 
                        xt_register_ixterr(XT_REG_CONTEXT, XT_ERR_FILE_TOO_LONG, xt_file_path(map));
2612
 
                        return FAILED;
2613
 
                }
2614
 
        }
2615
 
        else if (!mm->mm_start)
2616
 
                new_size = mm->mm_length;
2617
 
 
2618
 
        if (new_size) {
2619
 
                if (mm->mm_start) {
2620
 
                        /* Flush & unmap: */
2621
 
                        stat->ts_flush_start = xt_trace_clock();
2622
 
#ifdef XT_WIN
2623
 
                        if (!FlushViewOfFile(mm->mm_start, 0)) {
2624
 
                                xt_register_ferrno(XT_REG_CONTEXT, fs_get_win_error(), xt_file_path(map));
2625
 
                                goto failed;
2626
 
                        }
2627
 
 
2628
 
                        if (!UnmapViewOfFile(mm->mm_start)) {
2629
 
                                xt_register_ferrno(XT_REG_CONTEXT, fs_get_win_error(), xt_file_path(map));
2630
 
                                goto failed;
2631
 
                        }
2632
 
#else
2633
 
                        if (msync( (char *)mm->mm_start, (size_t) mm->mm_length, MS_SYNC) == -1) {
2634
 
                                xt_register_ferrno(XT_REG_CONTEXT, errno, xt_file_path(map));
2635
 
                                goto failed;
2636
 
                        }
2637
 
 
2638
 
                        /* Unmap: */
2639
 
                        if (munmap((caddr_t) mm->mm_start, (size_t) mm->mm_length) == -1) {
2640
 
                                xt_register_ferrno(XT_REG_CONTEXT, errno, xt_file_path(map));
2641
 
                                goto failed;
2642
 
                        }
2643
 
#endif
2644
 
                        s = stat->ts_flush_start;
2645
 
                        stat->ts_flush_start = 0;
2646
 
                        stat->ts_flush_time += xt_trace_clock() - s;
2647
 
                        stat->ts_flush++;
2648
 
                }
2649
 
                mm->mm_start = NULL;
2650
 
#ifdef XT_WIN
2651
 
                /* It is possible that a previous remap attempt has failed: the map was closed
2652
 
                 * but the new map was not allocated (e.g. because of insufficient disk space). 
2653
 
                 * In this case mm->mm_mapdes will be NULL.
2654
 
                 */
2655
 
                if (mm->mm_mapdes && !CloseHandle(mm->mm_mapdes))
2656
 
                        return xt_register_ferrno(XT_REG_CONTEXT, fs_get_win_error(), xt_file_path(map));
2657
 
                mm->mm_mapdes = NULL;
2658
 
#endif
2659
 
                off_t old_size = mm->mm_length;
2660
 
                mm->mm_length = new_size;
2661
 
 
2662
 
                if (!fs_map_file(mm, map->fr_file, TRUE)) {
2663
 
                        /* Try to restore old mapping */
2664
 
                        mm->mm_length = old_size;
2665
 
                        fs_map_file(mm, map->fr_file, FALSE);
2666
 
                        goto failed;
2667
 
                }
2668
 
        }
2669
 
        return OK;
2670
 
        
2671
 
        failed:
2672
 
        s = stat->ts_flush_start;
2673
 
        stat->ts_flush_start = 0;
2674
 
        stat->ts_flush_time += xt_trace_clock() - s;
2675
 
        return FAILED;
2676
 
}
2677
 
 
2678
 
/* ----------------------------------------------------------------------
2679
 
 * Copy files/directories
2680
 
 */
2681
 
 
2682
 
static void fs_copy_file(XTThreadPtr self, char *from_path, char *to_path, void *copy_buf)
2683
 
{
2684
 
        XTOpenFilePtr   from;
2685
 
        XTOpenFilePtr   to;
2686
 
        off_t                   offset = 0;
2687
 
        size_t                  read_size= 0;
2688
 
 
2689
 
        from = xt_open_file(self, from_path, XT_FT_STANDARD, XT_FS_READONLY, 16*1024);
2690
 
        pushr_(xt_close_file, from);
2691
 
        to = xt_open_file(self, to_path, XT_FT_STANDARD, XT_FS_CREATE | XT_FS_MAKE_PATH, 16*1024);
2692
 
        pushr_(xt_close_file, to);
2693
 
 
2694
 
        for (;;) {
2695
 
                if (!xt_pread_file(from, offset, 16*1024, 0, copy_buf, &read_size, &self->st_statistics.st_x, self))
2696
 
                        xt_throw(self);
2697
 
                if (!read_size)
2698
 
                        break;
2699
 
                if (!xt_pwrite_file(to, offset, read_size, copy_buf, &self->st_statistics.st_x, self))
2700
 
                        xt_throw(self);
2701
 
                offset += (off_t) read_size;
2702
 
        }
2703
 
 
2704
 
        freer_();
2705
 
        freer_();
2706
 
}
2707
 
 
2708
 
xtPublic void xt_fs_copy_file(XTThreadPtr self, char *from_path, char *to_path)
2709
 
{
2710
 
        void *buffer;
2711
 
 
2712
 
        buffer = xt_malloc(self, 16*1024);
2713
 
        pushr_(xt_free, buffer);
2714
 
        fs_copy_file(self, from_path, to_path, buffer);
2715
 
        freer_();
2716
 
}
2717
 
 
2718
 
static void fs_copy_dir(XTThreadPtr self, char *from_path, char *to_path, void *copy_buf)
2719
 
{
2720
 
        XTOpenDirPtr    od;
2721
 
        char                    *file;
2722
 
        
2723
 
        xt_add_dir_char(PATH_MAX, from_path);
2724
 
        xt_add_dir_char(PATH_MAX, to_path);
2725
 
 
2726
 
        pushsr_(od, xt_dir_close, xt_dir_open(self, from_path, NULL));
2727
 
        while (xt_dir_next(self, od)) {
2728
 
                file = xt_dir_name(self, od);
2729
 
                if (*file == '.')
2730
 
                        continue;
2731
 
#ifdef XT_WIN
2732
 
                if (strcmp(file, "pbxt-lock") == 0)
2733
 
                        continue;
2734
 
#endif
2735
 
                xt_strcat(PATH_MAX, from_path, file);
2736
 
                xt_strcat(PATH_MAX, to_path, file);
2737
 
                if (xt_dir_is_file(self, od))
2738
 
                        fs_copy_file(self, from_path, to_path, copy_buf);
2739
 
                else
2740
 
                        fs_copy_dir(self, from_path, to_path, copy_buf);
2741
 
                xt_remove_last_name_of_path(from_path);
2742
 
                xt_remove_last_name_of_path(to_path);
2743
 
        }
2744
 
        freer_();
2745
 
 
2746
 
        xt_remove_dir_char(from_path);
2747
 
        xt_remove_dir_char(to_path);
2748
 
}
2749
 
 
2750
 
xtPublic void xt_fs_copy_dir(XTThreadPtr self, const char *from, const char *to)
2751
 
{
2752
 
        void    *buffer;
2753
 
        char    from_path[PATH_MAX];
2754
 
        char    to_path[PATH_MAX];
2755
 
 
2756
 
        xt_strcpy(PATH_MAX, from_path, from);
2757
 
        xt_strcpy(PATH_MAX, to_path, to);
2758
 
 
2759
 
        buffer = xt_malloc(self, 16*1024);
2760
 
        pushr_(xt_free, buffer);
2761
 
        fs_copy_dir(self, from_path, to_path, buffer);
2762
 
        freer_();
2763
 
}
2764