1
/* Copyright (c) 2005 PrimeBase Technologies GmbH
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.
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.
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
19
* 2005-01-12 Paul McCullagh
24
#include "xt_config.h"
34
#include <sys/types.h>
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"
45
#include "sortedlist_xt.h"
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
59
#if defined(DEBUG_TRACE_AROUND) || defined(DEBUG_TRACE_FILES)
60
//#define PRINTF xt_ftracef
61
//#define PRINTF xt_trace
65
#ifdef INJECT_WRITE_REMAP_ERROR
66
#define INJECT_REMAP_FILE_SIZE 1000000
67
#define INJECT_REMAP_FILE_TYPE "xtd"
70
#ifdef INJECT_FLUSH_FILE_ERROR
71
#define INJECT_FLUSH_FILE_SIZE 10000000
72
#define INJECT_FLUSH_FILE_TYPE "dlog"
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;
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);
90
/* ----------------------------------------------------------------------
94
typedef struct FsGlobals {
95
xt_mutex_type *fsg_lock; /* The xtPublic cache lock. */
97
XTSortedListPtr fsg_open_files;
100
static FsGlobalsRec fs_globals;
103
static int fs_get_win_error()
105
return (int) GetLastError();
108
xtPublic void xt_get_win_message(char *buffer, size_t size, int err)
110
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err,
111
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
117
/* ----------------------------------------------------------------------
121
static int rewrite_opt_comp(void *k, void *r)
123
register off_t *key = (off_t *) k;
124
register RewriteBlockPtr rec = (RewriteBlockPtr) r;
126
if (*key == rec->rb_offset)
128
if (*key < rec->rb_offset)
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))
136
register size_t guess;
141
guess = (i + count - 1) >> 1;
142
r = compare(key, ((char *) base) + guess * size);
145
return ((char *) base) + guess * size;
157
/* ----------------------------------------------------------------------
161
static XTFilePtr fs_new_file(char *file, XTFileType type)
165
if (!(file_ptr = (XTFilePtr) xt_calloc_ns(sizeof(XTFileRec))))
168
file_ptr->fil_type = type;
169
if (!(file_ptr->fil_path = xt_dup_string(NULL, file))) {
170
xt_free_ns(file_ptr);
174
switch (file_ptr->fil_type) {
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);
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;
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));
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;
206
static void fs_close_fmap(XTThreadPtr self, XTFileMemMapPtr mm)
210
FlushViewOfFile(mm->mm_start, 0);
211
UnmapViewOfFile(mm->mm_start);
214
if (mm->mm_mapdes != NULL) {
215
CloseHandle(mm->mm_mapdes);
216
mm->mm_mapdes = NULL;
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);
225
FILE_MAP_FREE_LOCK(self, &mm->mm_lock);
229
static void fs_close_heap(XTThreadPtr self, XTFileHeapPtr fh)
232
xt_free(self, fh->fh_start);
236
FILE_MAP_FREE_LOCK(self, &fh->fh_lock);
240
static void fs_free_file(XTThreadPtr self, void *XT_UNUSED(thunk), void *item)
242
XTFilePtr file_ptr = *((XTFilePtr *) item);
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));
249
CloseHandle(file_ptr->fil_filedes);
251
close(file_ptr->fil_filedes);
253
//PRINTF("close (FILE) %d %s\n", file_ptr->fil_filedes, file_ptr->fil_path);
254
file_ptr->fil_filedes = XT_NULL_FD;
257
switch (file_ptr->fil_type) {
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;
274
if (file_ptr->x.fil_heap) {
275
fs_close_heap(self, file_ptr->x.fil_heap);
276
file_ptr->x.fil_heap = NULL;
281
#ifdef DEBUG_TRACE_FILES
283
XTThreadPtr thr = 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) : "?");
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;
300
xt_free(self, file_ptr);
304
static int fs_comp_file(XTThreadPtr XT_UNUSED(self), register const void *XT_UNUSED(thunk), register const void *a, register const void *b)
306
char *file_name = (char *) a;
307
XTFilePtr file_ptr = *((XTFilePtr *) b);
309
return strcmp(file_name, file_ptr->fil_path);
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)
314
char *file_name = (char *) a;
315
XTFilePtr file_ptr = *((XTFilePtr *) b);
317
return strcasecmp(file_name, file_ptr->fil_path);
320
/* ----------------------------------------------------------------------
324
xtPublic void xt_fs_init(XTThreadPtr self)
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;
334
xtPublic void xt_fs_exit(XTThreadPtr self)
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;
341
fs_globals.fsg_lock = NULL;
342
fs_globals.fsg_current_id = 0;
345
/* ----------------------------------------------------------------------
349
static void fs_set_stats(XTThreadPtr self, char *path)
351
char super_path[PATH_MAX];
355
ptr = xt_last_name_of_path(path);
357
strcpy(super_path, ".");
359
xt_strcpy(PATH_MAX, super_path, path);
361
if ((ptr = xt_last_name_of_path(super_path)))
364
if (stat(super_path, &stats) == -1)
365
xt_throw_ferrno(XT_CONTEXT, errno, super_path);
367
if (chmod(path, stats.st_mode) == -1)
368
xt_throw_ferrno(XT_CONTEXT, errno, path);
370
/*chown(path, stats.st_uid, stats.st_gid);*/
373
xtPublic char *xt_file_path(XTOpenFilePtr of)
375
return of->fr_file->fil_path;
378
static xtBool fs_exists(char *path, XTThreadPtr thread)
382
err = access(path, F_OK);
384
if (fs_heap_file_exists(path, thread) == XT_FT_HEAP)
391
xtBool xt_fs_exists(char *path)
394
* Do no use xt_get_self() because this function call is required before
395
* the self has been setup!
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\
416
return fs_exists(path, NULL);
420
* No error is generated if the file dose not exist.
422
xtPublic xtBool xt_fs_delete(XTThreadPtr self, char *name)
424
#ifdef DEBUG_TRACE_FILES
425
PRINTF("%s: DELETE FILE: %s\n", xt_get_self()->t_name, xt_last_2_names_of_path(name));
428
* This reference count is +1 for the file exists!
429
* It will be decremented on file delete!
431
if (fs_delete_heap_file(self, name))
435
//PRINTF("delete %s\n", name);
436
if (!DeleteFile(name)) {
437
int err = fs_get_win_error();
439
if (!XT_FILE_NOT_FOUND(err)) {
440
xt_throw_ferrno(XT_CONTEXT, err, name);
445
if (unlink(name) == -1) {
449
xt_throw_ferrno(XT_CONTEXT, err, name);
457
xtPublic xtBool xt_fs_file_not_found(int err)
460
return XT_FILE_NOT_FOUND(err);
462
return err == ENOENT;
466
xtPublic void xt_fs_move(struct XTThread *self, char *from_path, char *to_path)
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));
475
if (fs_rename_heap_file(self, &ok, from_path, to_path))
479
if (!MoveFile(from_path, to_path))
480
xt_throw_ferrno(XT_CONTEXT, fs_get_win_error(), from_path);
482
if (link(from_path, to_path) == -1) {
484
xt_throw_ferrno(XT_CONTEXT, err, from_path);
487
if (unlink(from_path) == -1) {
490
xt_throw_ferrno(XT_CONTEXT, err, from_path);
495
xtPublic xtBool xt_fs_rename(XTThreadPtr self, char *from_path, char *to_path)
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));
504
if (fs_rename_heap_file(self, &ok, from_path, to_path))
507
if (rename(from_path, to_path) == -1) {
509
xt_throw_ferrno(XT_CONTEXT, err, from_path);
515
xtPublic xtBool xt_fs_stat(XTThreadPtr self, char *path, off_t *size, struct timespec *mod_time)
519
BY_HANDLE_FILE_INFORMATION info;
520
SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), 0, 0 };
528
FILE_ATTRIBUTE_NORMAL,
530
if (fh == INVALID_HANDLE_VALUE) {
531
xt_throw_ferrno(XT_CONTEXT, fs_get_win_error(), path);
535
if (!GetFileInformationByHandle(fh, &info)) {
537
xt_throw_ferrno(XT_CONTEXT, fs_get_win_error(), path);
543
*size = (off_t) info.nFileSizeLow | (((off_t) info.nFileSizeHigh) << 32);
545
mod_time->tv.ft = info.ftLastWriteTime;
549
if (stat(path, &sb) == -1) {
550
xt_throw_ferrno(XT_CONTEXT, errno, path);
556
mod_time->tv_sec = sb.st_mtime;
558
/* This is the Mac OS X version: */
559
mod_time->tv_nsec = sb.st_mtimespec.tv_nsec;
562
/* This is the Linux version: */
563
mod_time->tv_nsec = sb.st_mtim.tv_nsec;
566
mod_time->tv_nsec = 0;
574
void xt_fs_mkdir(XTThreadPtr self, char *name)
578
xt_strcpy(PATH_MAX, path, name);
579
xt_remove_dir_char(path);
583
SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), 0, 0 };
585
if (!CreateDirectory(path, &sa))
586
xt_throw_ferrno(XT_CONTEXT, fs_get_win_error(), path);
589
if (mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO) == -1)
590
xt_throw_ferrno(XT_CONTEXT, errno, path);
593
fs_set_stats(self, path);
596
xt_fs_rmdir(NULL, name);
603
void xt_fs_mkpath(XTThreadPtr self, char *path)
607
if (fs_exists(path, self))
610
if (!(ptr = (char *) xt_last_directory_of_path((c_char *) path)))
615
if (XT_IS_DIR_CHAR(*ptr)) {
617
xt_fs_mkpath(self, path);
619
xt_fs_mkdir(self, path);
623
xtBool xt_fs_rmdir(XTThreadPtr self, char *name)
627
xt_strcpy(PATH_MAX, path, name);
628
xt_remove_dir_char(path);
631
if (!RemoveDirectory(path)) {
632
int err = fs_get_win_error();
634
if (!XT_FILE_NOT_FOUND(err)) {
635
xt_throw_ferrno(XT_CONTEXT, err, path);
640
if (rmdir(path) == -1) {
644
xt_throw_ferrno(XT_CONTEXT, err, path);
652
/* ----------------------------------------------------------------------
653
* Open & Close operations
656
xtPublic XTFilePtr xt_fs_get_file(XTThreadPtr self, char *file_name, XTFileType type)
658
XTFilePtr file_ptr, *file_pptr;
660
xt_sl_lock(self, fs_globals.fsg_open_files);
661
pushr_(xt_sl_unlock, fs_globals.fsg_open_files);
663
if ((file_pptr = (XTFilePtr *) xt_sl_find(self, fs_globals.fsg_open_files, file_name)))
664
file_ptr = *file_pptr;
666
if (!(file_ptr = fs_new_file(file_name, type)))
668
xt_sl_insert(self, fs_globals.fsg_open_files, file_name, &file_ptr);
670
file_ptr->fil_ref_count++;
671
freer_(); // xt_sl_unlock(fs_globals.fsg_open_files)
675
xtPublic void xt_fs_release_file(XTThreadPtr self, XTFilePtr file_ptr)
677
xt_sl_lock(self, fs_globals.fsg_open_files);
678
pushr_(xt_sl_unlock, fs_globals.fsg_open_files);
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);
685
freer_(); // xt_ht_unlock(fs_globals.fsg_open_files)
688
static XTFileType fs_heap_file_exists(char *file_name, XTThreadPtr thread)
690
XTFilePtr *file_pptr;
693
xt_sl_lock_ns(fs_globals.fsg_open_files, thread);
695
if ((file_pptr = (XTFilePtr *) xt_sl_find(NULL, fs_globals.fsg_open_files, file_name)))
696
type = (*file_pptr)->fil_type;
700
xt_sl_unlock_ns(fs_globals.fsg_open_files);
705
* Return TRUE if the heap file exists!
707
static xtBool fs_rename_heap_file(struct XTThread *self, xtBool *all_ok, char *from_name, char *to_name)
709
XTFilePtr from_ptr, to_ptr, *file_pptr;
711
xt_sl_lock_ns(fs_globals.fsg_open_files, self);
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) {
718
if (from_ptr->fil_ref_count > 1) {
719
xt_register_ferrno(XT_REG_CONTEXT, XT_FILE_IN_USE_ERR, from_name);
723
/* Add the new one: */
724
if (!(to_ptr = fs_new_file(to_name, XT_FT_HEAP)))
727
if (!xt_sl_insert(NULL, fs_globals.fsg_open_files, to_name, &to_ptr))
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++;
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);
740
xt_sl_unlock_ns(fs_globals.fsg_open_files);
746
xt_sl_unlock_ns(fs_globals.fsg_open_files);
750
xt_sl_unlock_ns(fs_globals.fsg_open_files);
756
* Return TRUE of this is a "heap" file.
758
static xtBool fs_delete_heap_file(XTThreadPtr self, char *file_name)
760
XTFilePtr file_ptr, *file_pptr;
762
xt_sl_lock_ns(fs_globals.fsg_open_files, self);
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);
775
xt_sl_unlock_ns(fs_globals.fsg_open_files);
779
static void fs_delete_all_heap_files(XTThreadPtr self)
781
XTFilePtr file_ptr, *file_pptr;
784
xt_sl_lock(self, fs_globals.fsg_open_files);
785
pushr_(xt_sl_unlock, fs_globals.fsg_open_files);
788
if (!(file_pptr = (XTFilePtr *) xt_sl_item_at(fs_globals.fsg_open_files, i)))
790
file_ptr = *file_pptr;
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);
801
freer_(); // xt_sl_unlock(fs_globals.fsg_open_files)
804
static xtBool fs_open_file(XTThreadPtr self, XT_FD *fd, XTFilePtr file, int mode)
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));
813
SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), 0, 0 };
816
if (mode & XT_FS_EXCLUSIVE)
818
else if (mode & XT_FS_CREATE)
821
flags = OPEN_EXISTING;
825
mode & XT_FS_READONLY ? GENERIC_READ : (GENERIC_READ | GENERIC_WRITE),
826
FILE_SHARE_READ | FILE_SHARE_WRITE,
829
FILE_FLAG_RANDOM_ACCESS,
831
if (*fd == INVALID_HANDLE_VALUE) {
832
int err = fs_get_win_error();
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)) {
838
xt_strcpy(PATH_MAX, path, file->fil_path);
839
xt_remove_last_name_of_path(path);
840
xt_fs_mkpath(self, path);
845
xt_throw_ferrno(XT_CONTEXT, err, file->fil_path);
848
/* File is missing, but don't throw an error. */
851
//PRINTF("open %d %s\n", *fd, file->fil_path);
856
if (mode & XT_FS_READONLY)
860
if (mode & XT_FS_CREATE)
862
if (mode & XT_FS_EXCLUSIVE)
865
if (mode & XT_FS_DIRECT_IO)
869
*fd = open(file->fil_path, flags, XT_MASK);
873
if (!(mode & XT_FS_MISSING_OK) || err != ENOENT) {
874
if (!retried && (mode & XT_FS_MAKE_PATH) && err == ENOENT) {
877
xt_strcpy(PATH_MAX, path, file->fil_path);
878
xt_remove_last_name_of_path(path);
879
xt_fs_mkpath(self, path);
884
xt_throw_ferrno(XT_CONTEXT, err, file->fil_path);
887
/* File is missing, but don't throw an error. */
890
///PRINTF("open %d %s\n", *fd, file->fil_path);
895
xtPublic XTOpenFilePtr xt_open_file(XTThreadPtr self, char *file, XTFileType type, int mode, size_t grow_size)
900
pushsr_(of, xt_close_file, (XTOpenFilePtr) xt_calloc(self, sizeof(XTOpenFileRec)));
901
fp = xt_fs_get_file(self, file, type);
904
of->fr_id = fp->fil_id;
909
case XT_FT_REWRITE_FLUSH:
911
of->x.of_filedes = XT_NULL_FD;
913
if (!fs_open_file(self, &of->of_filedes, fp, mode)) {
914
xt_close_file(self, of);
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))
928
freer_(); // xt_ht_unlock(fs_globals.fsg_open_files)
932
/* Close, but after we have release the fsg_open_files lock! */
933
xt_close_file(self, of);
937
of->x.of_filedes = fp->fil_filedes;
941
xt_sl_lock(self, fs_globals.fsg_open_files);
942
pushr_(xt_sl_unlock, fs_globals.fsg_open_files);
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);
953
fp->fil_handle_count++;
955
freer_(); // xt_ht_unlock(fs_globals.fsg_open_files)
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) {
963
mm = (XTFileMemMapPtr) xt_calloc(self, sizeof(XTFileMemMapRec));
964
pushr_(fs_close_fmap, mm);
967
/* NULL is the value returned on error! */
968
mm->mm_mapdes = NULL;
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;
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))
982
if (!fs_map_file(mm, fp, FALSE))
986
popr_(); // Discard fs_close_fmap(mm)
987
fp->x.fil_memmap = mm;
989
freer_(); // xt_ht_unlock(fs_globals.fsg_open_files)
991
of->x.mf_memmap = fp->x.fil_memmap;
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));
999
if (!fp->x.fil_heap) {
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);
1011
fh = (XTFileHeapPtr) xt_calloc(self, sizeof(XTFileHeapRec));
1012
pushr_(xt_free, fh);
1014
FILE_MAP_INIT_LOCK(self, &fh->fh_lock);
1015
fh->fh_grow_size = grow_size;
1017
popr_(); // Discard xt_free(fh)
1018
fp->x.fil_heap = fh;
1021
* This reference count is +1 for the file exists!
1022
* It will be decremented on file delete!
1024
fp->fil_ref_count++;
1026
freer_(); // xt_ht_unlock(fs_globals.fsg_open_files)
1027
of->x.of_heap = fp->x.fil_heap;
1032
popr_(); // Discard xt_close_file(of)
1036
xtPublic XTOpenFilePtr xt_open_file_ns(char *file, XTFileType type, int mode, size_t grow_size)
1038
XTThreadPtr self = xt_get_self();
1042
of = xt_open_file(self, file, type, mode, grow_size);
1051
xtPublic xtBool xt_open_file_ns(XTOpenFilePtr *fh, char *file, XTFileType type, int mode, size_t grow_size)
1053
XTThreadPtr self = xt_get_self();
1057
*fh = xt_open_file(self, file, type, mode, grow_size);
1066
xtPublic void xt_close_file(XTThreadPtr self, XTOpenFilePtr of)
1068
switch (of->of_type) {
1071
case XT_FT_REWRITE_FLUSH:
1072
case XT_FT_STANDARD:
1073
if (of->x.of_filedes != XT_NULL_FD) {
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));
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));
1088
of->x.of_filedes = XT_NULL_FD;
1092
xt_fs_release_file(self, of->fr_file);
1097
ASSERT_NS(!of->mf_slock_count);
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;
1111
ASSERT_NS(of->fr_file->fil_handle_count == 0);
1112
of->fr_file->fil_handle_count = 0;
1115
xt_fs_release_file(self, of->fr_file);
1118
of->x.mf_memmap = NULL;
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));
1125
xt_fs_release_file(self, of->fr_file);
1128
of->x.of_heap = NULL;
1134
xtPublic xtBool xt_close_file_ns(XTOpenFilePtr of)
1136
XTThreadPtr self = xt_get_self();
1137
xtBool failed = FALSE;
1140
xt_close_file(self, of);
1149
/* ----------------------------------------------------------------------
1153
xtPublic xtBool xt_lock_file(struct XTThread *self, XTOpenFilePtr of)
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));
1160
if (!LockFile(of->x.of_filedes, 0, 0, 512, 0)) {
1161
int err = fs_get_win_error();
1163
if (err == ERROR_LOCK_VIOLATION ||
1164
err == ERROR_LOCK_FAILED)
1167
xt_throw_ferrno(XT_CONTEXT, err, xt_file_path(of));
1172
if (lockf(of->x.of_filedes, F_TLOCK, 0) == 0)
1174
if (errno == EAGAIN)
1176
xt_throw_ferrno(XT_CONTEXT, errno, xt_file_path(of));
1181
xtPublic void xt_unlock_file(struct XTThread *self, XTOpenFilePtr of)
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));
1188
if (!UnlockFile(of->x.of_filedes, 0, 0, 512, 0)) {
1189
int err = fs_get_win_error();
1191
if (err != ERROR_NOT_LOCKED)
1192
xt_throw_ferrno(XT_CONTEXT, err, xt_file_path(of));
1195
if (lockf(of->x.of_filedes, F_ULOCK, 0) == -1)
1196
xt_throw_ferrno(XT_CONTEXT, errno, xt_file_path(of));
1200
static off_t fs_seek_eof(XTThreadPtr self, XT_FD fd, XTFilePtr file)
1204
LARGE_INTEGER lpFileSize;
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);
1212
if (!GetFileSizeEx(fd, &lpFileSize)) {
1213
xt_throw_ferrno(XT_CONTEXT, fs_get_win_error(), file->fil_path);
1217
return lpFileSize.QuadPart;
1221
off = lseek(fd, 0, SEEK_END);
1223
xt_throw_ferrno(XT_CONTEXT, errno, file->fil_path);
1231
xtPublic off_t xt_seek_eof_file(XTThreadPtr self, XTOpenFilePtr of)
1233
switch (of->of_type) {
1236
case XT_FT_REWRITE_FLUSH:
1237
case XT_FT_STANDARD:
1238
return fs_seek_eof(self, of->x.of_filedes, of->fr_file);
1240
return of->x.mf_memmap->mm_length;
1242
return of->x.of_heap->fh_length;
1247
xtPublic xtBool xt_set_eof_file(XTThreadPtr self, XTOpenFilePtr of, off_t offset)
1249
switch (of->of_type) {
1252
case XT_FT_REWRITE_FLUSH:
1253
case XT_FT_STANDARD:
1255
LARGE_INTEGER liDistanceToMove;
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));
1263
if (!SetEndOfFile(of->of_filedes)) {
1264
xt_throw_ferrno(XT_CONTEXT, fs_get_win_error(), xt_file_path(of));
1268
if (ftruncate(of->x.of_filedes, offset) == -1) {
1269
xt_throw_ferrno(XT_CONTEXT, errno, xt_file_path(of));
1275
xt_throw_ixterr(XT_CONTEXT, XT_ERR_FILE_OP_NOT_SUPP, xt_file_path(of));
1278
xt_throw_ixterr(XT_CONTEXT, XT_ERR_FILE_OP_NOT_SUPP, xt_file_path(of));
1284
static xtBool fs_rewrite_file(XTOpenFilePtr of, off_t offset, size_t size, void *data, XTIOStatsPtr stat, XTThreadPtr)
1286
#ifdef XT_TIME_DISK_WRITES
1291
LARGE_INTEGER liDistanceToMove;
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));
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));
1305
if ((size_t) result < 4) {
1306
xt_register_ferrno(XT_REG_CONTEXT, ERROR_HANDLE_EOF, xt_file_path(of));
1310
ASSERT_NS(offset + size == (offset + result + 1023) / 1024 * 1024);
1311
size = (size_t) result;
1313
stat->ts_read += (u_int) size;
1315
#ifdef XT_TIME_DISK_WRITES
1316
stat->ts_write_start = xt_trace_clock();
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));
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));
1330
if (result != size) {
1331
xt_register_ferrno(XT_REG_CONTEXT, ERROR_HANDLE_EOF, xt_file_path(of));
1335
ssize_t result_size;
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));
1343
/* Read may not work because of rounding: */
1344
ASSERT_NS(offset + size == (offset + result_size + 1023) / 1024 * 1024);
1347
stat->ts_read += (u_int) size;
1349
#ifdef XT_TIME_DISK_WRITES
1350
stat->ts_write_start = xt_trace_clock();
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));
1359
if ((size_t) result_size != size) {
1360
xt_register_ferrno(XT_REG_CONTEXT, ESPIPE, xt_file_path(of));
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;
1370
stat->ts_write += (u_int) size;
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;
1382
xtPublic xtBool xt_pwrite_file(XTOpenFilePtr of, off_t offset, size_t size, void *data, XTIOStatsPtr stat, XTThreadPtr thread)
1385
#ifdef XT_TIME_DISK_WRITES
1389
#if defined(DEBUG_TRACE_IO) || defined(DEBUG_TRACE_AROUND)
1391
xtWord8 start = xt_trace_clock();
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);
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
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);
1413
switch (of->of_type) {
1416
case XT_FT_REWRITE_FLUSH:
1417
XTRewriteFlushPtr rf;
1418
RewriteBlockPtr rec;
1422
xtWord8 flush_offset;
1424
rf = of->fr_file->x.fil_rewrite;
1426
/* Round up and down by 1K */
1427
block_offset = offset / 1024 * 1024;
1428
block_size = ((offset + size + 1023) / 1024 * 1024) - block_offset;
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;
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)
1446
/* Add the first entry: */
1450
/* Not the first entry: */
1452
rec = rf->rf_blocks + idx;
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;
1463
rec = rf->rf_blocks + idx;
1465
if (idx < rf->rf_block_count && rec->rb_offset - (block_offset + block_size) < XT_REWRITE_BLOCK_DISTANCE)
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;
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;
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));
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:
1503
off_t min_gap = (off_t) -1;
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) {
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));
1524
xt_spinlock_unlock(&rf->rf_lock);
1525
RR_FLUSH_READ_LOCK(&rf->rf_write_lock, thread->t_id);
1527
/* Wait for flush to pass this point: */
1529
flush_offset = ((xtWord8) rf->rf_flush_offset_hi << 32) | rf->rf_flush_offset_lo;
1530
if (offset < flush_offset)
1534
#ifdef XT_TIME_DISK_WRITES
1535
stat->ts_write_start = xt_trace_clock();
1538
LARGE_INTEGER liDistanceToMove;
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));
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));
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));
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));
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));
1575
RR_FLUSH_UNLOCK(&rf->rf_write_lock, thread->t_id);
1577
case XT_FT_STANDARD:
1578
#ifdef XT_TIME_DISK_WRITES
1579
stat->ts_write_start = xt_trace_clock();
1582
LARGE_INTEGER liDistanceToMove;
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));
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));
1596
if (result != size) {
1597
xt_register_ferrno(XT_REG_CONTEXT, ERROR_HANDLE_EOF, xt_file_path(of));
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));
1607
if ((size_t) write_size != size) {
1608
xt_register_ferrno(XT_REG_CONTEXT, ESPIPE, xt_file_path(of));
1613
case XT_FT_MEM_MAP: {
1614
XTFileMemMapPtr mm = of->x.mf_memmap;
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);
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);
1629
#ifdef XT_TIME_DISK_WRITES
1630
stat->ts_write_start = xt_trace_clock();
1635
memcpy(mm->mm_start + offset, data, size);
1637
// GetExceptionCode()== EXCEPTION_IN_PAGE_ERROR ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH
1638
__except(EXCEPTION_EXECUTE_HANDLER)
1640
xt_register_ferrno(XT_REG_CONTEXT, GetExceptionCode(), xt_file_path(map));
1641
FILE_MAP_UNLOCK(&mm->mm_lock, thd_id);
1645
memcpy(mm->mm_start + offset, data, size);
1648
FILE_MAP_UNLOCK(&mm->mm_lock, thd_id);
1652
XTFileHeapPtr fh = of->x.of_heap;
1654
#ifdef XT_TIME_DISK_WRITES
1655
stat->ts_write_start = xt_trace_clock();
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);
1663
FILE_MAP_WRITE_LOCK(&fh->fh_lock, thd_id);
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);
1671
fh->fh_length = new_len;
1674
memcpy(fh->fh_start + offset, data, size);
1676
FILE_MAP_UNLOCK(&fh->fh_lock, thd_id);
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;
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);
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));
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;
1705
xtPublic xtBool xt_flush_file(XTOpenFilePtr of, XTIOStatsPtr stat, XTThreadPtr thread)
1709
#if defined(DEBUG_TRACE_IO) || defined(DEBUG_TRACE_AROUND)
1711
xtWord8 start = xt_trace_clock();
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);
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);
1727
switch (of->of_type) {
1730
case XT_FT_REWRITE_FLUSH:
1731
XTRewriteFlushPtr rf;
1732
RewriteBlockPtr rec;
1738
rf = of->fr_file->x.fil_rewrite;
1740
xt_lock_mutex_ns(&rf->rf_flush_lock);
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);
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);
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;
1762
tfer = XT_REWRITE_BUFFER_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);
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));
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();
1793
if (!FlushFileBuffers(of->x.of_filedes)) {
1794
xt_register_ferrno(XT_REG_CONTEXT, fs_get_win_error(), xt_file_path(of));
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.
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));
1809
if (fsync(of->x.of_filedes) == -1) {
1810
xt_register_ferrno(XT_REG_CONTEXT, errno, xt_file_path(of));
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;
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);
1835
stat->ts_flush_start = xt_trace_clock();
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);
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);
1851
if (!of->mf_slock_count)
1852
FILE_MAP_UNLOCK(&mm->mm_lock, thd_id);
1856
stat->ts_flush_start = xt_trace_clock();
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);
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));
1867
s = stat->ts_flush_start;
1868
stat->ts_flush_start = 0;
1869
stat->ts_flush_time += xt_trace_clock() - s;
1874
s = stat->ts_flush_start;
1875
stat->ts_flush_start = 0;
1876
stat->ts_flush_time += xt_trace_clock() - s;
1880
xtPublic xtBool xt_pread_file_4(XTOpenFilePtr of, off_t offset, xtWord4 *value, XTIOStatsPtr stat, XTThreadPtr thread)
1883
#ifdef XT_TIME_DISK_READS
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);
1890
switch (of->of_type) {
1893
case XT_FT_REWRITE_FLUSH:
1894
case XT_FT_STANDARD:
1896
#ifdef XT_TIME_DISK_READS
1897
stat->ts_read_start = xt_trace_clock();
1900
LARGE_INTEGER liDistanceToMove;
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));
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));
1914
if ((size_t) result < 4) {
1915
xt_register_ferrno(XT_REG_CONTEXT, ERROR_HANDLE_EOF, xt_file_path(of));
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));
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));
1933
*value = XT_GET_DISK_4(data4);
1935
case XT_FT_MEM_MAP: {
1936
XTFileMemMapPtr mm = of->x.mf_memmap;
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);
1950
if (offset >= mm->mm_length)
1955
data = mm->mm_start + offset;
1956
#ifdef XT_TIME_DISK_READS
1957
stat->ts_read_start = xt_trace_clock();
1962
*value = XT_GET_DISK_4(data);
1963
// GetExceptionCode()== EXCEPTION_IN_PAGE_ERROR ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH
1965
__except(EXCEPTION_EXECUTE_HANDLER)
1967
FILE_MAP_UNLOCK(&mm->mm_lock, thd_id);
1968
xt_register_ferrno(XT_REG_CONTEXT, GetExceptionCode(), xt_file_path(of));
1972
*value = XT_GET_DISK_4(data);
1976
if (!of->mf_slock_count)
1977
FILE_MAP_UNLOCK(&mm->mm_lock, thd_id);
1981
XTFileHeapPtr fh = of->x.of_heap;
1982
thd_id = thread->t_id;
1984
#ifdef XT_TIME_DISK_READS
1985
stat->ts_read_start = xt_trace_clock();
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);
1998
if (offset >= fh->fh_length)
2003
data = fh->fh_start + offset;
2004
*value = XT_GET_DISK_4(data);
2006
if (!of->mf_slock_count)
2007
FILE_MAP_UNLOCK(&fh->fh_lock, thd_id);
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;
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;
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)
2033
#ifdef XT_TIME_DISK_READS
2037
#if defined(DEBUG_TRACE_IO) || defined(DEBUG_TRACE_AROUND)
2039
xtWord8 start = xt_trace_clock();
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);
2046
switch (of->of_type) {
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();
2055
LARGE_INTEGER liDistanceToMove;
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));
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));
2069
tfer = (size_t) result;
2073
result = pread(of->x.of_filedes, data, size, offset);
2075
xt_register_ferrno(XT_REG_CONTEXT, errno, xt_file_path(of));
2079
tfer = (size_t) result;
2082
case XT_FT_MEM_MAP: {
2083
XTFileMemMapPtr mm = of->x.mf_memmap;
2085
thd_id = thread->t_id;
2086
/* NOTE!! The file map may already be locked,
2087
* by a call to xt_lock_fmap_ptr()!
2089
* 20.05.2009: This problem should be fixed now with mf_slock_count!
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
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);
2107
* eval insert into t1 select a+@d,b+@d from t1;
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;
2118
* As a result, the slock must be able to handle
2119
* nested calls to lock/unlock.
2121
if (!of->mf_slock_count)
2122
FILE_MAP_READ_LOCK(&mm->mm_lock, thd_id);
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);
2134
if (offset >= mm->mm_length)
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();
2145
memcpy(data, mm->mm_start + offset, tfer);
2146
// GetExceptionCode()== EXCEPTION_IN_PAGE_ERROR ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH
2148
__except(EXCEPTION_EXECUTE_HANDLER)
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));
2156
memcpy(data, mm->mm_start + offset, tfer);
2159
if (!of->mf_slock_count)
2160
FILE_MAP_UNLOCK(&mm->mm_lock, thd_id);
2164
XTFileHeapPtr fh = of->x.of_heap;
2166
#ifdef XT_TIME_DISK_READS
2167
stat->ts_read_start = xt_trace_clock();
2169
thd_id = thread->t_id;
2170
if (!of->mf_slock_count)
2171
FILE_MAP_READ_LOCK(&fh->fh_lock, thd_id);
2173
if (offset >= fh->fh_length)
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);
2180
if (!of->mf_slock_count)
2181
FILE_MAP_UNLOCK(&fh->fh_lock, thd_id);
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;
2191
stat->ts_read += tfer;
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));
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);
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));
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;
2216
xtPublic xtBool xt_lock_file_ptr(XTOpenFilePtr of, xtWord1 **data, off_t offset, size_t size, XTIOStatsPtr stat, XTThreadPtr thread)
2218
switch (of->of_type) {
2221
case XT_FT_REWRITE_FLUSH:
2222
case XT_FT_STANDARD:
2226
if (!(*data = (xtWord1 *) xt_malloc_ns(size)))
2230
if (!xt_pread_file(of, offset, size, 0, *data, &red_size, stat, thread))
2233
//if (red_size < size)
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;
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);
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);
2263
if (offset + (off_t) size > mm->mm_length)
2264
stat->ts_read += (u_int) (offset + (off_t) size - mm->mm_length);
2266
stat->ts_read += size;
2267
*data = mm->mm_start + offset;
2271
XTFileHeapPtr fh = of->x.of_heap;
2272
#ifndef XT_NO_ATOMICS
2273
xtThreadID thd_id = thread->t_id;
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);
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);
2297
if (offset + (off_t) size > fh->fh_length)
2298
stat->ts_read += (u_int) (offset + (off_t) size - fh->fh_length);
2300
stat->ts_read += size;
2301
*data = fh->fh_start + offset;
2309
xtPublic void xt_unlock_file_ptr(XTOpenFilePtr of, xtWord1 *data, XTThreadPtr thread)
2311
switch (of->of_type) {
2314
case XT_FT_REWRITE_FLUSH:
2315
case XT_FT_STANDARD:
2320
of->mf_slock_count--;
2321
if (!of->mf_slock_count)
2322
FILE_MAP_UNLOCK(&of->x.mf_memmap->mm_lock, thread->t_id);
2325
of->mf_slock_count--;
2326
if (!of->mf_slock_count)
2327
FILE_MAP_UNLOCK(&of->x.of_heap->fh_lock, thread->t_id);
2332
/* ----------------------------------------------------------------------
2333
* Directory operations
2337
* The filter may contain one '*' as wildcard.
2339
XTOpenDirPtr xt_dir_open(XTThreadPtr self, c_char *path, c_char *filter)
2344
/* see the comment in filesys_xt.h */
2345
size_t sz = pathconf(path, _PC_NAME_MAX) + sizeof(XTOpenDirRec) + 1;
2347
size_t sz = sizeof(XTOpenDirRec);
2349
pushsr_(od, xt_dir_close, (XTOpenDirPtr) xt_calloc(self, sz));
2354
od->od_handle = XT_NULL_FD;
2356
// path = path\(filter | *)
2357
len = strlen(path) + 1 + (filter ? strlen(filter) : 1) + 1;
2358
od->od_path = (char *) xt_malloc(self, len);
2360
strcpy(od->od_path, path);
2361
xt_add_dir_char(len, od->od_path);
2363
strcat(od->od_path, filter);
2365
strcat(od->od_path, "*");
2367
od->od_path = xt_dup_string(self, path);
2370
od->od_filter = xt_dup_string(self, filter);
2372
od->od_dir = opendir(path);
2374
xt_throw_ferrno(XT_CONTEXT, errno, path);
2376
popr_(); // Discard xt_dir_close(od)
2380
void xt_dir_close(XTThreadPtr self, XTOpenDirPtr od)
2384
if (od->od_handle != XT_NULL_FD) {
2385
FindClose(od->od_handle);
2386
od->od_handle = XT_NULL_FD;
2390
closedir(od->od_dir);
2393
if (od->od_filter) {
2394
xt_free(self, od->od_filter);
2395
od->od_filter = NULL;
2399
xt_free(self, od->od_path);
2407
xtBool xt_dir_next(XTThreadPtr self, XTOpenDirPtr od)
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();
2417
if (!FindNextFile(od->od_handle, &od->od_data))
2418
err = fs_get_win_error();
2422
if (err != ERROR_NO_MORE_FILES) {
2423
if (err == ERROR_FILE_NOT_FOUND) {
2424
char path[PATH_MAX];
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);
2432
xt_throw_ferrno(XT_CONTEXT, err, od->od_path);
2440
static xtBool fs_match_filter(c_char *name, c_char *filter)
2442
while (*name && *filter) {
2443
if (*filter == '*') {
2444
if (filter[1] == *name)
2450
if (*name != *filter)
2457
if (!*filter || (*filter == '*' && !filter[1]))
2463
xtBool xt_dir_next(XTThreadPtr self, XTOpenDirPtr od)
2466
struct dirent *result;
2469
err = readdir_r(od->od_dir, &od->od_entry, &result);
2471
xt_throw_ferrno(XT_CONTEXT, err, od->od_path);
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')
2483
if (od->od_entry.d_name[1] == '\0')
2489
if (fs_match_filter(od->od_entry.d_name, od->od_filter))
2492
return result ? TRUE : FALSE;
2496
char *xt_dir_name(XTThreadPtr XT_UNUSED(self), XTOpenDirPtr od)
2499
return od->od_data.cFileName;
2501
return od->od_entry.d_name;
2505
xtBool xt_dir_is_file(XTThreadPtr self, XTOpenDirPtr od)
2509
if (od->od_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
2511
#elif defined(XT_SOLARIS)
2512
char path[PATH_MAX];
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);
2519
if (stat(path, &sb) == -1) {
2520
xt_throw_ferrno(XT_CONTEXT, errno, path);
2524
if ( sb.st_mode & S_IFDIR )
2527
if (od->od_entry.d_type & DT_DIR)
2533
off_t xt_dir_file_size(XTThreadPtr self, XTOpenDirPtr od)
2536
return (off_t) od->od_data.nFileSizeLow | (((off_t) od->od_data.nFileSizeHigh) << 32);
2538
char path[PATH_MAX];
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))
2550
/* ----------------------------------------------------------------------
2551
* File mapping operations
2554
static xtBool fs_map_file(XTFileMemMapPtr mm, XTFilePtr file, xtBool grow)
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);
2564
ASSERT_NS(!mm->mm_start);
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);
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);
2584
if (pwrite(file->fil_filedes, data, 1, mm->mm_length - 1) == -1) {
2585
xt_register_ferrno(XT_REG_CONTEXT, errno, file->fil_path);
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);
2601
static xtBool fs_remap_file(XTOpenFilePtr map, off_t offset, size_t size, XTIOStatsPtr stat)
2604
XTFileMemMapPtr mm = map->x.mf_memmap;
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;
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));
2619
else if (!mm->mm_start)
2620
new_size = mm->mm_length;
2624
/* Flush & unmap: */
2625
stat->ts_flush_start = xt_trace_clock();
2627
if (!FlushViewOfFile(mm->mm_start, 0)) {
2628
xt_register_ferrno(XT_REG_CONTEXT, fs_get_win_error(), xt_file_path(map));
2632
if (!UnmapViewOfFile(mm->mm_start)) {
2633
xt_register_ferrno(XT_REG_CONTEXT, fs_get_win_error(), xt_file_path(map));
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));
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));
2648
s = stat->ts_flush_start;
2649
stat->ts_flush_start = 0;
2650
stat->ts_flush_time += xt_trace_clock() - s;
2653
mm->mm_start = NULL;
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.
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;
2663
off_t old_size = mm->mm_length;
2664
mm->mm_length = new_size;
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);
2676
s = stat->ts_flush_start;
2677
stat->ts_flush_start = 0;
2678
stat->ts_flush_time += xt_trace_clock() - s;
2682
/* ----------------------------------------------------------------------
2683
* Copy files/directories
2686
static void fs_copy_file(XTThreadPtr self, char *from_path, char *to_path, void *copy_buf)
2691
size_t read_size= 0;
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);
2699
if (!xt_pread_file(from, offset, 16*1024, 0, copy_buf, &read_size, &self->st_statistics.st_x, self))
2703
if (!xt_pwrite_file(to, offset, read_size, copy_buf, &self->st_statistics.st_x, self))
2705
offset += (off_t) read_size;
2712
xtPublic void xt_fs_copy_file(XTThreadPtr self, char *from_path, char *to_path)
2716
buffer = xt_malloc(self, 16*1024);
2717
pushr_(xt_free, buffer);
2718
fs_copy_file(self, from_path, to_path, buffer);
2722
static void fs_copy_dir(XTThreadPtr self, char *from_path, char *to_path, void *copy_buf)
2727
xt_add_dir_char(PATH_MAX, from_path);
2728
xt_add_dir_char(PATH_MAX, to_path);
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);
2736
if (strcmp(file, "pbxt-lock") == 0)
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);
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);
2750
xt_remove_dir_char(from_path);
2751
xt_remove_dir_char(to_path);
2754
xtPublic void xt_fs_copy_dir(XTThreadPtr self, const char *from, const char *to)
2757
char from_path[PATH_MAX];
2758
char to_path[PATH_MAX];
2760
xt_strcpy(PATH_MAX, from_path, from);
2761
xt_strcpy(PATH_MAX, to_path, to);
2763
buffer = xt_malloc(self, 16*1024);
2764
pushr_(xt_free, buffer);
2765
fs_copy_dir(self, from_path, to_path, buffer);