Rename hed_blockoff_t -> hed_cursor_t
[hed.git] / libhed / file.h
blobd4482f243b609ede9b948515346bc3c65bde2ba7
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 LIBHED__FILE_H
23 #define LIBHED__FILE_H
25 #include <config.h>
27 #include <stdbool.h>
28 #include <string.h>
29 #include <sys/stat.h>
31 #include <libhed/types.h>
33 /* The block cache is organized as follows:
35 * At the start, there are two virtual blocks:
36 * --
38 * The first block covers the edited file (and has a physical size
39 * equal to the size of the file), the second block covers all
40 * possible file offsets beyond EOF (and has zero physical size).
42 * Then we can do a read and turn the virtual block to two, or shift its
43 * start/end:
44 * -x-
46 * After a while...
47 * x-xxx-xx-x-xxxxxxx-x
49 * As you can see, virtual blocks can have any size and stretch variably
50 * and fill the gaps between real blocks which have a size limit.
52 * Now, we can dirty some blocks:
53 * x-xxX-xx-x-xxxxxxx-x
55 * Even if we insert anything to the block, other blocks aren't touched,
56 * except when the block size hits the limit - then, the block will spawn
57 * another one:
58 * x-xxXX-xx-x-xxxxxxx-x
60 * Again, we don't touch other blocks during deletion. Only when the block
61 * size hits zero, we kill it:
62 * x-xxXX-xx-x-xxxxxx-x
64 * Note that we still keep around blocks which have any counterpart in the
65 * file, even if they are already dead in our current file image. This is
66 * necessary when reading more file blocks to the cache and when commiting
67 * the changes, in order to maintain offset consistency.
69 * When can size != phys_size?
70 * * byte(s) have been INSERTED into this block: size > phys_size
71 * Special case is an entire new block:
72 * in case of virtual blocks, phys_size MUST == 0 (gap)
73 * * byte(s) have been ERASED from this block: size < phys_size
74 * Virtual blocks are not permitted
77 struct hed_file_block {
78 struct hed_tree_head t;
79 struct hed_list_head lru;
81 /* Flags - see BLOCK_xxx below. */
82 long flags;
84 /* List of hed_cursor_t offsets which reference this
85 * structure. This is more flexible than refcounting,
86 * because you may actually do something to the file_block,
87 * as long as you update all the hed_cursor_t structs.
89 struct hed_list_head refs;
91 /* These are only valid for non-virtual blocks */
92 struct hed_file_data *dataobj;
93 size_t dataoff;
95 /* Physical position of this block. */
96 uoff_t phys_pos;
99 /* A hed_cursor_t consists of file position, its corresponding
100 * block pointer and the offset within that block.
102 typedef struct {
103 off_t pos;
104 struct hed_file_block *block;
105 uoff_t off;
106 struct hed_list_head list;
107 } hed_cursor_t;
109 #define NULL_CURSOR { 0, NULL, 0 }
111 #define BLOCK_DIRTY 0x01 /* data has been modified */
112 #define BLOCK_INSERTED 0x02 /* insert/delete block */
113 #define BLOCK_EXCACHE 0x04 /* block is NOT in the cache[] array
114 * and can be freed after it is undirtied */
115 #define BLOCK_VIRTUAL 0x08 /* "Virtual" block - must never be dirty
116 * nor excache; data is not valid - only
117 * size is meaningful. */
118 #define BLOCK_EOF 0x10 /* Purely virtual block beyond EOF. */
120 #define block_is_dirty(b) ((b)->flags & BLOCK_DIRTY)
121 #define block_set_dirty(b) ((b)->flags |= BLOCK_DIRTY)
122 #define block_clear_dirty(b) ((b)->flags &= ~BLOCK_DIRTY)
124 #define block_is_inserted(b) ((b)->flags & BLOCK_INSERTED)
125 #define block_set_inserted(b) ((b)->flags |= BLOCK_INSERTED)
126 #define block_clear_inserted(b) ((b)->flags &= ~BLOCK_INSERTED)
128 #define block_is_excache(b) ((b)->flags & BLOCK_EXCACHE)
129 #define block_set_excache(b) ((b)->flags |= BLOCK_EXCACHE)
130 #define block_clear_excache(b) ((b)->flags &= ~BLOCK_EXCACHE)
132 #define block_is_virtual(b) ((b)->flags & BLOCK_VIRTUAL)
133 #define block_set_virtual(b) ((b)->flags |= BLOCK_VIRTUAL)
134 #define block_clear_virtual(b) ((b)->flags &= ~BLOCK_VIRTUAL)
136 #define block_is_eof(b) ((b)->flags & BLOCK_EOF)
137 #define block_set_eof(b) ((b)->flags |= BLOCK_EOF)
138 #define block_clear_eof(b) ((b)->flags &= ~BLOCK_EOF)
140 #define block_is_inner_virtual(b) \
141 (((b)->flags & (BLOCK_VIRTUAL | BLOCK_EOF)) == BLOCK_VIRTUAL)
143 /* flags related to block allocation */
144 #define BLOCK_ALLOCMASK (BLOCK_EXCACHE)
146 /* flags related to block state */
147 #define BLOCK_STATEMASK (BLOCK_DIRTY | BLOCK_INSERTED | BLOCK_VIRTUAL)
149 static inline unsigned char *
150 block_data(struct hed_file_block *block)
152 return block->dataobj
153 ? block->dataobj->data + block->dataoff
154 : NULL;
157 /* File object */
159 #define MARKS_COUNT ('z' - 'a' + 1 + 'Z' - 'A' + 1)
161 struct hed_file {
162 /* The file blocks are sorted by the offset in this list. */
163 struct hed_tree blocks;
165 /* This list contains clean file-backed blocks.
166 * It is sorted from least recently used to most recently used. */
167 struct hed_list_head lru;
169 /* This cache holds the data for clean file-backed blocks. */
170 struct hed_file_cache *cache;
172 #ifdef CONFIG_READAHEAD
173 enum {
174 FILE_RA_NONE, /* No readahead */
175 FILE_RA_FORWARD, /* Read-ahead forwards */
176 FILE_RA_BACKWARD /* Read-ahead backwards */
177 } readahead;
178 #endif
180 int fd; /* file descriptor for read-only access */
181 uoff_t phys_size; /* physical size on disk */
182 uoff_t size; /* size after modifications */
184 const char *name; /* file name */
186 bool modified;
187 struct stat s;
189 #ifdef CONFIG_SWAP
190 char *swpname; /* original swap file name */
191 char *newswpname; /* new swap file name */
192 struct swp_file *swp;
193 struct hed_file_block *null_block;
194 #endif
196 hed_cursor_t marks[MARKS_COUNT];
199 #ifdef CONFIG_READAHEAD
200 static inline void
201 file_set_readahead(struct hed_file *file, int val)
203 file->readahead = val;
205 #else
206 # define file_set_readahead(file,t) do {} while(0)
207 #endif
209 static inline uoff_t
210 file_block_size(struct hed_file_block *block)
212 return block->t.size;
215 /* Returns true iff the block follows a deletion */
216 bool block_is_after_erase(const struct hed_tree *tree,
217 struct hed_file_block *block);
219 /* Returns true iff the block follows an insertion */
220 bool block_is_after_insert(const struct hed_tree *tree,
221 struct hed_file_block *block);
223 /*******************************************************************
224 * file object API
227 /* Global initialization */
228 int file_init(void);
230 /* Opens a file. */
231 struct hed_file *file_open(const char *name);
233 /* Closes the file. */
234 void file_close(struct hed_file *file);
236 /* Get the current file size */
237 static inline
238 uoff_t file_size(struct hed_file *file)
240 return file->size;
243 /* Get the blocks tree */
244 static inline struct hed_tree *
245 file_blocks(struct hed_file *file)
247 return &file->blocks;
250 /* Returns true iff the file has been modified */
251 static inline bool
252 file_is_modified(struct hed_file *file)
254 return file->modified;
257 /* Set the modified flag */
258 static inline void
259 file_set_modified(struct hed_file *file)
261 file->modified = true;
264 /* Clear the modified flag */
265 static inline void
266 file_clear_modified(struct hed_file *file)
268 file->modified = false;
271 /* Update the file size from the file system */
272 int file_update_size(struct hed_file *file);
274 /* Commits dirty blocks to the file. */
275 int file_commit(struct hed_file *file);
277 #ifdef CONFIG_SWAP
279 /* Return the swp file object */
280 static inline struct swp_file *
281 file_swp(struct hed_file *file)
283 return file->swp;
286 /* Saves dump of internal structures to disk. */
287 int file_write_swap(struct hed_file *file);
289 /* Loads dump of internal structures associated with given file from disk. */
290 int file_read_swap(struct hed_file *file);
292 /* Checks whether a swap file is available. */
293 int file_checkswp(struct hed_file *file);
295 /* Remoes dump of internal structures associated with given file from disk. */
296 int file_rmswp(struct hed_file *file);
298 #else /* CONFIG_SWAP */
300 /* Provide stubs for the non-swap case */
302 static inline void *
303 file_swp(struct hed_file *file)
305 return NULL;
308 static inline int
309 file_write_swap(struct hed_file *file)
311 return 0;
314 static inline int
315 file_read_swap(struct hed_file *file)
317 return -1;
320 static inline int
321 file_checkswp(struct hed_file *file)
323 return 1;
326 static inline int
327 file_rmswp(struct hed_file *file)
329 return 0;
332 #endif /* CONFIG_SWAP */
334 /* Fetches the required part of the file. The real size is saved to *size.
335 * On error, *size == 0, and the call returns NULL.
336 * The error code is available in @errno.
338 * Please note that even for incomplete reads, the memory pointed at
339 * by the return value will be allocated to the full size as specified
340 * by *size. So should the buffer be held for a longer time, you might
341 * want to reallocate the buffer to the exact length. */
342 void *file_fetch_block(struct hed_file *file, uoff_t offset, size_t *size);
344 /* Converts a logical @offset to a cursor (@curs). Returns
345 * non-zero on error, and the error code is available in @errno.
347 void file_get_cursor(struct hed_file *file, uoff_t offset,
348 hed_cursor_t *curs);
350 /* Mark @curs as no longer needed. In particular, this stops tracking
351 * file changes with this pointer.
353 void file_put_cursor(hed_cursor_t *curs);
355 /* Duplicate into an empty hed_cursor_t */
356 void file_dup_cursor(const hed_cursor_t *src, hed_cursor_t *dst);
358 /* Duplicate into an initialized hed_cursor_t */
359 void file_dup2_cursor(const hed_cursor_t *src, hed_cursor_t *dst);
361 #define is_a_cursor(curs) (!!(curs)->block)
363 /* Relative move from a given block offset.
364 * If the resulting position is out of bounds (either < 0 or > OFF_MAX),
365 * the offset is adjusted to only move to 0 or OFF_MAX.
366 * Returns the actual offset which was used.
368 off_t file_move_relative(hed_cursor_t *curs, off_t num);
370 /* Given you know that offset is just one byte beyond the last span,
371 * get the block which contains byte at @curs.
372 * If the block is not available, it is loaded from disk, so do not
373 * use this function if you only want to iterate through virtual
374 * blocks.
375 * Returns non-zero on error, and the error code is available in @errno.
377 int file_next_block(struct hed_file *file, hed_cursor_t *curs);
379 /* Ensure reads are valid from a block offset.
380 * Returns:
381 * <0 on error
382 * 0 on success
384 int file_read_begin(struct hed_file *file, const hed_cursor_t *curs);
386 /* Do whatever cleanup is necessary when read is complete. */
387 void file_read_end(struct hed_file *file);
389 /* Copy in @count bytes from file @file at @pos to @buf.
390 * Returns number of bytes which were not copied, i.e. zero on success.
392 size_t file_cpin(struct hed_file *file, void *buf, size_t count,
393 const hed_cursor_t *pos);
395 /* Find a given sequence of bytes in the file, starting at the @pos file
396 * offset and possibly wrapping around. @dir is +1 or -1. */
397 int file_find_expr(struct hed_file *file, hed_cursor_t *pos, int dir,
398 struct hed_expr *expr,
399 hed_expr_reg_cb expr_cb, void *expr_cb_data);
400 #define FINDOFF_NO_MATCH -1
401 #define FINDOFF_ERROR -2
403 /* Sets a single byte in the file. */
404 int file_set_byte(struct hed_file *file, hed_cursor_t *curs,
405 unsigned char byte);
406 /* Sets multiple bytes in the file. */
407 size_t file_set_block(struct hed_file *file, hed_cursor_t *curs,
408 unsigned char *buf, size_t len);
409 uoff_t file_set_bytes(struct hed_file *file, hed_cursor_t *curs,
410 unsigned char byte, uoff_t rep);
412 /* To insert bytes:
413 * 1. call file_insert_begin() with the cursor position and store the
414 * insert physical position.
415 * 2. call file_insert_byte() and/or file_insert_block() on the insert pos,
416 * possibly repeatedly
417 * 3. call file_insert_end() on the insert pos and forget all about it;
418 * be careful with aliases, because the insert might get merged/freed
420 int file_insert_begin(struct hed_file *file,
421 hed_cursor_t *curs, hed_cursor_t *curs_ins);
422 void file_insert_end(struct hed_file *file, hed_cursor_t *curs_ins);
424 /* Inserts a single byte to the file. */
425 int file_insert_byte(struct hed_file *file, hed_cursor_t *curs,
426 unsigned char byte);
427 /* Insert a block of bytes to the file. */
428 size_t file_insert_block(struct hed_file *file, hed_cursor_t *curs,
429 unsigned char *buf, size_t len);
431 /* The following function is a shorthand for the usual
432 * file_insert_begin, file_insert_block, file_insert_end
433 * sequence.
435 size_t file_insert_once(struct hed_file *file, hed_cursor_t *curs,
436 unsigned char *buf, size_t len);
438 /* Erases a single byte from the file. */
439 # define file_erase_byte(file,curs) (file_erase_block((file),(curs),1))
441 /* Erases a block of bytes from the file. */
442 size_t file_erase_block(struct hed_file *file, hed_cursor_t *curs, uoff_t len);
444 /*******************************************************************
445 * MARK FUNCTIONS
448 /* Returns true iff @mark is a valid mark */
449 static inline bool
450 file_mark_is_valid(struct hed_file *file, int mark)
452 return is_a_cursor(&file->marks[mark]);
455 /* Return pointer to a mark */
456 static inline hed_cursor_t*
457 file_mark(struct hed_file *file, int mark)
459 return &file->marks[mark];
462 #endif