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_.
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>
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:
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
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
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
83 struct hed_tree_head t
;
84 struct hed_list_head lru
;
86 /* Flags - see HED_BLOCK_xxx below. */
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
;
100 /* Physical position of this block. */
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
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. */
113 #define HED_BLOCK_BAD 0x20 /* Block with read errors */
115 #define hed_block_is_dirty(b) ((b)->flags & HED_BLOCK_DIRTY)
116 #define hed_block_set_dirty(b) ((b)->flags |= HED_BLOCK_DIRTY)
117 #define hed_block_clear_dirty(b) ((b)->flags &= ~HED_BLOCK_DIRTY)
119 #define hed_block_is_inserted(b) ((b)->flags & HED_BLOCK_INSERTED)
120 #define hed_block_set_inserted(b) ((b)->flags |= HED_BLOCK_INSERTED)
121 #define hed_block_clear_inserted(b) ((b)->flags &= ~HED_BLOCK_INSERTED)
123 #define hed_block_is_excache(b) ((b)->flags & HED_BLOCK_EXCACHE)
124 #define hed_block_set_excache(b) ((b)->flags |= HED_BLOCK_EXCACHE)
125 #define hed_block_clear_excache(b) ((b)->flags &= ~HED_BLOCK_EXCACHE)
127 #define hed_block_is_virtual(b) ((b)->flags & HED_BLOCK_VIRTUAL)
128 #define hed_block_set_virtual(b) ((b)->flags |= HED_BLOCK_VIRTUAL)
129 #define hed_block_clear_virtual(b) ((b)->flags &= ~HED_BLOCK_VIRTUAL)
131 #define hed_block_is_eof(b) ((b)->flags & HED_BLOCK_EOF)
132 #define hed_block_set_eof(b) ((b)->flags |= HED_BLOCK_EOF)
133 #define hed_block_clear_eof(b) ((b)->flags &= ~HED_BLOCK_EOF)
135 #define hed_block_is_bad(b) ((b)->flags & HED_BLOCK_BAD)
136 #define hed_block_set_bad(b) ((b)->flags |= HED_BLOCK_BAD)
137 #define hed_block_clear_bad(b) ((b)->flags &= ~HED_BLOCK_BAD)
139 #define hed_block_is_inner_virtual(b) \
140 (((b)->flags & (HED_BLOCK_VIRTUAL | HED_BLOCK_EOF | HED_BLOCK_BAD)) \
141 == HED_BLOCK_VIRTUAL)
143 /* flags related to block allocation */
144 #define HED_BLOCK_ALLOCMASK (HED_BLOCK_EXCACHE)
146 /* flags related to block state */
147 #define HED_BLOCK_STATEMASK (HED_BLOCK_DIRTY | HED_BLOCK_INSERTED | \
150 static inline hed_uoff_t
151 hed_block_size(struct hed_block
*block
)
153 return block
->t
.size
;
156 static inline unsigned char *
157 hed_block_data(struct hed_block
*block
)
159 return block
->dataobj
160 ? block
->dataobj
->data
+ block
->dataoff
164 /* Returns true iff the block follows a deletion */
165 bool hed_block_is_after_erase(const struct hed_tree
*tree
,
166 struct hed_block
*block
);
168 /* Returns true iff the block follows an insertion */
169 bool hed_block_is_after_insert(const struct hed_tree
*tree
,
170 struct hed_block
*block
);
172 /* A hed_cursor_t consists of file position, its corresponding
173 * block pointer and the offset within that block.
177 struct hed_block
*block
;
179 struct hed_list_head list
;
182 #define HED_NULL_CURSOR { 0, NULL, 0 }
184 #define hed_is_a_cursor(curs) (!!(curs)->block)
186 /* Return a pointer to the actual data at @curs, or NULL if none */
188 hed_cursor_data(hed_cursor_t
*curs
)
190 return !hed_block_is_virtual(curs
->block
)
191 ? hed_block_data(curs
->block
) + curs
->off
195 /* Returns the physical file position of the cursor */
196 static inline hed_uoff_t
197 hed_cursor_phys_pos(const hed_cursor_t
*curs
)
199 return hed_block_is_inserted(curs
->block
)
200 ? curs
->block
->phys_pos
201 : curs
->block
->phys_pos
+ curs
->off
;
204 /* Returns the number of contiguous bytes following @curs. */
205 static inline hed_uoff_t
206 hed_cursor_span(const hed_cursor_t
*curs
)
208 return hed_block_size(curs
->block
) - curs
->off
;
211 /* Returns the number of contiguous bytes following @curs,
212 * but at most @maxlen.
213 * The intended use of this function is to determine the next chunk
214 * length to read @maxlen bytes from the file.
217 hed_cursor_chunk_len(const hed_cursor_t
*curs
, size_t maxlen
)
219 hed_uoff_t ret
= hed_cursor_span(curs
);
220 return ret
< maxlen
? (size_t)ret
: maxlen
;
225 #define HED_MARK_NR ('z' - 'a' + 1 + 'Z' - 'A' + 1)
228 /* The file blocks are sorted by the offset in this list. */
229 struct hed_tree blocks
;
231 /* This list contains clean file-backed blocks.
232 * It is sorted from least recently used to most recently used. */
233 struct hed_list_head lru
;
235 /* This cache holds the data for clean file-backed blocks. */
236 struct hed_cache
*cache
;
238 #ifdef HED_CONFIG_READAHEAD
240 HED_RA_NONE
, /* No readahead */
241 HED_RA_FORWARD
, /* Read-ahead forwards */
242 HED_RA_BACKWARD
/* Read-ahead backwards */
246 int fd
; /* file descriptor for read-only access */
247 hed_uoff_t phys_size
; /* physical size on disk */
248 hed_uoff_t size
; /* size after modifications */
250 const char *name
; /* file name */
255 #ifdef HED_CONFIG_SWAP
256 char *swpname
; /* original swap file name */
257 char *newswpname
; /* new swap file name */
258 struct swp_file
*swp
;
259 struct hed_block
*null_block
;
262 #ifdef HED_CONFIG_MMAP
263 struct hed_list_head fixup_list
;
266 hed_cursor_t marks
[HED_MARK_NR
];
269 #ifdef HED_CONFIG_READAHEAD
271 hed_file_set_readahead(struct hed_file
*file
, int val
)
273 file
->readahead
= val
;
276 # define hed_file_set_readahead(file,t) do {} while(0)
279 /*******************************************************************
283 /* Global initialization */
284 int libhed_init(void);
287 struct hed_file
*hed_open(const char *name
);
289 /* Closes the file. */
290 void hed_close(struct hed_file
*file
);
292 /* Get the current file size */
294 hed_uoff_t
hed_file_size(struct hed_file
*file
)
299 /* Get the blocks tree */
300 static inline struct hed_tree
*
301 hed_file_blocks(struct hed_file
*file
)
303 return &file
->blocks
;
306 /* Returns true iff the file has been modified */
308 hed_file_is_modified(struct hed_file
*file
)
310 return file
->modified
;
313 /* Update the file size from the file system */
314 int hed_file_update_size(struct hed_file
*file
);
316 /* Commits dirty blocks to the file. */
317 int hed_file_commit(struct hed_file
*file
);
319 #ifdef HED_CONFIG_SWAP
321 /* Saves dump of internal structures to disk. */
322 int hed_file_write_swap(struct hed_file
*file
);
324 /* Loads dump of internal structures associated with given file from disk. */
325 int hed_file_read_swap(struct hed_file
*file
);
327 /* Checks whether a swap file is available. */
329 hed_file_has_swap(struct hed_file
*file
)
331 return file
->swpname
!= file
->newswpname
;
334 /* Remoes dump of internal structures associated with given file from disk. */
335 int hed_file_remove_swap(struct hed_file
*file
);
338 hed_file_swap_name(struct hed_file
*file
)
340 return file
->swpname
;
343 #else /* HED_CONFIG_SWAP */
346 hed_file_write_swap(struct hed_file
*file
)
352 hed_file_read_swap(struct hed_file
*file
)
358 hed_file_has_swap(struct hed_file
*file
)
364 hed_file_remove_swap(struct hed_file
*file
)
370 hed_file_swap_name(struct hed_file
*file
)
375 #endif /* HED_CONFIG_SWAP */
377 /* Converts a logical @offset to a cursor (@curs). Returns
378 * non-zero on error, and the error code is available in @errno.
380 void hed_get_cursor(struct hed_file
*file
, hed_uoff_t offset
,
383 /* Mark @curs as no longer needed. In particular, this stops tracking
384 * file changes with this pointer.
386 void hed_put_cursor(hed_cursor_t
*curs
);
388 /* Duplicate into an empty hed_cursor_t */
389 void hed_dup_cursor(const hed_cursor_t
*src
, hed_cursor_t
*dst
);
391 /* Duplicate into an initialized hed_cursor_t */
392 void hed_dup2_cursor(const hed_cursor_t
*src
, hed_cursor_t
*dst
);
394 /* Relative move from a given block offset.
395 * If the resulting position is out of bounds (either < 0 or > OFF_MAX),
396 * the offset is adjusted to only move to 0 or OFF_MAX.
397 * Returns the actual offset which was used.
399 hed_off_t
hed_move_relative(hed_cursor_t
*curs
, hed_off_t num
);
401 /* Ensure reads are valid from a block offset.
402 * If @curs points to a virtual block (and not beyond EOF), the
403 * corresponding physical block is loaded from the file.
404 * Returns the number of bytes available in the next chunk
405 * (cf. hed_cursor_chunk_len), or ZERO on error.
407 size_t hed_prepare_read(struct hed_file
*file
, const hed_cursor_t
*curs
,
410 /* Given you know that offset is just one byte beyond the last span,
411 * get the block which contains byte at @curs.
412 * If the block is not available, it is loaded from disk, so do not
413 * use this function if you only want to iterate through virtual
415 * Returns non-zero on error, and the error code is available in @errno.
417 int hed_file_next_block(struct hed_file
*file
, hed_cursor_t
*curs
);
419 /* Copy in @count bytes from file @file at @pos to @buf.
420 * Returns number of bytes which were not copied, i.e. zero on success.
422 size_t hed_file_cpin(struct hed_file
*file
, void *buf
, size_t count
,
423 const hed_cursor_t
*pos
);
425 /* Find a given sequence of bytes in the file, starting at the @pos file
426 * offset and possibly wrapping around. @dir is +1 or -1. */
427 int hed_file_find_expr(struct hed_file
*file
, hed_cursor_t
*pos
, int dir
,
428 struct hed_expr
*expr
,
429 hed_expr_reg_cb expr_cb
, void *expr_cb_data
);
430 #define HED_FINDOFF_NO_MATCH -1
431 #define HED_FINDOFF_ERROR -2
433 /* Sets a single byte in the file. */
434 int hed_file_set_byte(struct hed_file
*file
, hed_cursor_t
*curs
,
436 /* Sets multiple bytes in the file. */
437 size_t hed_file_set_block(struct hed_file
*file
, hed_cursor_t
*curs
,
438 unsigned char *buf
, size_t len
);
439 hed_uoff_t
hed_file_set_bytes(struct hed_file
*file
, hed_cursor_t
*curs
,
440 unsigned char byte
, hed_uoff_t rep
);
443 * 1. call file_insert_begin() with the cursor position and store the
444 * insert physical position.
445 * 2. call file_insert_byte() and/or file_insert_block() on the insert pos,
446 * possibly repeatedly
447 * 3. call file_insert_end() on the insert pos and forget all about it;
448 * be careful with aliases, because the insert might get merged/freed
450 int hed_file_insert_begin(struct hed_file
*file
,
451 const hed_cursor_t
*curs
, hed_cursor_t
*curs_ins
);
452 void hed_file_insert_end(struct hed_file
*file
, hed_cursor_t
*curs_ins
);
454 /* Inserts a single byte to the file. */
455 int hed_file_insert_byte(struct hed_file
*file
, hed_cursor_t
*curs
,
457 /* Insert a block of bytes to the file. */
458 size_t hed_file_insert_block(struct hed_file
*file
, hed_cursor_t
*curs
,
459 unsigned char *buf
, size_t len
);
461 /* The following function is a shorthand for the usual
462 * file_insert_begin, file_insert_block, file_insert_end
465 size_t hed_file_insert_once(struct hed_file
*file
, hed_cursor_t
*curs
,
466 unsigned char *buf
, size_t len
);
468 /* Erases a single byte from the file. */
469 # define hed_file_erase_byte(file,curs) (hed_file_erase_block((file),(curs),1))
471 /* Erases a block of bytes from the file. */
472 size_t hed_file_erase_block(struct hed_file
*file
, hed_cursor_t
*curs
,
475 /*******************************************************************
479 /* Returns true iff @mark is a valid mark */
481 hed_file_has_mark(struct hed_file
*file
, int mark
)
483 return hed_is_a_cursor(&file
->marks
[mark
]);
486 /* Return pointer to a mark */
487 static inline hed_cursor_t
*
488 hed_file_mark(struct hed_file
*file
, int mark
)
490 return &file
->marks
[mark
];