1 /* @(#)inode.c	1.20 18/05/14 Copyright 2006-2018 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static	UConst char sccsid[] =
5 	"@(#)inode.c	1.20 18/05/14 Copyright 2006-2016 J. Schilling";
6 #endif
7 /*
8  *	Inode and link count handling for ISO-9660/RR
9  *
10  *	This module computes and sets up a RR link count that reflects
11  *	the name-count for files/directories in the ISO-9660/RR image.
12  *	This module also assigns inode numbers tp all files/directories
13  *	using either the RRip-112 protocol or a mkisofs specific method
14  *	of asigning the related number to the "extent" field in the ISO
15  *	directory record.
16  *
17  *	Copyright (c) 2006-2018 J. Schilling
18  */
19 /*
20  * This program is free software; you can redistribute it and/or modify
21  * it under the terms of the GNU General Public License version 2
22  * as published by the Free Software Foundation.
23  *
24  * This program is distributed in the hope that it will be useful,
25  * but WITHOUT ANY WARRANTY; without even the implied warranty of
26  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
27  * GNU General Public License for more details.
28  *
29  * You should have received a copy of the GNU General Public License along with
30  * this program; see the file COPYING.  If not, write to the Free Software
31  * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
32  */
33 
34 #include "mkisofs.h"
35 #include <schily/schily.h>
36 
37 /*
38  * Highest inode value we assign in this session.
39  */
40 LOCAL	UInt32_t null_ino_high;
41 
42 EXPORT	void	do_inode		__PR((struct directory *dpnt));
43 EXPORT	void	do_dir_nlink		__PR((struct directory *dpnt));
44 LOCAL	void	assign_inodes		__PR((struct directory *dpnt));
45 LOCAL	void	compute_linkcount	__PR((struct directory *dpnt));
46 LOCAL	void	assign_linkcount	__PR((struct directory *dpnt));
47 LOCAL	void	update_inode		__PR((struct directory_entry *s_entry, int value));
48 LOCAL	void	update_nlink		__PR((struct directory_entry *s_entry, int value));
49 LOCAL	int	update_dir_nlink	__PR((struct directory *dpnt));
50 
51 /*
52  * Inode/hard link related stuff for non-directory type files.
53  */
54 EXPORT void
do_inode(dpnt)55 do_inode(dpnt)
56 	struct directory	*dpnt;
57 {
58 	null_ino_high = null_inodes;
59 
60 	if (correct_inodes)
61 		assign_inodes(root);
62 
63 #ifdef	UDF
64 	if (!use_RockRidge && !use_udf)
65 		return;
66 #else
67 	if (!use_RockRidge)
68 		return;
69 #endif
70 	if (!cache_inodes)		/* Never FALSE if correct_inodes TRUE */
71 		return;
72 
73 	compute_linkcount(dpnt);
74 	if (use_RockRidge)		/* If we have Rock Ridge extensions, */
75 		assign_linkcount(dpnt);	/* reassign computed linkcount in RR */
76 
77 	if (null_inodes < last_extent)
78 		comerrno(EX_BAD, _("Inode number overflow, too many files in file system.\n"));
79 }
80 
81 /*
82  * Set the link count for directories to 2 + number of sub-directories.
83  */
84 EXPORT void
do_dir_nlink(dpnt)85 do_dir_nlink(dpnt)
86 	struct directory	*dpnt;
87 {
88 	int	rootlinks;
89 
90 	if (!use_RockRidge)
91 		return;
92 
93 	/*
94 	 * Update everything except "/..".
95 	 */
96 	rootlinks = update_dir_nlink(dpnt);
97 	if (reloc_dir)
98 		rootlinks--;	/* rr_moved is hidden */
99 	/*
100 	 * Update "/." now.
101 	 */
102 	update_nlink(dpnt->contents, rootlinks);
103 	/*
104 	 * Update "/.." now.
105 	 */
106 	update_nlink(dpnt->contents->next, rootlinks);
107 }
108 
109 /*
110  * Assign inode numbers to files of zero size and to symlinks.
111  */
112 LOCAL void
assign_inodes(dpnt)113 assign_inodes(dpnt)
114 	struct directory	*dpnt;
115 {
116 	struct directory_entry	*s_entry;
117 	struct file_hash	*s_hash;
118 
119 	while (dpnt) {
120 		s_entry = dpnt->contents;
121 		for (s_entry = dpnt->contents; s_entry; s_entry = s_entry->next) {
122 			if (s_entry->starting_block == 0) {
123 				s_hash = find_hash(s_entry);
124 				/* find_directory_hash() ? */
125 				if (s_hash)
126 					s_entry->starting_block = s_hash->starting_block;
127 			}
128 			if (s_entry->starting_block == 0 && s_entry->size != 0) {
129 				unsigned int e = get_733((char *)s_entry->isorec.extent);
130 
131 				if (e != 0) {
132 					errmsgno(EX_BAD,
133 					_("Implementation botch, fetching extend %d for %s from dir entry.\n"),
134 					e, s_entry->whole_name);
135 				}
136 			}
137 			if (use_RockRidge && s_entry->starting_block > 0)
138 				update_inode(s_entry, s_entry->starting_block);
139 
140 			/*
141 			 * Be careful: UDF Symlinks have size != 0, then
142 			 * s_hash->starting_block is a valid inode number.
143 			 */
144 			if (s_entry->size != 0)
145 				continue;
146 #ifdef	UDF
147 			if ((s_entry->de_flags & IS_SYMLINK) != 0 &&
148 			    create_udfsymlinks)
149 				continue;
150 #else
151 			if ((s_entry->de_flags & IS_SYMLINK) != 0)
152 				continue;
153 #endif
154 
155 			if (s_entry->isorec.flags[0] & ISO_DIRECTORY)
156 				continue;
157 
158 			/*
159 			 * Assign inodes to symbolic links.
160 			 */
161 			if (s_entry->dev == UNCACHED_DEVICE && s_entry->inode == UNCACHED_INODE) {
162 				s_entry->dev = PREV_SESS_DEV;
163 				s_entry->inode = null_inodes;
164 			}
165 			s_hash = find_hash(s_entry);
166 			if (s_hash) {
167 				/*
168 				 * Paranoia: Check for hashed files without proper inode #.
169 				 */
170 				if (s_hash->starting_block <= last_extent)
171 					comerrno(EX_BAD,
172 					_("Implementation botch: Hashed file '%s' has illegal inode %u.\n"),
173 					s_entry->whole_name ?
174 					s_entry->whole_name : s_entry->name,
175 					s_hash->starting_block);
176 				set_733((char *)s_entry->isorec.extent, s_hash->starting_block);
177 				s_entry->starting_block = s_hash->starting_block;
178 			} else {
179 				s_entry->starting_block = null_inodes--;
180 				set_733((char *)s_entry->isorec.extent, s_entry->starting_block);
181 				add_hash(s_entry);
182 			}
183 			if (use_RockRidge)
184 				update_inode(s_entry, s_entry->starting_block);
185 		}
186 		if (dpnt->subdir) {
187 			assign_inodes(dpnt->subdir);
188 		}
189 
190 		dpnt = dpnt->next;
191 	}
192 }
193 
194 /*
195  * Compute the link count for non-directory type files.
196  */
197 LOCAL void
compute_linkcount(dpnt)198 compute_linkcount(dpnt)
199 	struct directory	*dpnt;
200 {
201 	struct directory_entry	*s_entry;
202 	struct file_hash	*s_hash;
203 
204 	while (dpnt) {
205 		s_entry = dpnt->contents;
206 		for (s_entry = dpnt->contents; s_entry; s_entry = s_entry->next) {
207 			/*
208 			 * Skip directories.
209 			 */
210 			if (s_entry->isorec.flags[0] & ISO_DIRECTORY)
211 				continue;
212 			if (s_entry->isorec.flags[0] & ISO_MULTIEXTENT)
213 				continue;
214 			if (s_entry->de_flags & RELOCATED_DIRECTORY)
215 				continue;
216 
217 			/*
218 			 * skip resource files or file stream files
219 			 * XXX should we assign a standard link count == 1 instead?
220 			 */
221 			if (s_entry->de_flags & RESOURCE_FORK)
222 				continue;
223 
224 			/*
225 			 * Assign inodes to symbolic links.
226 			 * We never come here in case that we create correct inodes,
227 			 * except with UDF symlinks.
228 			 */
229 			if (s_entry->dev == UNCACHED_DEVICE && s_entry->inode == UNCACHED_INODE) {
230 				s_entry->dev = PREV_SESS_DEV;
231 
232 				/*
233 				 * With UDF symlinks, the starting_block is a
234 				 * valid inode number.
235 				 */
236 #ifdef	UDF
237 				if ((s_entry->de_flags & IS_SYMLINK) != 0 &&
238 				    create_udfsymlinks) {
239 #else
240 				if ((s_entry->de_flags & IS_SYMLINK) != 0) {
241 #endif
242 					s_entry->inode = s_entry->starting_block;
243 				} else {
244 					s_entry->inode = null_inodes--;	/* Only used for caching */
245 					if (correct_inodes)
246 						comerrno(EX_BAD,
247 						_("Implementation botch: Unhashed file '%s'.\n"),
248 						s_entry->whole_name ?
249 						s_entry->whole_name : s_entry->name);
250 				}
251 			}
252 			s_hash = find_hash(s_entry);
253 			if (s_hash) {
254 				s_hash->nlink++;
255 			} else {
256 				add_hash(s_entry);
257 				s_hash = find_hash(s_entry);
258 				if (s_hash == NULL) {
259 					if (s_entry->dev == UNCACHED_DEVICE &&
260 					    s_entry->inode == TABLE_INODE) {
261 						continue;
262 					}
263 					comerrno(EX_BAD,
264 					_("Implementation botch: File '%s' not hashed (dev/ino %llX/%llX).\n"),
265 					s_entry->whole_name ?
266 					s_entry->whole_name : s_entry->name,
267 					(Llong)s_entry->dev,
268 					(Llong)s_entry->inode);
269 				}
270 				s_hash->nlink++;
271 			}
272 		}
273 		if (dpnt->subdir) {
274 			compute_linkcount(dpnt->subdir);
275 		}
276 
277 		dpnt = dpnt->next;
278 	}
279 }
280 
281 /*
282  * Assig the link count for non-directory type files to the value
283  * computed with compute_linkcount().
284  */
285 LOCAL void
assign_linkcount(dpnt)286 assign_linkcount(dpnt)
287 	struct directory	*dpnt;
288 {
289 	struct directory_entry	*s_entry;
290 	struct file_hash	*s_hash;
291 
292 	while (dpnt) {
293 		s_entry = dpnt->contents;
294 		for (s_entry = dpnt->contents; s_entry; s_entry = s_entry->next) {
295 			if (s_entry->isorec.flags[0] & ISO_DIRECTORY)
296 				continue;
297 			if (s_entry->isorec.flags[0] & ISO_MULTIEXTENT)
298 				continue;
299 			if (s_entry->de_flags & RELOCATED_DIRECTORY)
300 				continue;
301 			/*
302 			 * skip resource files or file stream files
303 			 */
304 			if (s_entry->de_flags & RESOURCE_FORK)
305 				continue;
306 
307 			s_hash = find_hash(s_entry);
308 			if (s_hash) {
309 				update_nlink(s_entry, s_hash->nlink);
310 			} else {
311 				if (s_entry->dev == UNCACHED_DEVICE &&
312 				    s_entry->inode == TABLE_INODE) {
313 					continue;
314 				}
315 				comerrno(EX_BAD,
316 				_("Implementation botch: File '%s' not hashed.\n"),
317 					s_entry->whole_name ?
318 					s_entry->whole_name : s_entry->name);
319 			}
320 		}
321 		if (dpnt->subdir) {
322 			assign_linkcount(dpnt->subdir);
323 		}
324 
325 		dpnt = dpnt->next;
326 	}
327 }
328 
329 /*
330  * Rewrite the content of the RR inode field in the PX record.
331  */
332 LOCAL void
update_inode(s_entry,value)333 update_inode(s_entry, value)
334 	struct directory_entry	*s_entry;
335 	int			value;
336 {
337 	unsigned char	*pnt;
338 	int		len;
339 
340 	if (!rrip112)
341 		return;
342 
343 	pnt = s_entry->rr_attributes;
344 	len = s_entry->total_rr_attr_size;
345 	pnt = parse_xa(pnt, &len, 0);
346 	while (len >= 4) {
347 		if (pnt[3] != 1 && pnt[3] != 2) {
348 			errmsgno(EX_BAD,
349 				_("**BAD RRVERSION (%d) in '%c%c' field (%2.2X %2.2X).\n"),
350 				pnt[3], pnt[0], pnt[1], pnt[0], pnt[1]);
351 		}
352 		if (pnt[2] < 4) {
353 			errmsgno(EX_BAD,
354 				_("**BAD RRLEN (%d) in '%2.2s' field %2.2X %2.2X.\n"),
355 				pnt[2], pnt, pnt[0], pnt[1]);
356 			break;
357 		}
358 		if (pnt[0] == 'P' && pnt[1] == 'X') {
359 			if ((pnt[2] & 0xFF) < 44)	/* Paranoia */
360 				return;
361 			set_733((char *)pnt + 36, value);
362 			break;
363 		}
364 		len -= pnt[2];
365 		pnt += pnt[2];
366 	}
367 }
368 
369 /*
370  * Rewrite the content of the RR nlink field in the PX record.
371  */
372 LOCAL void
update_nlink(s_entry,value)373 update_nlink(s_entry, value)
374 	struct directory_entry	*s_entry;
375 	int			value;
376 {
377 	unsigned char	*pnt;
378 	int		len;
379 
380 	pnt = s_entry->rr_attributes;
381 	len = s_entry->total_rr_attr_size;
382 	pnt = parse_xa(pnt, &len, 0);
383 	while (len >= 4) {
384 		if (pnt[3] != 1 && pnt[3] != 2) {
385 			errmsgno(EX_BAD,
386 				_("**BAD RRVERSION (%d) in '%c%c' field (%2.2X %2.2X).\n"),
387 				pnt[3], pnt[0], pnt[1], pnt[0], pnt[1]);
388 		}
389 		if (pnt[2] < 4) {
390 			errmsgno(EX_BAD,
391 				_("**BAD RRLEN (%d) in '%2.2s' field %2.2X %2.2X.\n"),
392 				pnt[2], pnt, pnt[0], pnt[1]);
393 			break;
394 		}
395 		if (pnt[0] == 'P' && pnt[1] == 'X') {
396 			set_733((char *)pnt + 12, value);
397 			break;
398 		}
399 		len -= pnt[2];
400 		pnt += pnt[2];
401 	}
402 }
403 
404 /*
405  * Set the link count for directories to 2 + number of sub-directories.
406  * This is done here for all diresctories except for "/..".
407  */
408 LOCAL int
update_dir_nlink(dpnt)409 update_dir_nlink(dpnt)
410 	struct directory *dpnt;
411 {
412 	struct directory *xpnt;
413 	struct directory_entry *s_entry;
414 	int		i = 0;
415 
416 	while (dpnt) {
417 		if (dpnt->dir_flags & INHIBIT_ISO9660_ENTRY) {
418 			dpnt = dpnt->next;
419 			continue;
420 		}
421 		/*
422 		 * First, count up the number of subdirectories this dir has.
423 		 */
424 		for (i = 0, xpnt = dpnt->subdir; xpnt; xpnt = xpnt->next)
425 			if ((xpnt->dir_flags & INHIBIT_ISO9660_ENTRY) == 0)
426 				i++;
427 		/*
428 		 * Next check to see if we have any relocated directories in
429 		 * this directory. The nlink field will include these as
430 		 * real directories when they are properly relocated.
431 		 * In the non-rockridge disk, the relocated entries appear as
432 		 * zero length files.
433 		 */
434 		for (s_entry = dpnt->contents; s_entry;
435 						s_entry = s_entry->next) {
436 			if ((s_entry->de_flags & RELOCATED_DIRECTORY) != 0 &&
437 				(s_entry->de_flags & INHIBIT_ISO9660_ENTRY) ==
438 									0) {
439 				i++;
440 			}
441 		}
442 		/*
443 		 * Now update the field in the Rock Ridge entry.
444 		 */
445 		update_nlink(dpnt->self, i + 2);
446 
447 		/*
448 		 * Update the '.' entry for this directory.
449 		 */
450 		update_nlink(dpnt->contents, i + 2);
451 
452 		/*
453 		 * Update all of the '..' entries that point to this guy.
454 		 */
455 		for (xpnt = dpnt->subdir; xpnt; xpnt = xpnt->next) {
456 			update_nlink(xpnt->contents->next, i + 2);
457 		}
458 
459 		if (dpnt->subdir)
460 			update_dir_nlink(dpnt->subdir);
461 		dpnt = dpnt->next;
462 	}
463 	return (i+2);
464 }
465