aboutsummaryrefslogtreecommitdiff
path: root/include/fstree.h
blob: aa8efd5698b152f252c8af4e6925ea1fe6dd3360 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
/* SPDX-License-Identifier: GPL-3.0-or-later */
/*
 * fstree.h
 *
 * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at>
 */
#ifndef FSTREE_H
#define FSTREE_H

#include "config.h"

#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#include <stdio.h>

#include "sqfs/predef.h"
#include "fstream.h"
#include "compat.h"

enum {
	DIR_SCAN_KEEP_TIME = 0x01,

	DIR_SCAN_ONE_FILESYSTEM = 0x02,

	DIR_SCAN_NO_RECURSION = 0x04,

	DIR_SCAN_NO_SOCK = 0x0008,
	DIR_SCAN_NO_SLINK = 0x0010,
	DIR_SCAN_NO_FILE = 0x0020,
	DIR_SCAN_NO_BLK = 0x0040,
	DIR_SCAN_NO_DIR = 0x0080,
	DIR_SCAN_NO_CHR = 0x0100,
	DIR_SCAN_NO_FIFO = 0x0200,
};

#define FSTREE_MODE_HARD_LINK (0)
#define FSTREE_MODE_HARD_LINK_RESOLVED (1)

typedef struct tree_node_t tree_node_t;
typedef struct file_info_t file_info_t;
typedef struct dir_info_t dir_info_t;
typedef struct fstree_t fstree_t;

#define container_of(ptr, type, member) \
	((type *)((char *)ptr - offsetof(type, member)))

/*
  Optionally used by fstree_from_dir and fstree_from_subdir to
  execute custom actions for each discovered node.

  If it returns a value > 0, the new node is discarded, if < 0, scanning is
  aborted and returns a failure status.
 */
typedef int (*scan_node_callback)(void *user, fstree_t *fs, tree_node_t *node);

/* Additional meta data stored in a tree_node_t for regular files. */
struct file_info_t {
	/* Linked list pointer for files in fstree_t */
	file_info_t *next;

	/* Path to the input file. */
	char *input_file;

	sqfs_inode_generic_t *inode;

	/* used by sort file processing */
	sqfs_s64 priority;
	int flags;
	bool already_matched;
};

/* Additional meta data stored in a tree_node_t for directories */
struct dir_info_t {
	/* Linked list head for children in the directory */
	tree_node_t *children;

	/* Set to true for implicitly generated directories.  */
	bool created_implicitly;

	/* Used by recursive tree walking code to avoid hard link loops */
	bool visited;
};

/* A node in a file system tree */
struct tree_node_t {
	/* Parent directory children linked list pointer. */
	tree_node_t *next;

	/* Root node has this set to NULL. */
	tree_node_t *parent;

	/* For the root node, this points to an empty string. */
	char *name;

	sqfs_u32 xattr_idx;
	sqfs_u32 uid;
	sqfs_u32 gid;
	sqfs_u32 inode_num;
	sqfs_u32 mod_time;
	sqfs_u16 mode;
	sqfs_u16 link_count;

	/* SquashFS inode refernce number. 32 bit offset of the meta data
	   block start (relative to inode table start), shifted left by 16
	   and ored with a 13 bit offset into the uncompressed meta data block.

	   Generated on the fly when writing inodes. */
	sqfs_u64 inode_ref;

	/* Type specific data. "target" pointer is into payload area below. */
	union {
		dir_info_t dir;
		file_info_t file;
		char *target;
		sqfs_u64 devno;
		tree_node_t *target_node;
	} data;

	sqfs_u8 payload[];
};

/* Encapsulates a file system tree */
struct fstree_t {
	struct stat defaults;
	size_t unique_inode_count;

	/* flat array of all nodes that have an inode number */
	tree_node_t **inodes;

	tree_node_t *root;

	/* linear linked list of all regular files */
	file_info_t *files;
};

/*
  Initializing means copying over the default values and creating a root node.
  On error, an error message is written to stderr.

  The string `defaults` can specify default attributes (mode, uid, gid, mtime)
  as a comma separated list of key value paris (<key>=<value>[,...]). The string
  is passed to getsubopt and will be altered.

  Returns 0 on success.
*/
int fstree_init(fstree_t *fs, char *defaults);

void fstree_cleanup(fstree_t *fs);

/*
  Create a tree node from a struct stat, node name and extra data.

  For symlinks, the extra part is interpreted as target. For regular files, it
  is interpreted as input path (can be NULL). The name doesn't have to be null
  terminated, a length has to be specified.

  This function does not print anything to stderr, instead it sets an
  appropriate errno value.

  The resulting node can be freed with a single free() call.
*/
tree_node_t *fstree_mknode(tree_node_t *parent, const char *name,
			   size_t name_len, const char *extra,
			   const struct stat *sb);

/*
  Add a node to an fstree at a specific path.

  If some components of the path don't exist, they are created as directories
  with default permissions, like mkdir -p would, and marked as implcitily
  created. A subsequent call that tries to create an existing tree node will
  fail, except if the target is an implicitly created directory node and the
  call tries to create it as a directory (this will simply overwrite the
  permissions and ownership). The implicitly created flag is then cleared.
  Subsequent attempts to create an existing directory again will then also
  fail.

  This function does not print anything to stderr, instead it sets an
  appropriate errno value. Internally it uses fstree_mknode to create the node.
*/
tree_node_t *fstree_add_generic(fstree_t *fs, const char *path,
				const struct stat *sb, const char *extra);

/*
  Parses the file format accepted by gensquashfs and produce a file system
  tree from it. File input paths are interpreted as relative to the current
  working directory.

  On failure, an error report with filename and line number is written
  to stderr.

  Returns 0 on success.
 */
int fstree_from_file(fstree_t *fs, const char *filename,
		     const char *basepath);

int fstree_from_file_stream(fstree_t *fs, istream_t *file,
			    const char *basepath);

/*
  This function performs all the necessary post processing steps on the file
  system tree, i.e. recursively sorting all directory entries by name,
  allocating inode numbers, resolving hard links and stringing all files nodes
  together into a linked list.

  The total inode count is stored in unique_inode_count. The head of the file
  list is pointed to by fs->files.

  The "inodes" array is allocated and each node that has an inode number is
  mapped into the array at index inode_num - 1.

  Returns 0 on success, prints to stderr on failure.
 */
int fstree_post_process(fstree_t *fs);

/*
  Generate a string holding the full path of a node. Returned
  string must be freed.

  Returns NULL on failure and sets errno.
*/
char *fstree_get_path(tree_node_t *node);

/*
  Resolve a path to a tree node. Returns NULL on failure and sets errno.

  If "create_implicitly" is set to true, the function acts essentially like
  mkdir_p if part of the path doesn't exist yet.

  If "stop_at_parent" is true, the function stops at the last component and
  returns the parent or would-be-parent of the last path component, but doesn't
  check if the last path component exists or not.
 */
tree_node_t *fstree_get_node_by_path(fstree_t *fs, tree_node_t *root,
				     const char *path, bool create_implicitly,
				     bool stop_at_parent);

/*
  Convert back to forward slashed, remove all preceeding and trailing slashes,
  collapse all sequences of slashes, remove all path components that are '.'
  and returns failure state if one of the path components is '..'.

  Returns 0 on success.
*/
int canonicalize_name(char *filename);

/*
  Returns true if a given filename is sane, false if it is not (e.g. contains
  slashes or it is equal to '.' or '..').

  If check_os_specific is true, this also checks if the filename contains
  a character, or is equal to a name, that is black listed on the current OS.
  E.g. on Windows, a file named "COM0" or "AUX" is a no-no.
 */
bool is_filename_sane(const char *name, bool check_os_specific);

/*
  Add a hard link node. Returns NULL on failure and sets errno.
 */
tree_node_t *fstree_add_hard_link(fstree_t *fs, const char *path,
				  const char *target);

/*
  Resolve a hard link node and replace it with a direct pointer to the target.

  Returns 0 on success. On failure, errno is set.
 */
int fstree_resolve_hard_link(fstree_t *fs, tree_node_t *node);

/*
  Recursively scan a directory to build a file system tree.

  Returns 0 on success, prints to stderr on failure.
 */
int fstree_from_dir(fstree_t *fs, tree_node_t *root,
		    const char *path, scan_node_callback cb, void *user,
		    unsigned int flags);

/*
  Same as fstree_from_dir, but scans a sub-directory inside the specified path.

  Returns 0 on success, prints to stderr on failure.
 */
int fstree_from_subdir(fstree_t *fs, tree_node_t *root,
		       const char *path, const char *subdir,
		       scan_node_callback cb, void *user, unsigned int flags);

int fstree_sort_files(fstree_t *fs, istream_t *sortfile);

#endif /* FSTREE_H */