Move global initialization to file_init()
[hed.git] / src / file / file.h
blob52afee466deb5f8023f1d3b13b8a68998f96a777
1 /* The file handling */
2 /* $Id$ */
4 /*
5 * hed - Hexadecimal editor
6 * Copyright (C) 2004 Petr Baudis <pasky@ucw.cz>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of version 2 of the GNU General Public License as
10 * published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #ifndef HED__FILE_FILE_H
23 #define HED__FILE_FILE_H
25 #include "config.h"
27 #include <string.h>
28 #include <sys/stat.h>
30 #include "eval/eval.h"
31 #include "file/fixup.h"
33 #include "file/access.h"
34 #include "file/cache.h"
35 #include "file/tree.h"
36 #include "file/swap.h"
37 #include "util/lists.h"
39 /* The block cache is organized as follows:
41 * At the start, there are two virtual blocks:
42 * --
44 * The first block covers the edited file (and has a physical size
45 * equal to the size of the file), the second block covers all
46 * possible file offsets beyond EOF (and has zero physical size).
48 * Then we can do a read and turn the virtual block to two, or shift its
49 * start/end:
50 * -x-
52 * After a while...
53 * x-xxx-xx-x-xxxxxxx-x
55 * As you can see, virtual blocks can have any size and stretch variably
56 * and fill the gaps between real blocks which have a size limit.
58 * Now, we can dirty some blocks:
59 * x-xxX-xx-x-xxxxxxx-x
61 * Even if we insert anything to the block, other blocks aren't touched,
62 * except when the block size hits the limit - then, the block will spawn
63 * another one:
64 * x-xxXX-xx-x-xxxxxxx-x
66 * Again, we don't touch other blocks during deletion. Only when the block
67 * size hits zero, we kill it:
68 * x-xxXX-xx-x-xxxxxx-x
70 * Note that we still keep around blocks which have any counterpart in the
71 * file, even if they are already dead in our current file image. This is
72 * necessary when reading more file blocks to the cache and when commiting
73 * the changes, in order to maintain offset consistency.
75 * When can size != phys_size?
76 * * byte(s) have been INSERTED into this block: size > phys_size
77 * Special case is an entire new block:
78 * in case of virtual blocks, phys_size MUST == 0 (gap)
79 * * byte(s) have been ERASED from this block: size < phys_size
80 * Virtual blocks are not permitted
83 struct file_block {
84 struct tree_head t;
85 struct list_head lru;
87 /* Flags - see BLOCK_xxx below. */
88 long flags;
90 /* List of blockoff_t offsets which reference this
91 * structure. This is more flexible than refcounting,
92 * because you may actually do something to the file_block,
93 * as long as you update all the blockoff_t structs.
95 struct list_head refs;
97 /* These are only valid for non-virtual blocks */
98 struct file_data *dataobj;
99 size_t dataoff;
101 /* Physical position of this block. */
102 uoff_t phys_pos;
105 /* A blockoff_t consists of file position, its corresponding
106 * block pointer and the offset within that block.
108 typedef struct {
109 off_t pos;
110 struct file_block *block;
111 uoff_t off;
112 struct list_head list;
113 } blockoff_t;
115 #define NULL_BLOCKOFF { 0, NULL, 0 }
117 #define BLOCK_DIRTY 0x01 /* data has been modified */
118 #define BLOCK_INSERTED 0x02 /* insert/delete block */
119 #define BLOCK_EXCACHE 0x04 /* block is NOT in the cache[] array
120 * and can be freed after it is undirtied */
121 #define BLOCK_VIRTUAL 0x08 /* "Virtual" block - must never be dirty
122 * nor excache; data is not valid - only
123 * size is meaningful. */
124 #define BLOCK_EOF 0x10 /* Purely virtual block beyond EOF. */
126 #define block_is_dirty(b) ((b)->flags & BLOCK_DIRTY)
127 #define block_set_dirty(b) ((b)->flags |= BLOCK_DIRTY)
128 #define block_clear_dirty(b) ((b)->flags &= ~BLOCK_DIRTY)
130 #define block_is_inserted(b) ((b)->flags & BLOCK_INSERTED)
131 #define block_set_inserted(b) ((b)->flags |= BLOCK_INSERTED)
132 #define block_clear_inserted(b) ((b)->flags &= ~BLOCK_INSERTED)
134 #define block_is_excache(b) ((b)->flags & BLOCK_EXCACHE)
135 #define block_set_excache(b) ((b)->flags |= BLOCK_EXCACHE)
136 #define block_clear_excache(b) ((b)->flags &= ~BLOCK_EXCACHE)
138 #define block_is_virtual(b) ((b)->flags & BLOCK_VIRTUAL)
139 #define block_set_virtual(b) ((b)->flags |= BLOCK_VIRTUAL)
140 #define block_clear_virtual(b) ((b)->flags &= ~BLOCK_VIRTUAL)
142 #define block_is_eof(b) ((b)->flags & BLOCK_EOF)
143 #define block_set_eof(b) ((b)->flags |= BLOCK_EOF)
144 #define block_clear_eof(b) ((b)->flags &= ~BLOCK_EOF)
146 #define block_is_inner_virtual(b) \
147 (((b)->flags & (BLOCK_VIRTUAL | BLOCK_EOF)) == BLOCK_VIRTUAL)
149 /* flags related to block allocation */
150 #define BLOCK_ALLOCMASK (BLOCK_EXCACHE)
152 /* flags related to block state */
153 #define BLOCK_STATEMASK (BLOCK_DIRTY | BLOCK_INSERTED | BLOCK_VIRTUAL)
155 static inline unsigned char *
156 block_data(struct file_block *block)
158 return block->dataobj
159 ? block->dataobj->data + block->dataoff
160 : NULL;
163 /* File object */
165 #define MARKS_COUNT ('z' - 'a' + 1 + 'Z' - 'A' + 1)
167 struct file {
168 /* The file blocks are sorted by the offset in this list. */
169 struct tree blocks;
171 /* This list contains clean file-backed blocks.
172 * It is sorted from least recently used to most recently used. */
173 struct list_head lru;
175 /* This cache holds the data for clean file-backed blocks. */
176 struct file_cache *cache;
178 #ifdef CONFIG_READAHEAD
179 enum {
180 FILE_RA_NONE, /* No readahead */
181 FILE_RA_FORWARD, /* Read-ahead forwards */
182 FILE_RA_BACKWARD /* Read-ahead backwards */
183 } readahead;
184 #endif
186 int fd; /* file descriptor for read-only access */
187 uoff_t phys_size; /* physical size on disk */
188 uoff_t size; /* size after modifications */
190 const char *name; /* file name */
192 bool modified;
193 struct stat s;
195 #ifdef CONFIG_SWAP
196 char *swpname; /* original swap file name */
197 char *newswpname; /* new swap file name */
198 struct swp_file *swp;
199 struct file_block *null_block;
200 #endif
202 blockoff_t marks[MARKS_COUNT];
205 #ifdef CONFIG_READAHEAD
206 static inline void
207 file_set_readahead(struct file *file, int val)
209 file->readahead = val;
211 #else
212 # define file_set_readahead(file,t) do {} while(0)
213 #endif
215 static inline uoff_t
216 file_block_size(struct file_block *block)
218 return block->t.size;
221 /* Returns true iff the block follows a deletion */
222 bool block_is_after_erase(const struct tree *tree, struct file_block *block);
224 /* Returns true iff the block follows an insertion */
225 bool block_is_after_insert(const struct tree *tree, struct file_block *block);
227 /*******************************************************************
228 * file object API
231 /* Global initialization */
232 int file_init(void);
234 /* Opens a file. */
235 struct file *file_open(const char *name);
237 /* Closes the file. */
238 void file_close(struct file *file);
240 /* Get the current file size */
241 static inline
242 uoff_t file_size(struct file *file)
244 return file->size;
247 /* Get the blocks tree */
248 static inline struct tree *
249 file_blocks(struct file *file)
251 return &file->blocks;
254 /* Returns true iff the file has been modified */
255 static inline bool
256 file_is_modified(struct file *file)
258 return file->modified;
261 /* Set the modified flag */
262 static inline void
263 file_set_modified(struct file *file)
265 file->modified = true;
268 /* Clear the modified flag */
269 static inline void
270 file_clear_modified(struct file *file)
272 file->modified = false;
275 /* Update the file size from the file system */
276 int file_update_size(struct file *file);
278 /* Commits dirty blocks to the file. */
279 int file_commit(struct file *file);
281 #ifdef CONFIG_SWAP
283 /* Return the swp file object */
284 static inline struct swp_file *
285 file_swp(struct file *file)
287 return file->swp;
290 /* Saves dump of internal structures to disk. */
291 static inline int
292 file_write_swap(struct file *file)
294 return swp_write(file_swp(file));
297 /* Loads dump of internal structures associated with given file from disk. */
298 int file_read_swap(struct file *file);
300 /* Checks whether a swap file is available. */
301 int file_checkswp(struct file *file);
303 /* Remoes dump of internal structures associated with given file from disk. */
304 int file_rmswp(struct file *file);
306 #else /* CONFIG_SWAP */
308 /* Provide stubs for the non-swap case */
310 static inline void *
311 file_swp(struct file *file)
313 return NULL;
316 static inline int
317 file_write_swap(struct file *file)
319 return 0;
322 static inline int
323 file_read_swap(struct file *file)
325 return -1;
328 static inline int
329 file_checkswp(struct file *file)
331 return 1;
334 static inline int
335 file_rmswp(struct file *file)
337 return 0;
340 #endif /* CONFIG_SWAP */
342 /* Fetches the required part of the file. The real size is saved to *size.
343 * On error, *size == 0, and the call returns NULL.
344 * The error code is available in @errno.
346 * Please note that even for incomplete reads, the memory pointed at
347 * by the return value will be allocated to the full size as specified
348 * by *size. So should the buffer be held for a longer time, you might
349 * want to reallocate the buffer to the exact length. */
350 void *file_fetch_block(struct file *file, uoff_t offset, size_t *size);
352 /* Converts a logical @offset to a block plus offset (@blockoff). Returns
353 * non-zero on error, and the error code is available in @errno.
355 void file_get_blockoff(struct file *file, uoff_t offset, blockoff_t *blockoff);
357 static inline void file_put_blockoff(blockoff_t *blockoff)
359 list_del(&blockoff->list);
362 /* Duplicate into an empty blockoff_t */
363 void file_dup_blockoff(const blockoff_t *src, blockoff_t *dst);
365 /* Duplicate into an initialized blockoff_t */
366 void file_dup2_blockoff(const blockoff_t *src, blockoff_t *dst);
368 #define is_a_blockoff(blockoff) (!!(blockoff)->block)
370 /* Relative move from a given block offset.
371 * If the resulting position is out of bounds (either < 0 or > OFF_MAX),
372 * the offset is adjusted to only move to 0 or OFF_MAX.
373 * Returns the actual offset which was used.
375 off_t file_move_relative(blockoff_t *blockoff, off_t num);
377 /* Given you know that offset is just one byte beyond the last span,
378 * get the block which contains byte at @blockoff.
379 * If the block is not available, it is loaded from disk, so do not
380 * use this function if you only want to iterate through virtual
381 * blocks.
382 * Returns non-zero on error, and the error code is available in @errno.
384 int file_next_block(struct file *file, blockoff_t *blockoff);
386 /* Ensure reads are valid from a block offset.
387 * Returns:
388 * <0 on error
389 * 0 on success
391 int file_read_begin(struct file *file, const blockoff_t *blockoff);
393 static inline void
394 file_read_end(struct file *file)
396 fixup_end();
399 /* Copy in @count bytes from file @file at @pos to @buf.
400 * Returns number of bytes which were not copied, i.e. zero on success.
402 size_t file_cpin(struct file *file, void *buf, size_t count,
403 const blockoff_t *pos);
405 /* Find a given sequence of bytes in the file, starting at the @pos file
406 * offset and possibly wrapping around. @dir is +1 or -1. */
407 int file_find_expr(struct file *file, blockoff_t *pos, int dir, struct expression *expr, reg_callback expr_cb, void *expr_cb_data);
408 #define FINDOFF_NO_MATCH -1
409 #define FINDOFF_ERROR -2
411 /* Sets a single byte in the file. */
412 int file_set_byte(struct file *file, blockoff_t *blockoff, unsigned char byte);
413 /* Sets multiple bytes in the file. */
414 size_t file_set_block(struct file *file, blockoff_t *blockoff, unsigned char *buf, size_t len);
415 uoff_t file_set_bytes(struct file *file, blockoff_t *blockoff, unsigned char byte, uoff_t rep);
417 /* To insert bytes:
418 * 1. call file_insert_begin() with the cursor position and store the
419 * insert physical position.
420 * 2. call file_insert_byte() and/or file_insert_block() on the insert pos,
421 * possibly repeatedly
422 * 3. call file_insert_end() on the insert pos and forget all about it;
423 * be careful with aliases, because the insert might get merged/freed
425 int file_insert_begin(struct file *file,
426 blockoff_t *blockoff, blockoff_t *blockoff_ins);
427 void file_insert_end(struct file *file, blockoff_t *blockoff_ins);
429 /* Inserts a single byte to the file. */
430 int file_insert_byte(struct file *file, blockoff_t *blockoff, unsigned char byte);
431 /* Insert a block of bytes to the file. */
432 size_t file_insert_block(struct file *file, blockoff_t *blockoff, unsigned char *buf, size_t len);
434 /* The following function is a shorthand for the usual
435 * file_insert_begin, file_insert_block, file_insert_end
436 * sequence.
438 size_t file_insert_once(struct file *file, blockoff_t *blockoff,
439 unsigned char *buf, size_t len);
441 /* Erases a single byte from the file. */
442 # define file_erase_byte(file,blockoff) (file_erase_block((file),(blockoff),1))
444 /* Erases a block of bytes from the file. */
445 size_t file_erase_block(struct file *file, blockoff_t *blockoff, uoff_t len);
447 /*******************************************************************
448 * MARK FUNCTIONS
451 /* Returns true iff @mark is a valid mark */
452 static inline bool
453 file_mark_is_valid(struct file *file, int mark)
455 return is_a_blockoff(&file->marks[mark]);
458 /* Return pointer to a mark */
459 static inline blockoff_t*
460 file_mark(struct file *file, int mark)
462 return &file->marks[mark];
465 static inline char
466 ch2mark(char ch)
468 return ('a' <= ch && ch <= 'z') ? ch - 'a' :
469 ('A' <= ch && ch <= 'Z') ? 26 + ch - 'A' :
473 #endif