5 #include "fileio.h" |
5 #include "fileio.h" |
6 #include "functions.h" |
6 #include "functions.h" |
7 #include "string.h" |
7 #include "string.h" |
8 #include "macros.h" |
8 #include "macros.h" |
9 #include "variables.h" |
9 #include "variables.h" |
|
10 #include "debug.h" |
10 |
11 |
11 /*************************************************/ |
12 /*************************************************/ |
12 /* FILE IO ROUTINES ******************************/ |
13 /* FILE IO ROUTINES ******************************/ |
13 /*************************************************/ |
14 /*************************************************/ |
14 |
15 |
15 #define FIO_BUFFER_SIZE 512 |
16 #define FIO_BUFFER_SIZE 512 |
|
17 #define MAX_HANDLES 64 |
16 |
18 |
17 typedef struct { |
19 typedef struct { |
18 byte *buffer, *buffer_end; ///< position pointer in local buffer and last valid byte of buffer |
20 byte *buffer, *buffer_end; ///< position pointer in local buffer and last valid byte of buffer |
19 uint32 pos; ///< current (system) position in file |
21 uint32 pos; ///< current (system) position in file |
20 FILE *cur_fh; ///< current file handle |
22 FILE *cur_fh; ///< current file handle |
21 FILE *handles[64]; ///< array of file handles we can have open |
23 FILE *handles[MAX_HANDLES]; ///< array of file handles we can have open |
22 byte buffer_start[FIO_BUFFER_SIZE]; ///< local buffer when read from file |
24 byte buffer_start[FIO_BUFFER_SIZE]; ///< local buffer when read from file |
|
25 #if defined(LIMITED_FDS) |
|
26 uint open_handles; ///< current amount of open handles |
|
27 const char *filename[MAX_HANDLES]; ///< array of filenames we (should) have open |
|
28 uint usage_count[MAX_HANDLES]; ///< count how many times this file has been opened |
|
29 #endif /* LIMITED_FDS */ |
23 } Fio; |
30 } Fio; |
24 |
31 |
25 static Fio _fio; |
32 static Fio _fio; |
26 |
33 |
27 // Get current position in file |
34 // Get current position in file |
36 _fio.buffer = _fio.buffer_end = _fio.buffer_start + FIO_BUFFER_SIZE; |
43 _fio.buffer = _fio.buffer_end = _fio.buffer_start + FIO_BUFFER_SIZE; |
37 _fio.pos = pos; |
44 _fio.pos = pos; |
38 fseek(_fio.cur_fh, _fio.pos, SEEK_SET); |
45 fseek(_fio.cur_fh, _fio.pos, SEEK_SET); |
39 } |
46 } |
40 |
47 |
|
48 #if defined(LIMITED_FDS) |
|
49 static void FioRestoreFile(int slot) |
|
50 { |
|
51 /* Do we still have the file open, or should we reopen it? */ |
|
52 if (_fio.handles[slot] == NULL) { |
|
53 DEBUG(misc, 6, "Restoring file '%s' in slot '%d' from disk", _fio.filename[slot], slot); |
|
54 FioOpenFile(slot, _fio.filename[slot]); |
|
55 } |
|
56 _fio.usage_count[slot]++; |
|
57 } |
|
58 #endif /* LIMITED_FDS */ |
|
59 |
41 // Seek to a file and a position |
60 // Seek to a file and a position |
42 void FioSeekToFile(uint32 pos) |
61 void FioSeekToFile(uint32 pos) |
43 { |
62 { |
44 FILE *f = _fio.handles[pos >> 24]; |
63 FILE *f; |
|
64 #if defined(LIMITED_FDS) |
|
65 /* Make sure we have this file open */ |
|
66 FioRestoreFile(pos >> 24); |
|
67 #endif /* LIMITED_FDS */ |
|
68 f = _fio.handles[pos >> 24]; |
45 assert(f != NULL); |
69 assert(f != NULL); |
46 _fio.cur_fh = f; |
70 _fio.cur_fh = f; |
47 FioSeekTo(GB(pos, 0, 24), SEEK_SET); |
71 FioSeekTo(GB(pos, 0, 24), SEEK_SET); |
48 } |
72 } |
49 |
73 |
90 static inline void FioCloseFile(int slot) |
114 static inline void FioCloseFile(int slot) |
91 { |
115 { |
92 if (_fio.handles[slot] != NULL) { |
116 if (_fio.handles[slot] != NULL) { |
93 fclose(_fio.handles[slot]); |
117 fclose(_fio.handles[slot]); |
94 _fio.handles[slot] = NULL; |
118 _fio.handles[slot] = NULL; |
|
119 #if defined(LIMITED_FDS) |
|
120 _fio.open_handles--; |
|
121 #endif /* LIMITED_FDS */ |
95 } |
122 } |
96 } |
123 } |
97 |
124 |
98 void FioCloseAll(void) |
125 void FioCloseAll(void) |
99 { |
126 { |
109 if (f == NULL) return false; |
136 if (f == NULL) return false; |
110 |
137 |
111 fclose(f); |
138 fclose(f); |
112 return true; |
139 return true; |
113 } |
140 } |
|
141 |
|
142 #if defined(LIMITED_FDS) |
|
143 static void FioFreeHandle() |
|
144 { |
|
145 /* If we are about to open a file that will exceed the limit, close a file */ |
|
146 if (_fio.open_handles + 1 == LIMITED_FDS) { |
|
147 uint i, count; |
|
148 int slot; |
|
149 |
|
150 count = UINT_MAX; |
|
151 slot = -1; |
|
152 /* Find the file that is used the least */ |
|
153 for (i = 0; i < lengthof(_fio.handles); i++) { |
|
154 if (_fio.handles[i] != NULL && _fio.usage_count[i] < count) { |
|
155 count = _fio.usage_count[i]; |
|
156 slot = i; |
|
157 } |
|
158 } |
|
159 assert(slot != -1); |
|
160 DEBUG(misc, 6, "Closing filehandler '%s' in slot '%d' because of fd-limit", _fio.filename[slot], slot); |
|
161 FioCloseFile(slot); |
|
162 } |
|
163 } |
|
164 #endif /* LIMITED_FDS */ |
114 |
165 |
115 FILE *FioFOpenFile(const char *filename) |
166 FILE *FioFOpenFile(const char *filename) |
116 { |
167 { |
117 FILE *f; |
168 FILE *f; |
118 char buf[MAX_PATH]; |
169 char buf[MAX_PATH]; |
139 return f; |
190 return f; |
140 } |
191 } |
141 |
192 |
142 void FioOpenFile(int slot, const char *filename) |
193 void FioOpenFile(int slot, const char *filename) |
143 { |
194 { |
144 FILE *f = FioFOpenFile(filename); |
195 FILE *f; |
145 |
196 |
|
197 #if defined(LIMITED_FDS) |
|
198 FioFreeHandle(); |
|
199 #endif /* LIMITED_FDS */ |
|
200 f = FioFOpenFile(filename); |
146 if (f == NULL) error("Cannot open file '%s%s'", _paths.data_dir, filename); |
201 if (f == NULL) error("Cannot open file '%s%s'", _paths.data_dir, filename); |
147 |
202 |
148 FioCloseFile(slot); // if file was opened before, close it |
203 FioCloseFile(slot); // if file was opened before, close it |
149 _fio.handles[slot] = f; |
204 _fio.handles[slot] = f; |
|
205 #if defined(LIMITED_FDS) |
|
206 _fio.filename[slot] = filename; |
|
207 _fio.usage_count[slot] = 0; |
|
208 _fio.open_handles++; |
|
209 #endif /* LIMITED_FDS */ |
150 FioSeekToFile(slot << 24); |
210 FioSeekToFile(slot << 24); |
151 } |
211 } |