~stewart/drizzle/embedded-innodb-create-select-transaction-arrgh

« back to all changes in this revision

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

Merged embedded-innodb-autoincrement into embedded-innodb-create-select-transaction-arrgh.

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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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)
 
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
                                int             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 (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
                        int                                     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
#ifndef XT_NO_ATOMICS
 
1820
                        xtThreadID              thd_id = thread->t_id;
 
1821
#endif
 
1822
 
 
1823
                        if (!of->mf_slock_count)
 
1824
                                FILE_MAP_READ_LOCK(&mm->mm_lock, thd_id);
 
1825
                        if (!mm->mm_start) {
 
1826
                                FILE_MAP_UNLOCK(&mm->mm_lock, thd_id);
 
1827
                                ASSERT_NS(!of->mf_slock_count);
 
1828
                                FILE_MAP_WRITE_LOCK(&mm->mm_lock, thd_id);
 
1829
                                if (!fs_remap_file(of, 0, 0, stat)) {
 
1830
                                        if (!of->mf_slock_count)
 
1831
                                                FILE_MAP_UNLOCK(&mm->mm_lock, thd_id);
 
1832
                                        return FAILED;
 
1833
                                }
 
1834
                        }
 
1835
                        stat->ts_flush_start = xt_trace_clock();
 
1836
#ifdef XT_WIN
 
1837
                        if (!FlushViewOfFile(mm->mm_start, 0)) {
 
1838
                                xt_register_ferrno(XT_REG_CONTEXT, fs_get_win_error(), xt_file_path(of));
 
1839
                                if (!of->mf_slock_count)
 
1840
                                        FILE_MAP_UNLOCK(&mm->mm_lock, thd_id);
 
1841
                                goto failed;
 
1842
                        }
 
1843
#else
 
1844
                        if (msync( (char *)mm->mm_start, (size_t) mm->mm_length, MS_SYNC) == -1) {
 
1845
                                xt_register_ferrno(XT_REG_CONTEXT, errno, xt_file_path(of));
 
1846
                                if (!of->mf_slock_count)
 
1847
                                        FILE_MAP_UNLOCK(&mm->mm_lock, thd_id);
 
1848
                                goto failed;
 
1849
                        }
 
1850
#endif
 
1851
                        if (!of->mf_slock_count)
 
1852
                                FILE_MAP_UNLOCK(&mm->mm_lock, thd_id);
 
1853
                        break;
 
1854
                }
 
1855
                case XT_FT_HEAP:
 
1856
                        stat->ts_flush_start = xt_trace_clock();
 
1857
                        break;
 
1858
        }
 
1859
 
 
1860
#ifdef DEBUG_TRACE_IO
 
1861
        xt_trace("/* %s */ pbxt_file_sync(\"%s\");\n", xt_trace_clock_diff(timef, start), of->fr_file->fil_path);
 
1862
#endif
 
1863
#ifdef DEBUG_TRACE_AROUND
 
1864
        if (xt_is_extension(of->fr_file->fil_path, "xti"))
 
1865
                PRINTF("%s %s FLUSH (%d)\n", xt_trace_clock_str(timef), thread->t_name, (int) (xt_trace_clock() - start));
 
1866
#endif
 
1867
        s = stat->ts_flush_start;
 
1868
        stat->ts_flush_start = 0;
 
1869
        stat->ts_flush_time += xt_trace_clock() - s;
 
1870
        stat->ts_flush++;
 
1871
        return OK;
 
1872
 
 
1873
        failed:
 
1874
        s = stat->ts_flush_start;
 
1875
        stat->ts_flush_start = 0;
 
1876
        stat->ts_flush_time += xt_trace_clock() - s;
 
1877
        return FAILED;
 
1878
}
 
1879
 
 
1880
xtPublic xtBool xt_pread_file_4(XTOpenFilePtr of, off_t offset, xtWord4 *value, XTIOStatsPtr stat, XTThreadPtr thread)
 
1881
{
 
1882
        xtThreadID      thd_id;
 
1883
#ifdef XT_TIME_DISK_READS
 
1884
        xtWord8         s;
 
1885
#endif
 
1886
 
 
1887
#ifdef DEBUG_TRACE_MAP_IO
 
1888
        xt_trace("/* %s */ pbxt_fmap_read_4(\"%s\", %lu, 4);\n", xt_trace_clock_diff(NULL), of->fr_file->fil_path, (u_long) offset);
 
1889
#endif
 
1890
        switch (of->of_type) {
 
1891
                case XT_FT_NONE:
 
1892
                        break;
 
1893
                case XT_FT_REWRITE_FLUSH:
 
1894
                case XT_FT_STANDARD:
 
1895
                        xtWord1                 data4[4];
 
1896
#ifdef XT_TIME_DISK_READS
 
1897
                        stat->ts_read_start = xt_trace_clock();
 
1898
#endif
 
1899
#ifdef XT_WIN
 
1900
                        LARGE_INTEGER   liDistanceToMove;
 
1901
                        DWORD                   result;
 
1902
 
 
1903
                        liDistanceToMove.QuadPart = offset;
 
1904
                        if (!SetFilePointerEx(of->of_filedes, liDistanceToMove, NULL, FILE_BEGIN)) {
 
1905
                                xt_register_ferrno(XT_REG_CONTEXT, fs_get_win_error(), xt_file_path(of));
 
1906
                                goto failed;
 
1907
                        }
 
1908
 
 
1909
                        if (!ReadFile(of->of_filedes, data, 4, &result, NULL)) {
 
1910
                                xt_register_ferrno(XT_REG_CONTEXT, fs_get_win_error(), xt_file_path(of));
 
1911
                                goto failed;
 
1912
                        }
 
1913
 
 
1914
                        if ((size_t) result < 4) {
 
1915
                                xt_register_ferrno(XT_REG_CONTEXT, ERROR_HANDLE_EOF, xt_file_path(of));
 
1916
                                goto failed;
 
1917
                        }
 
1918
#else
 
1919
                        ssize_t read_size;
 
1920
 
 
1921
                        read_size = pread(of->x.of_filedes, data4, 4, offset);
 
1922
                        if (read_size == -1) {
 
1923
                                xt_register_ferrno(XT_REG_CONTEXT, errno, xt_file_path(of));
 
1924
                                goto failed;
 
1925
                        }
 
1926
 
 
1927
                        /* Throw an error if read less than the minimum: */
 
1928
                        if ((size_t) read_size < 4) {
 
1929
                                xt_register_ferrno(XT_REG_CONTEXT, ESPIPE, xt_file_path(of));
 
1930
                                goto failed;
 
1931
                        }
 
1932
#endif
 
1933
                        *value = XT_GET_DISK_4(data4);
 
1934
                        break;
 
1935
                case XT_FT_MEM_MAP: {
 
1936
                        XTFileMemMapPtr mm = of->x.mf_memmap;
 
1937
 
 
1938
                        thd_id = thread->t_id;
 
1939
                        if (!of->mf_slock_count)
 
1940
                                FILE_MAP_READ_LOCK(&mm->mm_lock, thd_id);
 
1941
                        if (!mm->mm_start) {
 
1942
                                ASSERT_NS(!of->mf_slock_count);
 
1943
                                FILE_MAP_UNLOCK(&mm->mm_lock, thd_id);
 
1944
                                FILE_MAP_WRITE_LOCK(&mm->mm_lock, thd_id);
 
1945
                                if (!fs_remap_file(of, 0, 0, stat)) {
 
1946
                                        FILE_MAP_UNLOCK(&mm->mm_lock, thd_id);
 
1947
                                        return FAILED;
 
1948
                                }
 
1949
                        }
 
1950
                        if (offset >= mm->mm_length)
 
1951
                                *value = 0;
 
1952
                        else {
 
1953
                                xtWord1 *data;
 
1954
 
 
1955
                                data = mm->mm_start + offset;
 
1956
#ifdef XT_TIME_DISK_READS
 
1957
                                stat->ts_read_start = xt_trace_clock();
 
1958
#endif
 
1959
#ifdef XT_WIN
 
1960
                                __try
 
1961
                                {
 
1962
                                        *value = XT_GET_DISK_4(data);
 
1963
                                        // GetExceptionCode()== EXCEPTION_IN_PAGE_ERROR ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH
 
1964
                                }
 
1965
                                __except(EXCEPTION_EXECUTE_HANDLER)
 
1966
                                {
 
1967
                                        FILE_MAP_UNLOCK(&mm->mm_lock, thd_id);
 
1968
                                        xt_register_ferrno(XT_REG_CONTEXT, GetExceptionCode(), xt_file_path(of));
 
1969
                                        goto failed;
 
1970
                                }
 
1971
#else
 
1972
                                *value = XT_GET_DISK_4(data);
 
1973
#endif
 
1974
                        }
 
1975
 
 
1976
                        if (!of->mf_slock_count)
 
1977
                                FILE_MAP_UNLOCK(&mm->mm_lock, thd_id);
 
1978
                        break;
 
1979
                }
 
1980
                case XT_FT_HEAP: {
 
1981
                        XTFileHeapPtr   fh = of->x.of_heap;
 
1982
                        thd_id = thread->t_id;
 
1983
 
 
1984
#ifdef XT_TIME_DISK_READS
 
1985
                        stat->ts_read_start = xt_trace_clock();
 
1986
#endif
 
1987
                        if (!of->mf_slock_count)
 
1988
                                FILE_MAP_READ_LOCK(&fh->fh_lock, thd_id);
 
1989
                        if (!fh->fh_start) {
 
1990
                                ASSERT_NS(!of->mf_slock_count);
 
1991
                                FILE_MAP_UNLOCK(&fh->fh_lock, thd_id);
 
1992
                                FILE_MAP_WRITE_LOCK(&fh->fh_lock, thd_id);
 
1993
                                if (!fs_remap_file(of, 0, 0, stat)) {
 
1994
                                        FILE_MAP_UNLOCK(&fh->fh_lock, thd_id);
 
1995
                                        goto failed;
 
1996
                                }
 
1997
                        }
 
1998
                        if (offset >= fh->fh_length)
 
1999
                                *value = 0;
 
2000
                        else {
 
2001
                                xtWord1 *data;
 
2002
 
 
2003
                                data = fh->fh_start + offset;
 
2004
                                *value = XT_GET_DISK_4(data);
 
2005
                        }
 
2006
                        if (!of->mf_slock_count)
 
2007
                                FILE_MAP_UNLOCK(&fh->fh_lock, thd_id);
 
2008
                        break;
 
2009
                }
 
2010
        }
 
2011
 
 
2012
#ifdef XT_TIME_DISK_READS
 
2013
        s = stat->ts_read_start;
 
2014
        stat->ts_read_start = 0;
 
2015
        stat->ts_read_time += xt_trace_clock() - s;
 
2016
#endif
 
2017
        stat->ts_read += 4;
 
2018
        return OK;
 
2019
 
 
2020
        failed:
 
2021
#ifdef XT_TIME_DISK_READS
 
2022
        s = stat->ts_read_start;
 
2023
        stat->ts_read_start = 0;
 
2024
        stat->ts_read_time += xt_trace_clock() - s;
 
2025
#endif
 
2026
        return FAILED;
 
2027
}
 
2028
 
 
2029
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)
 
2030
{
 
2031
        xtThreadID      thd_id;
 
2032
        size_t          tfer = 0;
 
2033
#ifdef XT_TIME_DISK_READS
 
2034
        xtWord8         s;
 
2035
#endif
 
2036
 
 
2037
#if defined(DEBUG_TRACE_IO) || defined(DEBUG_TRACE_AROUND)
 
2038
        char    timef[50];
 
2039
        xtWord8 start = xt_trace_clock();
 
2040
#endif
 
2041
#ifdef DEBUG_TRACE_AROUND
 
2042
        if (xt_is_extension(of->fr_file->fil_path, "xti"))
 
2043
                PRINTF("%s %s read\n", xt_trace_clock_str(timef), thread->t_name);
 
2044
#endif
 
2045
 
 
2046
        switch (of->of_type) {
 
2047
                case XT_FT_NONE:
 
2048
                        break;
 
2049
                case XT_FT_REWRITE_FLUSH:
 
2050
                case XT_FT_STANDARD:
 
2051
#ifdef XT_TIME_DISK_READS
 
2052
                        stat->ts_read_start = xt_trace_clock();
 
2053
#endif
 
2054
#ifdef XT_WIN
 
2055
                        LARGE_INTEGER   liDistanceToMove;
 
2056
                        DWORD                   result;
 
2057
 
 
2058
                        liDistanceToMove.QuadPart = offset;
 
2059
                        if (!SetFilePointerEx(of->of_filedes, liDistanceToMove, NULL, FILE_BEGIN)) {
 
2060
                                xt_register_ferrno(XT_REG_CONTEXT, fs_get_win_error(), xt_file_path(of));
 
2061
                                goto failed;
 
2062
                        }
 
2063
 
 
2064
                        if (!ReadFile(of->of_filedes, data, size, &result, NULL)) {
 
2065
                                xt_register_ferrno(XT_REG_CONTEXT, fs_get_win_error(), xt_file_path(of));
 
2066
                                goto failed;
 
2067
                        }
 
2068
 
 
2069
                        tfer = (size_t) result;
 
2070
#else
 
2071
                        ssize_t                 result;
 
2072
 
 
2073
                        result = pread(of->x.of_filedes, data, size, offset);
 
2074
                        if (result == -1) {
 
2075
                                xt_register_ferrno(XT_REG_CONTEXT, errno, xt_file_path(of));
 
2076
                                goto failed;
 
2077
                        }
 
2078
 
 
2079
                        tfer = (size_t) result;
 
2080
#endif
 
2081
                        break;
 
2082
                case XT_FT_MEM_MAP: {
 
2083
                        XTFileMemMapPtr mm = of->x.mf_memmap;
 
2084
 
 
2085
                        thd_id = thread->t_id;
 
2086
                        /* NOTE!! The file map may already be locked,
 
2087
                         * by a call to xt_lock_fmap_ptr()!
 
2088
                         *
 
2089
                         * 20.05.2009: This problem should be fixed now with mf_slock_count!
 
2090
                         *
 
2091
                         * This can occur during a sequential scan:
 
2092
                         * xt_pread_fmap()  Line 1330
 
2093
                         * XTTabCache::tc_read_direct()  Line 361
 
2094
                         * XTTabCache::xt_tc_read()  Line 220
 
2095
                         * xt_tab_get_rec_data()
 
2096
                         * tab_visible()  Line 2412
 
2097
                         * xt_tab_seq_next()  Line 4068
 
2098
                         *
 
2099
                         * And occurs during the following test:
 
2100
                         * create table t1 ( a int not null, b int not null) ;
 
2101
                         * --disable_query_log
 
2102
                         * insert into t1 values (1,1),(2,2),(3,3),(4,4);
 
2103
                         * let $1=19;
 
2104
                         * set @d=4;
 
2105
                         * while ($1)
 
2106
                         * {
 
2107
                         *   eval insert into t1 select a+@d,b+@d from t1;
 
2108
                         *   eval set @d=@d*2;
 
2109
                         *   dec $1;
 
2110
                         * }
 
2111
                         * 
 
2112
                         * --enable_query_log
 
2113
                         * alter table t1 add index i1(a);
 
2114
                         * delete from t1 where a > 2000000;
 
2115
                         * create table t2 like t1;
 
2116
                         * insert into t2 select * from t1;
 
2117
                         *
 
2118
                         * As a result, the slock must be able to handle
 
2119
                         * nested calls to lock/unlock.
 
2120
                         */
 
2121
                        if (!of->mf_slock_count)
 
2122
                                FILE_MAP_READ_LOCK(&mm->mm_lock, thd_id);
 
2123
                        tfer = size;
 
2124
                        if (!mm->mm_start) {
 
2125
                                FILE_MAP_UNLOCK(&mm->mm_lock, thd_id);
 
2126
                                ASSERT_NS(!of->mf_slock_count);
 
2127
                                FILE_MAP_WRITE_LOCK(&mm->mm_lock, thd_id);
 
2128
                                if (!fs_remap_file(of, 0, 0, stat)) {
 
2129
                                        if (!of->mf_slock_count)
 
2130
                                                FILE_MAP_UNLOCK(&mm->mm_lock, thd_id);
 
2131
                                        return FAILED;
 
2132
                                }
 
2133
                        }
 
2134
                        if (offset >= mm->mm_length)
 
2135
                                tfer = 0;
 
2136
                        else {
 
2137
                                if (mm->mm_length - offset < (off_t) tfer)
 
2138
                                        tfer = (size_t) (mm->mm_length - offset);
 
2139
#ifdef XT_TIME_DISK_READS
 
2140
                                stat->ts_read_start = xt_trace_clock();
 
2141
#endif
 
2142
#ifdef XT_WIN
 
2143
                                __try
 
2144
                                {
 
2145
                                        memcpy(data, mm->mm_start + offset, tfer);
 
2146
                                        // GetExceptionCode()== EXCEPTION_IN_PAGE_ERROR ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH
 
2147
                                }
 
2148
                                __except(EXCEPTION_EXECUTE_HANDLER)
 
2149
                                {
 
2150
                                        if (!of->mf_slock_count)
 
2151
                                                FILE_MAP_UNLOCK(&mm->mm_lock, thd_id);
 
2152
                                        xt_register_ferrno(XT_REG_CONTEXT, GetExceptionCode(), xt_file_path(of));
 
2153
                                        goto failed;
 
2154
                                }
 
2155
#else
 
2156
                                memcpy(data, mm->mm_start + offset, tfer);
 
2157
#endif
 
2158
                        }
 
2159
                        if (!of->mf_slock_count)
 
2160
                                FILE_MAP_UNLOCK(&mm->mm_lock, thd_id);
 
2161
                        break;
 
2162
                }
 
2163
                case XT_FT_HEAP: {
 
2164
                        XTFileHeapPtr   fh = of->x.of_heap;
 
2165
 
 
2166
#ifdef XT_TIME_DISK_READS
 
2167
                        stat->ts_read_start = xt_trace_clock();
 
2168
#endif
 
2169
                        thd_id  = thread->t_id;
 
2170
                        if (!of->mf_slock_count)
 
2171
                                FILE_MAP_READ_LOCK(&fh->fh_lock, thd_id);
 
2172
                        tfer = size;
 
2173
                        if (offset >= fh->fh_length)
 
2174
                                tfer = 0;
 
2175
                        else {
 
2176
                                if (fh->fh_length - offset < (off_t) tfer)
 
2177
                                        tfer = (size_t) (fh->fh_length - offset);
 
2178
                                memcpy(data, fh->fh_start + offset, tfer);
 
2179
                        }
 
2180
                        if (!of->mf_slock_count)
 
2181
                                FILE_MAP_UNLOCK(&fh->fh_lock, thd_id);
 
2182
                        break;
 
2183
                }
 
2184
        }
 
2185
 
 
2186
#ifdef XT_TIME_DISK_READS
 
2187
        s = stat->ts_read_start;
 
2188
        stat->ts_read_start = 0;
 
2189
        stat->ts_read_time += xt_trace_clock() - s;
 
2190
#endif
 
2191
        stat->ts_read += tfer;
 
2192
 
 
2193
        /* Throw an error if read less than the minimum: */
 
2194
        if (tfer < min_size)
 
2195
                return xt_register_ferrno(XT_REG_CONTEXT, ESPIPE, xt_file_path(of));
 
2196
        if (red_size)
 
2197
                *red_size = tfer;
 
2198
#ifdef DEBUG_TRACE_IO
 
2199
        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);
 
2200
#endif
 
2201
#ifdef DEBUG_TRACE_AROUND
 
2202
        if (xt_is_extension(of->fr_file->fil_path, "xti"))
 
2203
                PRINTF("%s %s read (%d)\n", xt_trace_clock_str(timef), thread->t_name, (int) (xt_trace_clock() - start));
 
2204
#endif
 
2205
        return OK;
 
2206
 
 
2207
        failed:
 
2208
#ifdef XT_TIME_DISK_READS
 
2209
        s = stat->ts_read_start;
 
2210
        stat->ts_read_start = 0;
 
2211
        stat->ts_read_time += xt_trace_clock() - s;
 
2212
#endif
 
2213
        return FAILED;
 
2214
}
 
2215
 
 
2216
xtPublic xtBool xt_lock_file_ptr(XTOpenFilePtr of, xtWord1 **data, off_t offset, size_t size, XTIOStatsPtr stat, XTThreadPtr thread)
 
2217
{
 
2218
        switch (of->of_type) {
 
2219
                case XT_FT_NONE:
 
2220
                        break;
 
2221
                case XT_FT_REWRITE_FLUSH:
 
2222
                case XT_FT_STANDARD:
 
2223
                        size_t red_size;
 
2224
                
 
2225
                        if (!*data) {
 
2226
                                if (!(*data = (xtWord1 *) xt_malloc_ns(size)))
 
2227
                                        return FAILED;
 
2228
                        }
 
2229
 
 
2230
                        if (!xt_pread_file(of, offset, size, 0, *data, &red_size, stat, thread))
 
2231
                                return FAILED;
 
2232
                        
 
2233
                        //if (red_size < size)
 
2234
                        //      memset();
 
2235
                        break;
 
2236
                case XT_FT_MEM_MAP: {
 
2237
                        XTFileMemMapPtr mm = of->x.mf_memmap;
 
2238
#ifndef XT_NO_ATOMICS
 
2239
                        xtThreadID              thd_id = thread->t_id;
 
2240
#endif
 
2241
 
 
2242
                        if (!of->mf_slock_count)
 
2243
                                FILE_MAP_READ_LOCK(&mm->mm_lock, thd_id);
 
2244
                        of->mf_slock_count++;
 
2245
                        if (!mm->mm_start) {
 
2246
                                FILE_MAP_UNLOCK(&mm->mm_lock, thd_id);
 
2247
                                ASSERT_NS(of->mf_slock_count == 1);
 
2248
                                FILE_MAP_WRITE_LOCK(&mm->mm_lock, thd_id);
 
2249
                                if (!fs_remap_file(of, 0, 0, stat)) {
 
2250
                                        of->mf_slock_count--;
 
2251
                                        if (!of->mf_slock_count)
 
2252
                                                FILE_MAP_UNLOCK(&mm->mm_lock, thd_id);
 
2253
                                        return FAILED;
 
2254
                                }
 
2255
                        }
 
2256
                        if (offset >= mm->mm_length) {
 
2257
                                of->mf_slock_count--;
 
2258
                                if (!of->mf_slock_count)
 
2259
                                        FILE_MAP_UNLOCK(&mm->mm_lock, thd_id);
 
2260
                                return FAILED;
 
2261
                        }
 
2262
                        
 
2263
                        if (offset + (off_t) size > mm->mm_length)
 
2264
                                stat->ts_read += (u_int) (offset + (off_t) size - mm->mm_length);
 
2265
                        else
 
2266
                                stat->ts_read += size;
 
2267
                        *data = mm->mm_start + offset;
 
2268
                        break;
 
2269
                }
 
2270
                case XT_FT_HEAP: {
 
2271
                        XTFileHeapPtr   fh = of->x.of_heap;
 
2272
#ifndef XT_NO_ATOMICS
 
2273
                        xtThreadID              thd_id = thread->t_id;
 
2274
#endif
 
2275
 
 
2276
                        if (!of->mf_slock_count)
 
2277
                                FILE_MAP_READ_LOCK(&fh->fh_lock, thd_id);
 
2278
                        of->mf_slock_count++;
 
2279
                        if (!fh->fh_start) {
 
2280
                                FILE_MAP_UNLOCK(&fh->fh_lock, thd_id);
 
2281
                                ASSERT_NS(of->mf_slock_count == 1);
 
2282
                                FILE_MAP_WRITE_LOCK(&fh->fh_lock, thd_id);
 
2283
                                if (!fs_remap_file(of, 0, 0, stat)) {
 
2284
                                        of->mf_slock_count--;
 
2285
                                        if (!of->mf_slock_count)
 
2286
                                                FILE_MAP_UNLOCK(&fh->fh_lock, thd_id);
 
2287
                                        return FAILED;
 
2288
                                }
 
2289
                        }
 
2290
                        if (offset >= fh->fh_length) {
 
2291
                                of->mf_slock_count--;
 
2292
                                if (!of->mf_slock_count)
 
2293
                                        FILE_MAP_UNLOCK(&fh->fh_lock, thd_id);
 
2294
                                return FAILED;
 
2295
                        }
 
2296
                        
 
2297
                        if (offset + (off_t) size > fh->fh_length)
 
2298
                                stat->ts_read += (u_int) (offset + (off_t) size - fh->fh_length);
 
2299
                        else
 
2300
                                stat->ts_read += size;
 
2301
                        *data = fh->fh_start + offset;
 
2302
                        break;
 
2303
                }
 
2304
        }
 
2305
 
 
2306
        return OK;
 
2307
}
 
2308
 
 
2309
xtPublic void xt_unlock_file_ptr(XTOpenFilePtr of, xtWord1 *data, XTThreadPtr thread)
 
2310
{
 
2311
        switch (of->of_type) {
 
2312
                case XT_FT_NONE:
 
2313
                        break;
 
2314
                case XT_FT_REWRITE_FLUSH:
 
2315
                case XT_FT_STANDARD:
 
2316
                        if (data)
 
2317
                                xt_free_ns(data);
 
2318
                        break;
 
2319
                case XT_FT_MEM_MAP:
 
2320
                        of->mf_slock_count--;
 
2321
                        if (!of->mf_slock_count)
 
2322
                                FILE_MAP_UNLOCK(&of->x.mf_memmap->mm_lock, thread->t_id);
 
2323
                        break;
 
2324
                case XT_FT_HEAP:
 
2325
                        of->mf_slock_count--;
 
2326
                        if (!of->mf_slock_count)
 
2327
                                FILE_MAP_UNLOCK(&of->x.of_heap->fh_lock, thread->t_id);
 
2328
                        break;
 
2329
        }
 
2330
}
 
2331
 
 
2332
/* ----------------------------------------------------------------------
 
2333
 * Directory operations
 
2334
 */
 
2335
 
 
2336
/*
 
2337
 * The filter may contain one '*' as wildcard.
 
2338
 */
 
2339
XTOpenDirPtr xt_dir_open(XTThreadPtr self, c_char *path, c_char *filter)
 
2340
{
 
2341
        XTOpenDirPtr    od;
 
2342
 
 
2343
#ifdef XT_SOLARIS
 
2344
        /* see the comment in filesys_xt.h */
 
2345
        size_t sz = pathconf(path, _PC_NAME_MAX) + sizeof(XTOpenDirRec) + 1;
 
2346
#else
 
2347
        size_t sz = sizeof(XTOpenDirRec);
 
2348
#endif
 
2349
        pushsr_(od, xt_dir_close, (XTOpenDirPtr) xt_calloc(self, sz));
 
2350
 
 
2351
#ifdef XT_WIN
 
2352
        size_t                  len;
 
2353
 
 
2354
        od->od_handle = XT_NULL_FD;
 
2355
 
 
2356
        // path = path\(filter | *)
 
2357
        len = strlen(path) + 1 + (filter ? strlen(filter) : 1) + 1;
 
2358
        od->od_path = (char *) xt_malloc(self, len);
 
2359
 
 
2360
        strcpy(od->od_path, path);
 
2361
        xt_add_dir_char(len, od->od_path);
 
2362
        if (filter)
 
2363
                strcat(od->od_path, filter);
 
2364
        else
 
2365
                strcat(od->od_path, "*");
 
2366
#else
 
2367
        od->od_path = xt_dup_string(self, path);
 
2368
 
 
2369
        if (filter)
 
2370
                od->od_filter = xt_dup_string(self, filter);
 
2371
 
 
2372
        od->od_dir = opendir(path);
 
2373
        if (!od->od_dir)
 
2374
                xt_throw_ferrno(XT_CONTEXT, errno, path);
 
2375
#endif
 
2376
        popr_(); // Discard xt_dir_close(od)
 
2377
        return od;
 
2378
}
 
2379
 
 
2380
void xt_dir_close(XTThreadPtr self, XTOpenDirPtr od)
 
2381
{
 
2382
        if (od) {
 
2383
#ifdef XT_WIN
 
2384
                if (od->od_handle != XT_NULL_FD) {
 
2385
                        FindClose(od->od_handle);
 
2386
                        od->od_handle = XT_NULL_FD;
 
2387
                }
 
2388
#else
 
2389
                if (od->od_dir) {
 
2390
                        closedir(od->od_dir);
 
2391
                        od->od_dir = NULL;
 
2392
                }
 
2393
                if (od->od_filter) {
 
2394
                        xt_free(self, od->od_filter);
 
2395
                        od->od_filter = NULL;
 
2396
                }
 
2397
#endif
 
2398
                if (od->od_path) {
 
2399
                        xt_free(self, od->od_path);
 
2400
                        od->od_path = NULL;
 
2401
                }
 
2402
                xt_free(self, od);
 
2403
        }
 
2404
}
 
2405
 
 
2406
#ifdef XT_WIN
 
2407
xtBool xt_dir_next(XTThreadPtr self, XTOpenDirPtr od)
 
2408
{
 
2409
        int err = 0;
 
2410
 
 
2411
        if (od->od_handle == INVALID_HANDLE_VALUE) {
 
2412
                od->od_handle = FindFirstFile(od->od_path, &od->od_data);
 
2413
                if (od->od_handle == INVALID_HANDLE_VALUE)
 
2414
                        err = fs_get_win_error();
 
2415
        }
 
2416
        else {
 
2417
                if (!FindNextFile(od->od_handle, &od->od_data))
 
2418
                        err = fs_get_win_error();
 
2419
        }
 
2420
 
 
2421
        if (err) {
 
2422
                if (err != ERROR_NO_MORE_FILES) {
 
2423
                        if (err == ERROR_FILE_NOT_FOUND) {
 
2424
                                char path[PATH_MAX];
 
2425
 
 
2426
                                xt_strcpy(PATH_MAX, path, od->od_path);
 
2427
                                xt_remove_last_name_of_path(path);
 
2428
                                if (!fs_exists(path, self))
 
2429
                                        xt_throw_ferrno(XT_CONTEXT, err, path);
 
2430
                        }
 
2431
                        else
 
2432
                                xt_throw_ferrno(XT_CONTEXT, err, od->od_path);
 
2433
                }
 
2434
                return FAILED;
 
2435
        }
 
2436
 
 
2437
        return OK;
 
2438
}
 
2439
#else
 
2440
static xtBool fs_match_filter(c_char *name, c_char *filter)
 
2441
{
 
2442
        while (*name && *filter) {
 
2443
                if (*filter == '*') {
 
2444
                        if (filter[1] == *name)
 
2445
                                filter++;
 
2446
                        else
 
2447
                                name++;
 
2448
                }
 
2449
                else {
 
2450
                        if (*name != *filter)
 
2451
                                return FALSE;
 
2452
                        name++;
 
2453
                        filter++;
 
2454
                }
 
2455
        }
 
2456
        if (!*name) {
 
2457
                if (!*filter || (*filter == '*' && !filter[1]))
 
2458
                        return TRUE;
 
2459
        }
 
2460
        return FALSE;
 
2461
}
 
2462
 
 
2463
xtBool xt_dir_next(XTThreadPtr self, XTOpenDirPtr od)
 
2464
{
 
2465
        int                             err;
 
2466
        struct dirent   *result;
 
2467
 
 
2468
        for (;;) {
 
2469
                err = readdir_r(od->od_dir, &od->od_entry, &result);
 
2470
                if (err) {
 
2471
                        xt_throw_ferrno(XT_CONTEXT, err, od->od_path);
 
2472
                        return FAILED;
 
2473
                }
 
2474
                if (!result)
 
2475
                        break;
 
2476
                /* Filter out '.' and '..': */
 
2477
                if (od->od_entry.d_name[0] == '.') {
 
2478
                        if (od->od_entry.d_name[1] == '.') {
 
2479
                                if (od->od_entry.d_name[2] == '\0')
 
2480
                                        continue;
 
2481
                        }
 
2482
                        else {
 
2483
                                if (od->od_entry.d_name[1] == '\0')
 
2484
                                        continue;
 
2485
                        }
 
2486
                }
 
2487
                if (!od->od_filter)
 
2488
                        break;
 
2489
                if (fs_match_filter(od->od_entry.d_name, od->od_filter))
 
2490
                        break;
 
2491
        }
 
2492
        return result ? TRUE : FALSE;
 
2493
}
 
2494
#endif
 
2495
 
 
2496
char *xt_dir_name(XTThreadPtr XT_UNUSED(self), XTOpenDirPtr od)
 
2497
{
 
2498
#ifdef XT_WIN
 
2499
        return od->od_data.cFileName;
 
2500
#else
 
2501
        return od->od_entry.d_name;
 
2502
#endif
 
2503
}
 
2504
 
 
2505
xtBool xt_dir_is_file(XTThreadPtr self, XTOpenDirPtr od)
 
2506
{
 
2507
        (void) self;
 
2508
#ifdef XT_WIN
 
2509
        if (od->od_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
 
2510
                return FALSE;
 
2511
#elif defined(XT_SOLARIS)
 
2512
        char path[PATH_MAX];
 
2513
        struct stat sb;
 
2514
 
 
2515
        xt_strcpy(PATH_MAX, path, od->od_path);
 
2516
        xt_add_dir_char(PATH_MAX, path);
 
2517
        xt_strcat(PATH_MAX, path, od->od_entry.d_name);
 
2518
 
 
2519
        if (stat(path, &sb) == -1) {
 
2520
                xt_throw_ferrno(XT_CONTEXT, errno, path);
 
2521
                return FAILED;
 
2522
        }
 
2523
 
 
2524
        if ( sb.st_mode & S_IFDIR )
 
2525
                return FALSE;
 
2526
#else
 
2527
        if (od->od_entry.d_type & DT_DIR)
 
2528
                return FALSE;
 
2529
#endif
 
2530
        return TRUE;
 
2531
}
 
2532
 
 
2533
off_t xt_dir_file_size(XTThreadPtr self, XTOpenDirPtr od)
 
2534
{
 
2535
#ifdef XT_WIN
 
2536
        return (off_t) od->od_data.nFileSizeLow | (((off_t) od->od_data.nFileSizeHigh) << 32);
 
2537
#else
 
2538
        char    path[PATH_MAX];
 
2539
        off_t   size;
 
2540
 
 
2541
        xt_strcpy(PATH_MAX, path, od->od_path);
 
2542
        xt_add_dir_char(PATH_MAX, path);
 
2543
        xt_strcat(PATH_MAX, path, od->od_entry.d_name);
 
2544
        if (!xt_fs_stat(self, path, &size, NULL))
 
2545
                return -1;
 
2546
        return size;
 
2547
#endif
 
2548
}
 
2549
 
 
2550
/* ----------------------------------------------------------------------
 
2551
 * File mapping operations
 
2552
 */
 
2553
 
 
2554
static xtBool fs_map_file(XTFileMemMapPtr mm, XTFilePtr file, xtBool grow)
 
2555
{
 
2556
#ifdef INJECT_WRITE_REMAP_ERROR
 
2557
        if (xt_is_extension(file->fil_path, INJECT_REMAP_FILE_TYPE)) {
 
2558
                if (mm->mm_length > INJECT_REMAP_FILE_SIZE) {
 
2559
                        xt_register_ferrno(XT_REG_CONTEXT, 30, file->fil_path);
 
2560
                        return FAILED;
 
2561
                }
 
2562
        }
 
2563
#endif
 
2564
        ASSERT_NS(!mm->mm_start);
 
2565
#ifdef XT_WIN
 
2566
        /* This will grow the file to the given size: */
 
2567
        mm->mm_mapdes = CreateFileMapping(file->fil_filedes, NULL, PAGE_READWRITE, (DWORD) (mm->mm_length >> 32), (DWORD) mm->mm_length, NULL);
 
2568
        if (mm->mm_mapdes == NULL) {
 
2569
                xt_register_ferrno(XT_REG_CONTEXT, fs_get_win_error(), file->fil_path);
 
2570
                return FAILED;
 
2571
        }
 
2572
 
 
2573
        mm->mm_start = (xtWord1 *) MapViewOfFile(mm->mm_mapdes, FILE_MAP_WRITE, 0, 0, 0);
 
2574
        if (!mm->mm_start) {
 
2575
                CloseHandle(mm->mm_mapdes);
 
2576
                mm->mm_mapdes = NULL;
 
2577
                xt_register_ferrno(XT_REG_CONTEXT, fs_get_win_error(), file->fil_path);
 
2578
                return FAILED;
 
2579
        }
 
2580
#else
 
2581
        if (grow) {
 
2582
                char data[2];
 
2583
 
 
2584
                if (pwrite(file->fil_filedes, data, 1, mm->mm_length - 1) == -1) {
 
2585
                        xt_register_ferrno(XT_REG_CONTEXT, errno, file->fil_path);
 
2586
                        return FAILED;
 
2587
                }
 
2588
        }
 
2589
 
 
2590
        /* Remap: */
 
2591
        mm->mm_start = (xtWord1 *) mmap(0, (size_t) mm->mm_length, PROT_READ | PROT_WRITE, MAP_SHARED, file->fil_filedes, 0);
 
2592
        if (mm->mm_start == MAP_FAILED) {
 
2593
                mm->mm_start = NULL;
 
2594
                xt_register_ferrno(XT_REG_CONTEXT, errno, file->fil_path);
 
2595
                return FAILED;
 
2596
        }
 
2597
#endif
 
2598
        return OK;
 
2599
}
 
2600
 
 
2601
static xtBool fs_remap_file(XTOpenFilePtr map, off_t offset, size_t size, XTIOStatsPtr stat)
 
2602
{
 
2603
        off_t                   new_size = 0;
 
2604
        XTFileMemMapPtr mm = map->x.mf_memmap;
 
2605
        xtWord8                 s;
 
2606
 
 
2607
        if (offset + (off_t) size > mm->mm_length) {
 
2608
                /* Expand the file: */
 
2609
                new_size = (mm->mm_length + (off_t) mm->mm_grow_size) / (off_t) mm->mm_grow_size;
 
2610
                new_size *= mm->mm_grow_size;
 
2611
                while (new_size < offset + (off_t) size)
 
2612
                        new_size += mm->mm_grow_size;
 
2613
 
 
2614
                if (sizeof(size_t) == 4 && new_size >= (off_t) 0xFFFFFFFF) {
 
2615
                        xt_register_ixterr(XT_REG_CONTEXT, XT_ERR_FILE_TOO_LONG, xt_file_path(map));
 
2616
                        return FAILED;
 
2617
                }
 
2618
        }
 
2619
        else if (!mm->mm_start)
 
2620
                new_size = mm->mm_length;
 
2621
 
 
2622
        if (new_size) {
 
2623
                if (mm->mm_start) {
 
2624
                        /* Flush & unmap: */
 
2625
                        stat->ts_flush_start = xt_trace_clock();
 
2626
#ifdef XT_WIN
 
2627
                        if (!FlushViewOfFile(mm->mm_start, 0)) {
 
2628
                                xt_register_ferrno(XT_REG_CONTEXT, fs_get_win_error(), xt_file_path(map));
 
2629
                                goto failed;
 
2630
                        }
 
2631
 
 
2632
                        if (!UnmapViewOfFile(mm->mm_start)) {
 
2633
                                xt_register_ferrno(XT_REG_CONTEXT, fs_get_win_error(), xt_file_path(map));
 
2634
                                goto failed;
 
2635
                        }
 
2636
#else
 
2637
                        if (msync( (char *)mm->mm_start, (size_t) mm->mm_length, MS_SYNC) == -1) {
 
2638
                                xt_register_ferrno(XT_REG_CONTEXT, errno, xt_file_path(map));
 
2639
                                goto failed;
 
2640
                        }
 
2641
 
 
2642
                        /* Unmap: */
 
2643
                        if (munmap((caddr_t) mm->mm_start, (size_t) mm->mm_length) == -1) {
 
2644
                                xt_register_ferrno(XT_REG_CONTEXT, errno, xt_file_path(map));
 
2645
                                goto failed;
 
2646
                        }
 
2647
#endif
 
2648
                        s = stat->ts_flush_start;
 
2649
                        stat->ts_flush_start = 0;
 
2650
                        stat->ts_flush_time += xt_trace_clock() - s;
 
2651
                        stat->ts_flush++;
 
2652
                }
 
2653
                mm->mm_start = NULL;
 
2654
#ifdef XT_WIN
 
2655
                /* It is possible that a previous remap attempt has failed: the map was closed
 
2656
                 * but the new map was not allocated (e.g. because of insufficient disk space). 
 
2657
                 * In this case mm->mm_mapdes will be NULL.
 
2658
                 */
 
2659
                if (mm->mm_mapdes && !CloseHandle(mm->mm_mapdes))
 
2660
                        return xt_register_ferrno(XT_REG_CONTEXT, fs_get_win_error(), xt_file_path(map));
 
2661
                mm->mm_mapdes = NULL;
 
2662
#endif
 
2663
                off_t old_size = mm->mm_length;
 
2664
                mm->mm_length = new_size;
 
2665
 
 
2666
                if (!fs_map_file(mm, map->fr_file, TRUE)) {
 
2667
                        /* Try to restore old mapping */
 
2668
                        mm->mm_length = old_size;
 
2669
                        fs_map_file(mm, map->fr_file, FALSE);
 
2670
                        goto failed;
 
2671
                }
 
2672
        }
 
2673
        return OK;
 
2674
        
 
2675
        failed:
 
2676
        s = stat->ts_flush_start;
 
2677
        stat->ts_flush_start = 0;
 
2678
        stat->ts_flush_time += xt_trace_clock() - s;
 
2679
        return FAILED;
 
2680
}
 
2681
 
 
2682
/* ----------------------------------------------------------------------
 
2683
 * Copy files/directories
 
2684
 */
 
2685
 
 
2686
static void fs_copy_file(XTThreadPtr self, char *from_path, char *to_path, void *copy_buf)
 
2687
{
 
2688
        XTOpenFilePtr   from;
 
2689
        XTOpenFilePtr   to;
 
2690
        off_t                   offset = 0;
 
2691
        size_t                  read_size= 0;
 
2692
 
 
2693
        from = xt_open_file(self, from_path, XT_FT_STANDARD, XT_FS_READONLY, 16*1024);
 
2694
        pushr_(xt_close_file, from);
 
2695
        to = xt_open_file(self, to_path, XT_FT_STANDARD, XT_FS_CREATE | XT_FS_MAKE_PATH, 16*1024);
 
2696
        pushr_(xt_close_file, to);
 
2697
 
 
2698
        for (;;) {
 
2699
                if (!xt_pread_file(from, offset, 16*1024, 0, copy_buf, &read_size, &self->st_statistics.st_x, self))
 
2700
                        xt_throw(self);
 
2701
                if (!read_size)
 
2702
                        break;
 
2703
                if (!xt_pwrite_file(to, offset, read_size, copy_buf, &self->st_statistics.st_x, self))
 
2704
                        xt_throw(self);
 
2705
                offset += (off_t) read_size;
 
2706
        }
 
2707
 
 
2708
        freer_();
 
2709
        freer_();
 
2710
}
 
2711
 
 
2712
xtPublic void xt_fs_copy_file(XTThreadPtr self, char *from_path, char *to_path)
 
2713
{
 
2714
        void *buffer;
 
2715
 
 
2716
        buffer = xt_malloc(self, 16*1024);
 
2717
        pushr_(xt_free, buffer);
 
2718
        fs_copy_file(self, from_path, to_path, buffer);
 
2719
        freer_();
 
2720
}
 
2721
 
 
2722
static void fs_copy_dir(XTThreadPtr self, char *from_path, char *to_path, void *copy_buf)
 
2723
{
 
2724
        XTOpenDirPtr    od;
 
2725
        char                    *file;
 
2726
        
 
2727
        xt_add_dir_char(PATH_MAX, from_path);
 
2728
        xt_add_dir_char(PATH_MAX, to_path);
 
2729
 
 
2730
        pushsr_(od, xt_dir_close, xt_dir_open(self, from_path, NULL));
 
2731
        while (xt_dir_next(self, od)) {
 
2732
                file = xt_dir_name(self, od);
 
2733
                if (*file == '.')
 
2734
                        continue;
 
2735
#ifdef XT_WIN
 
2736
                if (strcmp(file, "pbxt-lock") == 0)
 
2737
                        continue;
 
2738
#endif
 
2739
                xt_strcat(PATH_MAX, from_path, file);
 
2740
                xt_strcat(PATH_MAX, to_path, file);
 
2741
                if (xt_dir_is_file(self, od))
 
2742
                        fs_copy_file(self, from_path, to_path, copy_buf);
 
2743
                else
 
2744
                        fs_copy_dir(self, from_path, to_path, copy_buf);
 
2745
                xt_remove_last_name_of_path(from_path);
 
2746
                xt_remove_last_name_of_path(to_path);
 
2747
        }
 
2748
        freer_();
 
2749
 
 
2750
        xt_remove_dir_char(from_path);
 
2751
        xt_remove_dir_char(to_path);
 
2752
}
 
2753
 
 
2754
xtPublic void xt_fs_copy_dir(XTThreadPtr self, const char *from, const char *to)
 
2755
{
 
2756
        void    *buffer;
 
2757
        char    from_path[PATH_MAX];
 
2758
        char    to_path[PATH_MAX];
 
2759
 
 
2760
        xt_strcpy(PATH_MAX, from_path, from);
 
2761
        xt_strcpy(PATH_MAX, to_path, to);
 
2762
 
 
2763
        buffer = xt_malloc(self, 16*1024);
 
2764
        pushr_(xt_free, buffer);
 
2765
        fs_copy_dir(self, from_path, to_path, buffer);
 
2766
        freer_();
 
2767
}
 
2768