I’m writing a FUSE plugin in C. I’m keeping track of data structures in the filesystem through structs like:
typedef struct {
block_number_t inode;
filename_t filename; //char[SOME_SIZE]
some_other_field_t other_field;
} fs_directory_table_item_t;
Obviously, I have to read (write) these structs from (to) disk at some point. I could treat the struct as a sequence of bytes and do something like this:
read(disk_fd, directory_table_item, sizeof(fs_directory_table_item_t));
…except that cannot possibly work as filename is actually a pointer to the char array.
I’d really like to avoid having to write code like:
read(disk_df, *directory_table_item.inode, sizeof(block_number_t));
read(disk_df, directory_table_item.filename, sizeof(filename_t));
read(disk_df, *directory_table_item.other_field, sizeof(some_other_field_t));
…for each struct in the code, because I’d have to replicate code and changes in no less than three different places (definition, reading, writing).
Any DRYer but still maintainable ideas?
The memory of the string will be part of your struct, even though the array type is promoted to a pointer in many cases, the type stored in the struct is the array, not the pointer.
So your read statement:
will work and bring in the data.
When reading and writing memory blocks you should take padding into consideration. Padding is extra, empty fields added by the compiler to align data on relevant boundaries; e.g. a 32-byte value should often start at 4-byte boundary in the memory to allow the processor to read it efficiently. This is normally nothing to be concerned about, but when persisting the struct to disk it can pose problems if you recompile the code with another setting. There are often some kind of
#pragmadirectives that disables padding, I think it is named#pragma packin MS Visual c++.