1 /* The file handling */
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
31 #include <libhed/types.h>
33 /* The block cache is organized as follows:
35 * At the start, there are two virtual blocks:
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
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
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. */
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
;
95 /* Physical position of this block. */
99 /* A hed_cursor_t consists of file position, its corresponding
100 * block pointer and the offset within that block.
104 struct hed_file_block
*block
;
106 struct hed_list_head list
;
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
159 #define MARKS_COUNT ('z' - 'a' + 1 + 'Z' - 'A' + 1)
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
174 FILE_RA_NONE
, /* No readahead */
175 FILE_RA_FORWARD
, /* Read-ahead forwards */
176 FILE_RA_BACKWARD
/* Read-ahead backwards */
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 */
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
;
196 hed_cursor_t marks
[MARKS_COUNT
];
199 #ifdef CONFIG_READAHEAD
201 file_set_readahead(struct hed_file
*file
, int val
)
203 file
->readahead
= val
;
206 # define file_set_readahead(file,t) do {} while(0)
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 /*******************************************************************
227 /* Global initialization */
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 */
238 uoff_t
file_size(struct hed_file
*file
)
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 */
252 file_is_modified(struct hed_file
*file
)
254 return file
->modified
;
257 /* Set the modified flag */
259 file_set_modified(struct hed_file
*file
)
261 file
->modified
= true;
264 /* Clear the modified flag */
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
);
279 /* Return the swp file object */
280 static inline struct swp_file
*
281 file_swp(struct hed_file
*file
)
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 */
303 file_swp(struct hed_file
*file
)
309 file_write_swap(struct hed_file
*file
)
315 file_read_swap(struct hed_file
*file
)
321 file_checkswp(struct hed_file
*file
)
327 file_rmswp(struct hed_file
*file
)
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
,
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
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.
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
,
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
);
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
,
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
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 /*******************************************************************
448 /* Returns true iff @mark is a valid mark */
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
];