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 HED__FILE_FILE_H
23 #define HED__FILE_FILE_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:
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
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
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
87 /* Flags - see BLOCK_xxx below. */
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
;
101 /* Physical position of this block. */
105 /* A blockoff_t consists of file position, its corresponding
106 * block pointer and the offset within that block.
110 struct file_block
*block
;
112 struct list_head list
;
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
165 #define MARKS_COUNT ('z' - 'a' + 1 + 'Z' - 'A' + 1)
168 /* The file blocks are sorted by the offset in this list. */
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
180 FILE_RA_NONE
, /* No readahead */
181 FILE_RA_FORWARD
, /* Read-ahead forwards */
182 FILE_RA_BACKWARD
/* Read-ahead backwards */
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 */
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
;
202 blockoff_t marks
[MARKS_COUNT
];
205 #ifdef CONFIG_READAHEAD
207 file_set_readahead(struct file
*file
, int val
)
209 file
->readahead
= val
;
212 # define file_set_readahead(file,t) do {} while(0)
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 /*******************************************************************
231 /* Global initialization */
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 */
242 uoff_t
file_size(struct file
*file
)
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 */
256 file_is_modified(struct file
*file
)
258 return file
->modified
;
261 /* Set the modified flag */
263 file_set_modified(struct file
*file
)
265 file
->modified
= true;
268 /* Clear the modified flag */
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
);
283 /* Return the swp file object */
284 static inline struct swp_file
*
285 file_swp(struct file
*file
)
290 /* Saves dump of internal structures to disk. */
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 */
311 file_swp(struct file
*file
)
317 file_write_swap(struct file
*file
)
323 file_read_swap(struct file
*file
)
329 file_checkswp(struct file
*file
)
335 file_rmswp(struct file
*file
)
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
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.
391 int file_read_begin(struct file
*file
, const blockoff_t
*blockoff
);
394 file_read_end(struct file
*file
)
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
);
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
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 /*******************************************************************
451 /* Returns true iff @mark is a valid mark */
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
];
468 return ('a' <= ch
&& ch
<= 'z') ? ch
- 'a' :
469 ('A' <= ch
&& ch
<= 'Z') ? 26 + ch
- 'A' :