Merge hed_cursor_chunk_len with hed_prepare_read
[hed.git] / libhed / file.h
blobf873ed39cdf35c29f57d2f0f8f0bfc5dbf717e2d
1 /* The file handling */
3 /* This is a libhed PUBLIC file.
4 * This header file will be installed on the target system.
5 * When you add new things here, make sure they start with hed_.
6 */
8 /*
9 * hed - Hexadecimal editor
10 * Copyright (C) 2004 Petr Baudis <pasky@ucw.cz>
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of version 2 of the GNU General Public License as
14 * published by the Free Software Foundation.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #ifndef LIBHED__FILE_H
27 #define LIBHED__FILE_H
29 #include <libhed/config.h>
31 #include <stdbool.h>
32 #include <string.h>
33 #include <sys/stat.h>
35 #include <libhed/types.h>
36 #include <libhed/expr.h>
38 /* The block cache is organized as follows:
40 * At the start, there are two virtual blocks:
41 * --
43 * The first block covers the edited file (and has a physical size
44 * equal to the size of the file), the second block covers all
45 * possible file offsets beyond EOF (and has zero physical size).
47 * Then we can do a read and turn the virtual block to two, or shift its
48 * start/end:
49 * -x-
51 * After a while...
52 * x-xxx-xx-x-xxxxxxx-x
54 * As you can see, virtual blocks can have any size and stretch variably
55 * and fill the gaps between real blocks which have a size limit.
57 * Now, we can dirty some blocks:
58 * x-xxX-xx-x-xxxxxxx-x
60 * Even if we insert anything to the block, other blocks aren't touched,
61 * except when the block size hits the limit - then, the block will spawn
62 * another one:
63 * x-xxXX-xx-x-xxxxxxx-x
65 * Again, we don't touch other blocks during deletion. Only when the block
66 * size hits zero, we kill it:
67 * x-xxXX-xx-x-xxxxxx-x
69 * Note that we still keep around blocks which have any counterpart in the
70 * file, even if they are already dead in our current file image. This is
71 * necessary when reading more file blocks to the cache and when commiting
72 * the changes, in order to maintain offset consistency.
74 * When can size != phys_size?
75 * * byte(s) have been INSERTED into this block: size > phys_size
76 * Special case is an entire new block:
77 * in case of virtual blocks, phys_size MUST == 0 (gap)
78 * * byte(s) have been ERASED from this block: size < phys_size
79 * Virtual blocks are not permitted
82 struct hed_block {
83 struct hed_tree_head t;
84 struct hed_list_head lru;
86 /* Flags - see HED_BLOCK_xxx below. */
87 long flags;
89 /* List of hed_cursor_t offsets which reference this
90 * structure. This is more flexible than refcounting,
91 * because you may actually do something to the file_block,
92 * as long as you update all the hed_cursor_t structs.
94 struct hed_list_head refs;
96 /* These are only valid for non-virtual blocks */
97 struct hed_block_data *dataobj;
98 size_t dataoff;
100 /* Physical position of this block. */
101 hed_uoff_t phys_pos;
104 #define HED_BLOCK_DIRTY 0x01 /* data has been modified */
105 #define HED_BLOCK_INSERTED 0x02 /* insert/delete block */
106 #define HED_BLOCK_EXCACHE 0x04 /* block is NOT in the cache[] array
107 and can be freed after it is
108 undirtied */
109 #define HED_BLOCK_VIRTUAL 0x08 /* "Virtual" block - must never be
110 dirty nor excache; data is not
111 valid - only size is meaningful. */
112 #define HED_BLOCK_EOF 0x10 /* Purely virtual block beyond EOF. */
114 #define hed_block_is_dirty(b) ((b)->flags & HED_BLOCK_DIRTY)
115 #define hed_block_set_dirty(b) ((b)->flags |= HED_BLOCK_DIRTY)
116 #define hed_block_clear_dirty(b) ((b)->flags &= ~HED_BLOCK_DIRTY)
118 #define hed_block_is_inserted(b) ((b)->flags & HED_BLOCK_INSERTED)
119 #define hed_block_set_inserted(b) ((b)->flags |= HED_BLOCK_INSERTED)
120 #define hed_block_clear_inserted(b) ((b)->flags &= ~HED_BLOCK_INSERTED)
122 #define hed_block_is_excache(b) ((b)->flags & HED_BLOCK_EXCACHE)
123 #define hed_block_set_excache(b) ((b)->flags |= HED_BLOCK_EXCACHE)
124 #define hed_block_clear_excache(b) ((b)->flags &= ~HED_BLOCK_EXCACHE)
126 #define hed_block_is_virtual(b) ((b)->flags & HED_BLOCK_VIRTUAL)
127 #define hed_block_set_virtual(b) ((b)->flags |= HED_BLOCK_VIRTUAL)
128 #define hed_block_clear_virtual(b) ((b)->flags &= ~HED_BLOCK_VIRTUAL)
130 #define hed_block_is_eof(b) ((b)->flags & HED_BLOCK_EOF)
131 #define hed_block_set_eof(b) ((b)->flags |= HED_BLOCK_EOF)
132 #define hed_block_clear_eof(b) ((b)->flags &= ~HED_BLOCK_EOF)
134 #define hed_block_is_inner_virtual(b) \
135 (((b)->flags & (HED_BLOCK_VIRTUAL | HED_BLOCK_EOF)) \
136 == HED_BLOCK_VIRTUAL)
138 /* flags related to block allocation */
139 #define HED_BLOCK_ALLOCMASK (HED_BLOCK_EXCACHE)
141 /* flags related to block state */
142 #define HED_BLOCK_STATEMASK (HED_BLOCK_DIRTY | HED_BLOCK_INSERTED | \
143 HED_BLOCK_VIRTUAL)
145 static inline hed_uoff_t
146 hed_block_size(struct hed_block *block)
148 return block->t.size;
151 static inline unsigned char *
152 hed_block_data(struct hed_block *block)
154 return block->dataobj
155 ? block->dataobj->data + block->dataoff
156 : NULL;
159 /* Returns true iff the block follows a deletion */
160 bool hed_block_is_after_erase(const struct hed_tree *tree,
161 struct hed_block *block);
163 /* Returns true iff the block follows an insertion */
164 bool hed_block_is_after_insert(const struct hed_tree *tree,
165 struct hed_block *block);
167 /* A hed_cursor_t consists of file position, its corresponding
168 * block pointer and the offset within that block.
170 typedef struct {
171 hed_off_t pos;
172 struct hed_block *block;
173 hed_uoff_t off;
174 struct hed_list_head list;
175 } hed_cursor_t;
177 #define HED_NULL_CURSOR { 0, NULL, 0 }
179 #define hed_is_a_cursor(curs) (!!(curs)->block)
181 /* Return a pointer to the actual data at @curs, or NULL if none */
182 static inline void *
183 hed_cursor_data(hed_cursor_t *curs)
185 return !hed_block_is_virtual(curs->block)
186 ? hed_block_data(curs->block) + curs->off
187 : NULL;
190 /* Returns the number of contiguous bytes following @curs. */
191 static inline hed_uoff_t
192 hed_cursor_span(const hed_cursor_t *curs)
194 return hed_block_size(curs->block) - curs->off;
197 /* Returns the number of contiguous bytes following @curs,
198 * but at most @maxlen.
199 * The intended use of this function is to determine the next chunk
200 * length to read @maxlen bytes from the file.
202 static inline size_t
203 hed_cursor_chunk_len(const hed_cursor_t *curs, size_t maxlen)
205 hed_uoff_t ret = hed_cursor_span(curs);
206 return ret < maxlen ? (size_t)ret : maxlen;
209 /* File object */
211 #define HED_MARK_NR ('z' - 'a' + 1 + 'Z' - 'A' + 1)
213 struct hed_file {
214 /* The file blocks are sorted by the offset in this list. */
215 struct hed_tree blocks;
217 /* This list contains clean file-backed blocks.
218 * It is sorted from least recently used to most recently used. */
219 struct hed_list_head lru;
221 /* This cache holds the data for clean file-backed blocks. */
222 struct hed_cache *cache;
224 #ifdef HED_CONFIG_READAHEAD
225 enum {
226 HED_RA_NONE, /* No readahead */
227 HED_RA_FORWARD, /* Read-ahead forwards */
228 HED_RA_BACKWARD /* Read-ahead backwards */
229 } readahead;
230 #endif
232 int fd; /* file descriptor for read-only access */
233 hed_uoff_t phys_size; /* physical size on disk */
234 hed_uoff_t size; /* size after modifications */
236 const char *name; /* file name */
238 bool modified;
239 struct stat s;
241 #ifdef HED_CONFIG_SWAP
242 char *swpname; /* original swap file name */
243 char *newswpname; /* new swap file name */
244 struct swp_file *swp;
245 struct hed_block *null_block;
246 #endif
248 #ifdef HED_CONFIG_MMAP
249 struct hed_list_head fixup_list;
250 #endif
252 hed_cursor_t marks[HED_MARK_NR];
255 #ifdef HED_CONFIG_READAHEAD
256 static inline void
257 hed_file_set_readahead(struct hed_file *file, int val)
259 file->readahead = val;
261 #else
262 # define hed_file_set_readahead(file,t) do {} while(0)
263 #endif
265 /*******************************************************************
266 * file object API
269 /* Global initialization */
270 int libhed_init(void);
272 /* Opens a file. */
273 struct hed_file *hed_open(const char *name);
275 /* Closes the file. */
276 void hed_close(struct hed_file *file);
278 /* Get the current file size */
279 static inline
280 hed_uoff_t hed_file_size(struct hed_file *file)
282 return file->size;
285 /* Get the blocks tree */
286 static inline struct hed_tree *
287 hed_file_blocks(struct hed_file *file)
289 return &file->blocks;
292 /* Returns true iff the file has been modified */
293 static inline bool
294 hed_file_is_modified(struct hed_file *file)
296 return file->modified;
299 /* Update the file size from the file system */
300 int hed_file_update_size(struct hed_file *file);
302 /* Commits dirty blocks to the file. */
303 int hed_file_commit(struct hed_file *file);
305 #ifdef HED_CONFIG_SWAP
307 /* Saves dump of internal structures to disk. */
308 int hed_file_write_swap(struct hed_file *file);
310 /* Loads dump of internal structures associated with given file from disk. */
311 int hed_file_read_swap(struct hed_file *file);
313 /* Checks whether a swap file is available. */
314 static inline int
315 hed_file_has_swap(struct hed_file *file)
317 return file->swpname != file->newswpname;
320 /* Remoes dump of internal structures associated with given file from disk. */
321 int hed_file_remove_swap(struct hed_file *file);
323 static inline char *
324 hed_file_swap_name(struct hed_file *file)
326 return file->swpname;
329 #else /* HED_CONFIG_SWAP */
331 static inline int
332 hed_file_write_swap(struct hed_file *file)
334 return 0;
337 static inline int
338 hed_file_read_swap(struct hed_file *file)
340 return -1;
343 static inline int
344 hed_file_has_swap(struct hed_file *file)
346 return 0;
349 static inline int
350 hed_file_remove_swap(struct hed_file *file)
352 return 0;
355 static inline char *
356 hed_file_swap_name(struct hed_file *file)
358 return NULL;
361 #endif /* HED_CONFIG_SWAP */
363 /* Converts a logical @offset to a cursor (@curs). Returns
364 * non-zero on error, and the error code is available in @errno.
366 void hed_get_cursor(struct hed_file *file, hed_uoff_t offset,
367 hed_cursor_t *curs);
369 /* Mark @curs as no longer needed. In particular, this stops tracking
370 * file changes with this pointer.
372 void hed_put_cursor(hed_cursor_t *curs);
374 /* Duplicate into an empty hed_cursor_t */
375 void hed_dup_cursor(const hed_cursor_t *src, hed_cursor_t *dst);
377 /* Duplicate into an initialized hed_cursor_t */
378 void hed_dup2_cursor(const hed_cursor_t *src, hed_cursor_t *dst);
380 /* Relative move from a given block offset.
381 * If the resulting position is out of bounds (either < 0 or > OFF_MAX),
382 * the offset is adjusted to only move to 0 or OFF_MAX.
383 * Returns the actual offset which was used.
385 hed_off_t hed_move_relative(hed_cursor_t *curs, hed_off_t num);
387 /* Ensure reads are valid from a block offset.
388 * If @curs points to a virtual block (and not beyond EOF), the
389 * corresponding physical block is loaded from the file.
390 * Returns the number of bytes available in the next chunk
391 * (cf. hed_cursor_chunk_len), or ZERO on error.
393 size_t hed_prepare_read(struct hed_file *file, const hed_cursor_t *curs,
394 size_t len);
396 /* Given you know that offset is just one byte beyond the last span,
397 * get the block which contains byte at @curs.
398 * If the block is not available, it is loaded from disk, so do not
399 * use this function if you only want to iterate through virtual
400 * blocks.
401 * Returns non-zero on error, and the error code is available in @errno.
403 int hed_file_next_block(struct hed_file *file, hed_cursor_t *curs);
405 /* Copy in @count bytes from file @file at @pos to @buf.
406 * Returns number of bytes which were not copied, i.e. zero on success.
408 size_t hed_file_cpin(struct hed_file *file, void *buf, size_t count,
409 const hed_cursor_t *pos);
411 /* Find a given sequence of bytes in the file, starting at the @pos file
412 * offset and possibly wrapping around. @dir is +1 or -1. */
413 int hed_file_find_expr(struct hed_file *file, hed_cursor_t *pos, int dir,
414 struct hed_expr *expr,
415 hed_expr_reg_cb expr_cb, void *expr_cb_data);
416 #define HED_FINDOFF_NO_MATCH -1
417 #define HED_FINDOFF_ERROR -2
419 /* Sets a single byte in the file. */
420 int hed_file_set_byte(struct hed_file *file, hed_cursor_t *curs,
421 unsigned char byte);
422 /* Sets multiple bytes in the file. */
423 size_t hed_file_set_block(struct hed_file *file, hed_cursor_t *curs,
424 unsigned char *buf, size_t len);
425 hed_uoff_t hed_file_set_bytes(struct hed_file *file, hed_cursor_t *curs,
426 unsigned char byte, hed_uoff_t rep);
428 /* To insert bytes:
429 * 1. call file_insert_begin() with the cursor position and store the
430 * insert physical position.
431 * 2. call file_insert_byte() and/or file_insert_block() on the insert pos,
432 * possibly repeatedly
433 * 3. call file_insert_end() on the insert pos and forget all about it;
434 * be careful with aliases, because the insert might get merged/freed
436 int hed_file_insert_begin(struct hed_file *file,
437 hed_cursor_t *curs, hed_cursor_t *curs_ins);
438 void hed_file_insert_end(struct hed_file *file, hed_cursor_t *curs_ins);
440 /* Inserts a single byte to the file. */
441 int hed_file_insert_byte(struct hed_file *file, hed_cursor_t *curs,
442 unsigned char byte);
443 /* Insert a block of bytes to the file. */
444 size_t hed_file_insert_block(struct hed_file *file, hed_cursor_t *curs,
445 unsigned char *buf, size_t len);
447 /* The following function is a shorthand for the usual
448 * file_insert_begin, file_insert_block, file_insert_end
449 * sequence.
451 size_t hed_file_insert_once(struct hed_file *file, hed_cursor_t *curs,
452 unsigned char *buf, size_t len);
454 /* Erases a single byte from the file. */
455 # define hed_file_erase_byte(file,curs) (hed_file_erase_block((file),(curs),1))
457 /* Erases a block of bytes from the file. */
458 size_t hed_file_erase_block(struct hed_file *file, hed_cursor_t *curs,
459 hed_uoff_t len);
461 /*******************************************************************
462 * MARK FUNCTIONS
465 /* Returns true iff @mark is a valid mark */
466 static inline bool
467 hed_file_has_mark(struct hed_file *file, int mark)
469 return hed_is_a_cursor(&file->marks[mark]);
472 /* Return pointer to a mark */
473 static inline hed_cursor_t*
474 hed_file_mark(struct hed_file *file, int mark)
476 return &file->marks[mark];
479 #endif