Branch data Line data Source code
1 : : #include "precizer.h"
2 : :
3 : : /**
4 : : * @brief Build a root-relative path for an FTS entry
5 : : *
6 : : * @details
7 : : * Builds a path from the FTS parent chain instead of trimming a textual root
8 : : * prefix from `FTSENT::fts_path`. This keeps the stored file path independent
9 : : * from how the traversal root was written by the user, while preserving that
10 : : * original root spelling in the database `paths` table
11 : : *
12 : : * The root entry itself is represented as ".". Child entries are assembled
13 : : * from their component names, for example `dir/subdir/file.txt`
14 : : *
15 : : * @param[out] relative_path String descriptor that receives the relative path
16 : : * @param[in] entry FTS entry whose path should be built
17 : : * @return SUCCESS when the path is built, otherwise FAILURE
18 : : */
19 : 23658 : Return path_build_relative(
20 : : memory *relative_path,
21 : : const FTSENT *entry)
22 : : {
23 : : /* Status returned by this function through provide()
24 : : Default value assumes successful completion */
25 : 23658 : Return status = SUCCESS;
26 : :
27 [ - + ]: 23658 : if(entry == NULL)
28 : : {
29 : 0 : report("Relative path building; FTS entry must be non-NULL");
30 : 0 : provide(FAILURE);
31 : : }
32 : :
33 [ - + ]: 23658 : if(entry->fts_level < FTS_ROOTLEVEL)
34 : : {
35 : 0 : report("Relative path building; FTS entry is above the traversal root");
36 : 0 : provide(FAILURE);
37 : : }
38 : :
39 [ + + ]: 23658 : if(entry->fts_level == FTS_ROOTLEVEL)
40 : : {
41 : 447 : run(m_copy_literal(relative_path,"."));
42 : 447 : provide(status);
43 : : }
44 : :
45 : 23211 : size_t relative_path_length = 0U;
46 : 23211 : size_t component_count = 0U;
47 : :
48 : 23211 : for(const FTSENT *node = entry;
49 [ + - + + ]: 117827 : node != NULL && node->fts_level > FTS_ROOTLEVEL;
50 : 94616 : node = node->fts_parent)
51 : : {
52 [ - + ]: 94616 : if(node->fts_namelen == 0U)
53 : : {
54 : 0 : report("Relative path building; FTS entry has an invalid component name");
55 : 0 : provide(FAILURE);
56 : : }
57 : :
58 [ - + ]: 94616 : if(relative_path_length > SIZE_MAX - (size_t)node->fts_namelen)
59 : : {
60 : 0 : report("Relative path building; Path length overflow");
61 : 0 : provide(FAILURE);
62 : : }
63 : :
64 : 94616 : relative_path_length += (size_t)node->fts_namelen;
65 : :
66 [ + + ]: 94616 : if(component_count > 0U)
67 : : {
68 [ - + ]: 71405 : if(relative_path_length == SIZE_MAX)
69 : : {
70 : 0 : report("Relative path building; Path separator overflow");
71 : 0 : provide(FAILURE);
72 : : }
73 : :
74 : 71405 : relative_path_length++;
75 : : }
76 : :
77 : 94616 : component_count++;
78 : : }
79 : :
80 : 23211 : const FTSENT *root_entry = entry;
81 : :
82 [ + - + + ]: 117827 : while(root_entry != NULL && root_entry->fts_level > FTS_ROOTLEVEL)
83 : : {
84 : 94616 : root_entry = root_entry->fts_parent;
85 : : }
86 : :
87 [ + - - + ]: 23211 : if(root_entry == NULL || root_entry->fts_level != FTS_ROOTLEVEL)
88 : : {
89 : 0 : report("Relative path building; FTS parent chain does not reach the traversal root");
90 : 0 : provide(FAILURE);
91 : : }
92 : :
93 [ - + ]: 23211 : if(relative_path_length == SIZE_MAX)
94 : : {
95 : 0 : report("Relative path building; Path terminator overflow");
96 : 0 : provide(FAILURE);
97 : : }
98 : :
99 : 23211 : run(m_resize(relative_path,relative_path_length + 1U));
100 : :
101 [ - + ]: 23211 : if(SUCCESS != status)
102 : : {
103 : 0 : provide(status);
104 : : }
105 : :
106 : 23211 : char *relative_path_data = m_data(char,relative_path);
107 : :
108 [ - + ]: 23211 : if(relative_path_data == NULL)
109 : : {
110 : 0 : report("Relative path building; Destination buffer is unavailable");
111 : 0 : provide(FAILURE);
112 : : }
113 : :
114 : 23211 : char *write_cursor = relative_path_data + relative_path_length;
115 : 23211 : *write_cursor = '\0';
116 : :
117 : 23211 : for(const FTSENT *node = entry;
118 [ + - + + ]: 117827 : node != NULL && node->fts_level > FTS_ROOTLEVEL;
119 : 94616 : node = node->fts_parent)
120 : : {
121 : 94616 : const size_t component_length = (size_t)node->fts_namelen;
122 : :
123 : 94616 : write_cursor -= component_length;
124 : 94616 : memcpy(write_cursor,node->fts_name,component_length);
125 : :
126 [ + - + + ]: 94616 : if(node->fts_parent != NULL && node->fts_parent->fts_level > FTS_ROOTLEVEL)
127 : : {
128 : 71405 : write_cursor--;
129 : 71405 : *write_cursor = '/';
130 : : }
131 : : }
132 : :
133 [ - + ]: 23211 : if(write_cursor != relative_path_data)
134 : : {
135 : 0 : report("Relative path building; Internal path assembly size mismatch");
136 : 0 : provide(FAILURE);
137 : : }
138 : :
139 : 23211 : run(m_finalize_string(relative_path,relative_path_length));
140 : :
141 : 23211 : provide(status);
142 : : }
|