mtree parsing and manipulation library
Student: MichalRatajsky (<michal AT SPAMFREE FreeBSD DOT org>)
Mentor: BrooksDavis (<brooks AT SPAMFREE FreeBSD DOT org>)
Project description
FreeBSD currently includes several tools that work with file system hierarchy descriptions and each contains its own routines to parse and/or manipulate these descriptions.
This project attempts to improve this by designing a library to include all the common code, removing duplications from application code and allowing simple future extensions.
Approach to solving the problem
Develop a new libmtree library
The library will provide an API for specfile-related operations that are currently present in the mtree tool and other tools as well as additional manipulations (filter, merge, update and possibly others) that could be useful to applications in the future or allow expansion of the mtree tool.
The API will be designed to be intuitive, well documented and easily useable by applications.
Some code will be reused from existing applications, mainly from the mtree tool. All reused code will be verified and eventually adapted or rewritten to fit the required abstraction.
The library will include complete API documentation and unit tests.
Modify existing applications and libraries to use libmtree
Applications and libraries that contain mtree code will be modified to use libmtree instead:
- mtree
- makefs
- xinstall
The mtree tool itself will be distributed in the same source tree as libmtree. Both libmtree and mtree will be implemented portably.
Milestones
- May 25: Start of coding
- June 26: Fully functional libmtree and mtree with support for reading, writing, comparison of spec files
- June 26-July 3: Mid-term Evaluations
- July 5: Fully functional mtree with support for all current features and command-line options
- July 26: All applications and libraries ported to libmtree
- August 9: Complete and fully documented libmtree and mtree
- August 17: FreeBSD source tree updated to include libmtree and the new mtree implementation
- August 17: End of coding (soft)
- August 21 19:00 UTC: End of coding (hard)
Timeline
Week 1 (May 25 - 31) |
Status |
Create project skeleton with autotools support |
DONE |
libmtree: Initial API design |
DONE |
libmtree: Start implementing support functions |
DONE |
Week 2 - 5 (June 1 - 26) |
|
libmtree: Implement reading of mtree specs |
DONE |
libmtree: Implement creation of mtree specs from directory structure |
DONE |
libmtree: Implement writing of mtree specs |
DONE |
libmtree: Implement comparison of/against mtree specs |
DONE |
Provide initial mtree implementation of the current libmtree features |
DONE |
Week 6 - 7 (June 29 - July 12) |
|
libmtree: Implement spec filtering |
DONE |
Implement remaining pieces of mtree |
DONE |
Week 8 - 9 (July 13 - July 26) |
|
libmtree: Implement additional API parts required by applications |
DONE |
Port libarchive to libmtree |
DONE |
Port makefs to libmtree |
DONE |
Port xinstall to libmtree |
DONE |
Week 10 - 11 (July 27 - August 9) |
|
libmtree: Implement spec merging |
DONE |
libmtree: Implement remaining tests |
DONE |
Write libmtree and mtree manual pages |
DONE |
Week 12 (August 10 - August 17) |
|
Update the FreeBSD source tree to include libmtree and remove redundant code |
NOT DONE |
TODO
libmtree, mtree
- see TODOs, FIXMEs and XXXs directly in code
- think about what to do with magic characters, are they needed?; they used to match the first file when matching spec against filesystem, but supporting this properly would require special treatment in about every operation (for example how to deal with overlapping entries when merging?)
- mtree(8): make sure all command-line options work correctly; some problems are mentioned in code, but some options are just untested
- mtree(8): bring error reporting on par with the former implementation
- mtree(8/5) man pages should be updated to reflect portability issues (e.g some mtree options being BSD-only) and describe the mtree formats (libarchive used to call the -C format mtree 2.0 but later reverted this, libmtree still calls it 2.0), common parts should be unified
libarchive
- investigate failing tests; most of them fail because libmtree enforces "./" prefix of each entry, see if this is OK and it's enough to update the tests
makefs
- -x is not implemented
- creating an image crashes sometimes
Changes
- mtree(8) no longer supports magic chars in file names, as mentioned above
- libarchive no longer recognizes the "content" keyword alias, but only the documented "contents" keyword
- makefs no longer requires separate entries for each path segment in spec files
The Code
Example
This is a simplified example demonstrating how to use the libmtree API:
1 #include <mtree.h>
2 #include <mtree_file.h>
3
4 int main(void)
5 {
6 struct mtree_spec *spec_yesterday, *spec_today;
7 struct mtree_spec_diff *diff;
8 struct mtree_entry *entries;
9 FILE *fp;
10
11 /*
12 * Read specification from slash-bin-yesterday.mtree file into spec_yesterday.
13 */
14 fp = fopen("slash-bin-yesterday.mtree", "r");
15 spec_yesterday = mtree_spec_create();
16 mtree_spec_read_spec_file(spec_yesterday, fp);
17
18 /*
19 * Create specification by walking directory tree.
20 */
21 spec_today = mtree_spec_create();
22 mtree_spec_read_path(spec_today, "/bin");
23
24 /*
25 * Compare file type and time of each file.
26 */
27 diff = mtree_spec_diff_create(spec_yesterday, spec_today,
28 MTREE_KEYWORD_TIME |
29 MTREE_KEYWORD_TYPE, 0);
30
31 entries = mtree_spec_diff_get_different(diff);
32 if (entries != NULL) {
33 printf("ALERT! == Some files have been changed! == ALERT!\n\n");
34 while (entries != NULL) {
35 struct mtree_entry *entry_yesterday, *entry_today;
36
37 /*
38 * "entries" is a linked list of entries containing the entries that
39 * are different in each spec.
40 *
41 * As described in mtree_spec_diff(3), the entries are stored in pairs,
42 * first entry being from the first list, second being from the second
43 * list.
44 *
45 * Also, their keyword sets have been modified to include only the
46 * keywords that are different.
47 */
48 entry_yesterday = entries;
49 entry_today = mtree_entry_get_next(entry_yesterday);
50
51 printf("%s\n", mtree_entry_get_path(entry_yesterday));
52 if (mtree_entry_get_keywords(entry_yesterday) & MTREE_KEYWORD_TIME)
53 printf("\tTime: %ld -> %ld\n",
54 mtree_entry_get_time(entry_yesterday)->tv_sec,
55 mtree_entry_get_time(entry_today)->tv_sec);
56 if (mtree_entry_get_keywords(entry_yesterday) & MTREE_KEYWORD_TYPE)
57 printf("\tType: %s -> %s\n",
58 mtree_entry_type_string(mtree_entry_get_type(entry_yesterday)),
59 mtree_entry_type_string(mtree_entry_get_type(entry_today)));
60
61 entries = mtree_entry_get_next(entry_today);
62 }
63 }
64 }
API Design
https://github.com/mratajsky/libmtree/blob/master/libmtree/mtree.h
https://github.com/mratajsky/libmtree/blob/master/libmtree/mtree_file.h