xref: /aosp_15_r20/external/fsck_msdos/dir.c (revision 9558e6ac2e10ab0fef46fdd14187b840555f86f4)
1*9558e6acSTreehugger Robot /*-
2*9558e6acSTreehugger Robot  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3*9558e6acSTreehugger Robot  *
4*9558e6acSTreehugger Robot  * Copyright (c) 2019 Google LLC
5*9558e6acSTreehugger Robot  * Copyright (C) 1995, 1996, 1997 Wolfgang Solfrank
6*9558e6acSTreehugger Robot  * Copyright (c) 1995 Martin Husemann
7*9558e6acSTreehugger Robot  * Some structure declaration borrowed from Paul Popelka
8*9558e6acSTreehugger Robot  * ([email protected]), see /sys/msdosfs/ for reference.
9*9558e6acSTreehugger Robot  *
10*9558e6acSTreehugger Robot  * Redistribution and use in source and binary forms, with or without
11*9558e6acSTreehugger Robot  * modification, are permitted provided that the following conditions
12*9558e6acSTreehugger Robot  * are met:
13*9558e6acSTreehugger Robot  * 1. Redistributions of source code must retain the above copyright
14*9558e6acSTreehugger Robot  *    notice, this list of conditions and the following disclaimer.
15*9558e6acSTreehugger Robot  * 2. Redistributions in binary form must reproduce the above copyright
16*9558e6acSTreehugger Robot  *    notice, this list of conditions and the following disclaimer in the
17*9558e6acSTreehugger Robot  *    documentation and/or other materials provided with the distribution.
18*9558e6acSTreehugger Robot  *
19*9558e6acSTreehugger Robot  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
20*9558e6acSTreehugger Robot  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21*9558e6acSTreehugger Robot  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22*9558e6acSTreehugger Robot  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23*9558e6acSTreehugger Robot  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24*9558e6acSTreehugger Robot  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25*9558e6acSTreehugger Robot  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26*9558e6acSTreehugger Robot  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27*9558e6acSTreehugger Robot  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28*9558e6acSTreehugger Robot  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29*9558e6acSTreehugger Robot  */
30*9558e6acSTreehugger Robot 
31*9558e6acSTreehugger Robot 
32*9558e6acSTreehugger Robot #include <sys/cdefs.h>
33*9558e6acSTreehugger Robot #ifndef lint
34*9558e6acSTreehugger Robot __RCSID("$NetBSD: dir.c,v 1.20 2006/06/05 16:51:18 christos Exp $");
35*9558e6acSTreehugger Robot static const char rcsid[] =
36*9558e6acSTreehugger Robot   "$FreeBSD$";
37*9558e6acSTreehugger Robot #endif /* not lint */
38*9558e6acSTreehugger Robot 
39*9558e6acSTreehugger Robot #include <assert.h>
40*9558e6acSTreehugger Robot #include <inttypes.h>
41*9558e6acSTreehugger Robot #include <stdio.h>
42*9558e6acSTreehugger Robot #include <stdlib.h>
43*9558e6acSTreehugger Robot #include <string.h>
44*9558e6acSTreehugger Robot #include <ctype.h>
45*9558e6acSTreehugger Robot #include <unistd.h>
46*9558e6acSTreehugger Robot #include <time.h>
47*9558e6acSTreehugger Robot 
48*9558e6acSTreehugger Robot #include <sys/param.h>
49*9558e6acSTreehugger Robot 
50*9558e6acSTreehugger Robot #include "ext.h"
51*9558e6acSTreehugger Robot #include "fsutil.h"
52*9558e6acSTreehugger Robot 
53*9558e6acSTreehugger Robot #define	SLOT_EMPTY	0x00		/* slot has never been used */
54*9558e6acSTreehugger Robot #define	SLOT_E5		0x05		/* the real value is 0xe5 */
55*9558e6acSTreehugger Robot #define	SLOT_DELETED	0xe5		/* file in this slot deleted */
56*9558e6acSTreehugger Robot 
57*9558e6acSTreehugger Robot #define	ATTR_NORMAL	0x00		/* normal file */
58*9558e6acSTreehugger Robot #define	ATTR_READONLY	0x01		/* file is readonly */
59*9558e6acSTreehugger Robot #define	ATTR_HIDDEN	0x02		/* file is hidden */
60*9558e6acSTreehugger Robot #define	ATTR_SYSTEM	0x04		/* file is a system file */
61*9558e6acSTreehugger Robot #define	ATTR_VOLUME	0x08		/* entry is a volume label */
62*9558e6acSTreehugger Robot #define	ATTR_DIRECTORY	0x10		/* entry is a directory name */
63*9558e6acSTreehugger Robot #define	ATTR_ARCHIVE	0x20		/* file is new or modified */
64*9558e6acSTreehugger Robot 
65*9558e6acSTreehugger Robot #define	ATTR_WIN95	0x0f		/* long name record */
66*9558e6acSTreehugger Robot 
67*9558e6acSTreehugger Robot /*
68*9558e6acSTreehugger Robot  * This is the format of the contents of the deTime field in the direntry
69*9558e6acSTreehugger Robot  * structure.
70*9558e6acSTreehugger Robot  * We don't use bitfields because we don't know how compilers for
71*9558e6acSTreehugger Robot  * arbitrary machines will lay them out.
72*9558e6acSTreehugger Robot  */
73*9558e6acSTreehugger Robot #define DT_2SECONDS_MASK	0x1F	/* seconds divided by 2 */
74*9558e6acSTreehugger Robot #define DT_2SECONDS_SHIFT	0
75*9558e6acSTreehugger Robot #define DT_MINUTES_MASK		0x7E0	/* minutes */
76*9558e6acSTreehugger Robot #define DT_MINUTES_SHIFT	5
77*9558e6acSTreehugger Robot #define DT_HOURS_MASK		0xF800	/* hours */
78*9558e6acSTreehugger Robot #define DT_HOURS_SHIFT		11
79*9558e6acSTreehugger Robot 
80*9558e6acSTreehugger Robot /*
81*9558e6acSTreehugger Robot  * This is the format of the contents of the deDate field in the direntry
82*9558e6acSTreehugger Robot  * structure.
83*9558e6acSTreehugger Robot  */
84*9558e6acSTreehugger Robot #define DD_DAY_MASK		0x1F	/* day of month */
85*9558e6acSTreehugger Robot #define DD_DAY_SHIFT		0
86*9558e6acSTreehugger Robot #define DD_MONTH_MASK		0x1E0	/* month */
87*9558e6acSTreehugger Robot #define DD_MONTH_SHIFT		5
88*9558e6acSTreehugger Robot #define DD_YEAR_MASK		0xFE00	/* year - 1980 */
89*9558e6acSTreehugger Robot #define DD_YEAR_SHIFT		9
90*9558e6acSTreehugger Robot 
91*9558e6acSTreehugger Robot 
92*9558e6acSTreehugger Robot /* dir.c */
93*9558e6acSTreehugger Robot static struct dosDirEntry *newDosDirEntry(void);
94*9558e6acSTreehugger Robot static void freeDosDirEntry(struct dosDirEntry *);
95*9558e6acSTreehugger Robot static struct dirTodoNode *newDirTodo(void);
96*9558e6acSTreehugger Robot static void freeDirTodo(struct dirTodoNode *);
97*9558e6acSTreehugger Robot static char *fullpath(struct dosDirEntry *);
98*9558e6acSTreehugger Robot static u_char calcShortSum(u_char *);
99*9558e6acSTreehugger Robot static int delete(struct fat_descriptor *, cl_t, int, cl_t, int, int);
100*9558e6acSTreehugger Robot static int removede(struct fat_descriptor *, u_char *, u_char *,
101*9558e6acSTreehugger Robot     cl_t, cl_t, cl_t, char *, int);
102*9558e6acSTreehugger Robot static int checksize(struct fat_descriptor *, u_char *, struct dosDirEntry *);
103*9558e6acSTreehugger Robot static int readDosDirSection(struct fat_descriptor *, struct dosDirEntry *);
104*9558e6acSTreehugger Robot 
105*9558e6acSTreehugger Robot /*
106*9558e6acSTreehugger Robot  * Manage free dosDirEntry structures.
107*9558e6acSTreehugger Robot  */
108*9558e6acSTreehugger Robot static struct dosDirEntry *freede;
109*9558e6acSTreehugger Robot 
110*9558e6acSTreehugger Robot static struct dosDirEntry *
newDosDirEntry(void)111*9558e6acSTreehugger Robot newDosDirEntry(void)
112*9558e6acSTreehugger Robot {
113*9558e6acSTreehugger Robot 	struct dosDirEntry *de;
114*9558e6acSTreehugger Robot 
115*9558e6acSTreehugger Robot 	if (!(de = freede)) {
116*9558e6acSTreehugger Robot 		if (!(de = malloc(sizeof *de)))
117*9558e6acSTreehugger Robot 			return (NULL);
118*9558e6acSTreehugger Robot 	} else
119*9558e6acSTreehugger Robot 		freede = de->next;
120*9558e6acSTreehugger Robot 	return de;
121*9558e6acSTreehugger Robot }
122*9558e6acSTreehugger Robot 
123*9558e6acSTreehugger Robot static void
freeDosDirEntry(struct dosDirEntry * de)124*9558e6acSTreehugger Robot freeDosDirEntry(struct dosDirEntry *de)
125*9558e6acSTreehugger Robot {
126*9558e6acSTreehugger Robot 	de->next = freede;
127*9558e6acSTreehugger Robot 	freede = de;
128*9558e6acSTreehugger Robot }
129*9558e6acSTreehugger Robot 
130*9558e6acSTreehugger Robot /*
131*9558e6acSTreehugger Robot  * The same for dirTodoNode structures.
132*9558e6acSTreehugger Robot  */
133*9558e6acSTreehugger Robot static struct dirTodoNode *freedt;
134*9558e6acSTreehugger Robot 
135*9558e6acSTreehugger Robot static struct dirTodoNode *
newDirTodo(void)136*9558e6acSTreehugger Robot newDirTodo(void)
137*9558e6acSTreehugger Robot {
138*9558e6acSTreehugger Robot 	struct dirTodoNode *dt;
139*9558e6acSTreehugger Robot 
140*9558e6acSTreehugger Robot 	if (!(dt = freedt)) {
141*9558e6acSTreehugger Robot 		if (!(dt = malloc(sizeof *dt)))
142*9558e6acSTreehugger Robot 			return 0;
143*9558e6acSTreehugger Robot 	} else
144*9558e6acSTreehugger Robot 		freedt = dt->next;
145*9558e6acSTreehugger Robot 	return dt;
146*9558e6acSTreehugger Robot }
147*9558e6acSTreehugger Robot 
148*9558e6acSTreehugger Robot static void
freeDirTodo(struct dirTodoNode * dt)149*9558e6acSTreehugger Robot freeDirTodo(struct dirTodoNode *dt)
150*9558e6acSTreehugger Robot {
151*9558e6acSTreehugger Robot 	dt->next = freedt;
152*9558e6acSTreehugger Robot 	freedt = dt;
153*9558e6acSTreehugger Robot }
154*9558e6acSTreehugger Robot 
155*9558e6acSTreehugger Robot /*
156*9558e6acSTreehugger Robot  * The stack of unread directories
157*9558e6acSTreehugger Robot  */
158*9558e6acSTreehugger Robot static struct dirTodoNode *pendingDirectories = NULL;
159*9558e6acSTreehugger Robot 
160*9558e6acSTreehugger Robot /*
161*9558e6acSTreehugger Robot  * Return the full pathname for a directory entry.
162*9558e6acSTreehugger Robot  */
163*9558e6acSTreehugger Robot static char *
fullpath(struct dosDirEntry * dir)164*9558e6acSTreehugger Robot fullpath(struct dosDirEntry *dir)
165*9558e6acSTreehugger Robot {
166*9558e6acSTreehugger Robot 	static char namebuf[MAXPATHLEN + 1];
167*9558e6acSTreehugger Robot 	char *cp, *np;
168*9558e6acSTreehugger Robot 	int nl;
169*9558e6acSTreehugger Robot 
170*9558e6acSTreehugger Robot 	cp = namebuf + sizeof namebuf;
171*9558e6acSTreehugger Robot 	*--cp = '\0';
172*9558e6acSTreehugger Robot 
173*9558e6acSTreehugger Robot 	for(;;) {
174*9558e6acSTreehugger Robot 		np = dir->lname[0] ? dir->lname : dir->name;
175*9558e6acSTreehugger Robot 		nl = strlen(np);
176*9558e6acSTreehugger Robot 		if (cp <= namebuf + 1 + nl) {
177*9558e6acSTreehugger Robot 			*--cp = '?';
178*9558e6acSTreehugger Robot 			break;
179*9558e6acSTreehugger Robot 		}
180*9558e6acSTreehugger Robot 		cp -= nl;
181*9558e6acSTreehugger Robot 		memcpy(cp, np, nl);
182*9558e6acSTreehugger Robot 		dir = dir->parent;
183*9558e6acSTreehugger Robot 		if (!dir)
184*9558e6acSTreehugger Robot 			break;
185*9558e6acSTreehugger Robot 		*--cp = '/';
186*9558e6acSTreehugger Robot 	}
187*9558e6acSTreehugger Robot 
188*9558e6acSTreehugger Robot 	return cp;
189*9558e6acSTreehugger Robot }
190*9558e6acSTreehugger Robot 
191*9558e6acSTreehugger Robot /*
192*9558e6acSTreehugger Robot  * Calculate a checksum over an 8.3 alias name
193*9558e6acSTreehugger Robot  */
194*9558e6acSTreehugger Robot static inline u_char
calcShortSum(u_char * p)195*9558e6acSTreehugger Robot calcShortSum(u_char *p)
196*9558e6acSTreehugger Robot {
197*9558e6acSTreehugger Robot 	u_char sum = 0;
198*9558e6acSTreehugger Robot 	int i;
199*9558e6acSTreehugger Robot 
200*9558e6acSTreehugger Robot 	for (i = 0; i < 11; i++) {
201*9558e6acSTreehugger Robot 		sum = (sum << 7)|(sum >> 1);	/* rotate right */
202*9558e6acSTreehugger Robot 		sum += p[i];
203*9558e6acSTreehugger Robot 	}
204*9558e6acSTreehugger Robot 
205*9558e6acSTreehugger Robot 	return sum;
206*9558e6acSTreehugger Robot }
207*9558e6acSTreehugger Robot 
208*9558e6acSTreehugger Robot /*
209*9558e6acSTreehugger Robot  * Global variables temporarily used during a directory scan
210*9558e6acSTreehugger Robot  */
211*9558e6acSTreehugger Robot static char longName[DOSLONGNAMELEN] = "";
212*9558e6acSTreehugger Robot static u_char *buffer = NULL;
213*9558e6acSTreehugger Robot static u_char *delbuf = NULL;
214*9558e6acSTreehugger Robot 
215*9558e6acSTreehugger Robot static struct dosDirEntry *rootDir;
216*9558e6acSTreehugger Robot static struct dosDirEntry *lostDir;
217*9558e6acSTreehugger Robot 
218*9558e6acSTreehugger Robot /*
219*9558e6acSTreehugger Robot  * Init internal state for a new directory scan.
220*9558e6acSTreehugger Robot  */
221*9558e6acSTreehugger Robot int
resetDosDirSection(struct fat_descriptor * fat)222*9558e6acSTreehugger Robot resetDosDirSection(struct fat_descriptor *fat)
223*9558e6acSTreehugger Robot {
224*9558e6acSTreehugger Robot 	int rootdir_size, cluster_size;
225*9558e6acSTreehugger Robot 	int ret = FSOK;
226*9558e6acSTreehugger Robot 	size_t len;
227*9558e6acSTreehugger Robot 	struct bootblock *boot;
228*9558e6acSTreehugger Robot 
229*9558e6acSTreehugger Robot 	boot = fat_get_boot(fat);
230*9558e6acSTreehugger Robot 
231*9558e6acSTreehugger Robot 	rootdir_size = boot->bpbRootDirEnts * 32;
232*9558e6acSTreehugger Robot 	cluster_size = boot->bpbSecPerClust * boot->bpbBytesPerSec;
233*9558e6acSTreehugger Robot 
234*9558e6acSTreehugger Robot 	if ((buffer = malloc(len = MAX(rootdir_size, cluster_size))) == NULL) {
235*9558e6acSTreehugger Robot 		perr("No space for directory buffer (%zu)", len);
236*9558e6acSTreehugger Robot 		return FSFATAL;
237*9558e6acSTreehugger Robot 	}
238*9558e6acSTreehugger Robot 
239*9558e6acSTreehugger Robot 	if ((delbuf = malloc(len = cluster_size)) == NULL) {
240*9558e6acSTreehugger Robot 		free(buffer);
241*9558e6acSTreehugger Robot 		perr("No space for directory delbuf (%zu)", len);
242*9558e6acSTreehugger Robot 		return FSFATAL;
243*9558e6acSTreehugger Robot 	}
244*9558e6acSTreehugger Robot 
245*9558e6acSTreehugger Robot 	if ((rootDir = newDosDirEntry()) == NULL) {
246*9558e6acSTreehugger Robot 		free(buffer);
247*9558e6acSTreehugger Robot 		free(delbuf);
248*9558e6acSTreehugger Robot 		perr("No space for directory entry");
249*9558e6acSTreehugger Robot 		return FSFATAL;
250*9558e6acSTreehugger Robot 	}
251*9558e6acSTreehugger Robot 
252*9558e6acSTreehugger Robot 	memset(rootDir, 0, sizeof *rootDir);
253*9558e6acSTreehugger Robot 	if (boot->flags & FAT32) {
254*9558e6acSTreehugger Robot 		if (!fat_is_cl_head(fat, boot->bpbRootClust)) {
255*9558e6acSTreehugger Robot 			pfatal("Root directory doesn't start a cluster chain");
256*9558e6acSTreehugger Robot 			return FSFATAL;
257*9558e6acSTreehugger Robot 		}
258*9558e6acSTreehugger Robot 		rootDir->head = boot->bpbRootClust;
259*9558e6acSTreehugger Robot 	}
260*9558e6acSTreehugger Robot 
261*9558e6acSTreehugger Robot 	return ret;
262*9558e6acSTreehugger Robot }
263*9558e6acSTreehugger Robot 
264*9558e6acSTreehugger Robot /*
265*9558e6acSTreehugger Robot  * Cleanup after a directory scan
266*9558e6acSTreehugger Robot  */
267*9558e6acSTreehugger Robot void
finishDosDirSection(void)268*9558e6acSTreehugger Robot finishDosDirSection(void)
269*9558e6acSTreehugger Robot {
270*9558e6acSTreehugger Robot 	struct dirTodoNode *p, *np;
271*9558e6acSTreehugger Robot 	struct dosDirEntry *d, *nd;
272*9558e6acSTreehugger Robot 
273*9558e6acSTreehugger Robot 	for (p = pendingDirectories; p; p = np) {
274*9558e6acSTreehugger Robot 		np = p->next;
275*9558e6acSTreehugger Robot 		freeDirTodo(p);
276*9558e6acSTreehugger Robot 	}
277*9558e6acSTreehugger Robot 	pendingDirectories = NULL;
278*9558e6acSTreehugger Robot 	for (d = rootDir; d; d = nd) {
279*9558e6acSTreehugger Robot 		if ((nd = d->child) != NULL) {
280*9558e6acSTreehugger Robot 			d->child = 0;
281*9558e6acSTreehugger Robot 			continue;
282*9558e6acSTreehugger Robot 		}
283*9558e6acSTreehugger Robot 		if (!(nd = d->next))
284*9558e6acSTreehugger Robot 			nd = d->parent;
285*9558e6acSTreehugger Robot 		freeDosDirEntry(d);
286*9558e6acSTreehugger Robot 	}
287*9558e6acSTreehugger Robot 	rootDir = lostDir = NULL;
288*9558e6acSTreehugger Robot 	free(buffer);
289*9558e6acSTreehugger Robot 	free(delbuf);
290*9558e6acSTreehugger Robot 	buffer = NULL;
291*9558e6acSTreehugger Robot 	delbuf = NULL;
292*9558e6acSTreehugger Robot }
293*9558e6acSTreehugger Robot 
294*9558e6acSTreehugger Robot /*
295*9558e6acSTreehugger Robot  * Delete directory entries between startcl, startoff and endcl, endoff.
296*9558e6acSTreehugger Robot  */
297*9558e6acSTreehugger Robot static int
delete(struct fat_descriptor * fat,cl_t startcl,int startoff,cl_t endcl,int endoff,int notlast)298*9558e6acSTreehugger Robot delete(struct fat_descriptor *fat, cl_t startcl,
299*9558e6acSTreehugger Robot     int startoff, cl_t endcl, int endoff, int notlast)
300*9558e6acSTreehugger Robot {
301*9558e6acSTreehugger Robot 	u_char *s, *e;
302*9558e6acSTreehugger Robot 	off_t off;
303*9558e6acSTreehugger Robot 	int clsz, fd;
304*9558e6acSTreehugger Robot 	struct bootblock *boot;
305*9558e6acSTreehugger Robot 
306*9558e6acSTreehugger Robot 	boot = fat_get_boot(fat);
307*9558e6acSTreehugger Robot 	fd = fat_get_fd(fat);
308*9558e6acSTreehugger Robot 	clsz = boot->bpbSecPerClust * boot->bpbBytesPerSec;
309*9558e6acSTreehugger Robot 
310*9558e6acSTreehugger Robot 	s = delbuf + startoff;
311*9558e6acSTreehugger Robot 	e = delbuf + clsz;
312*9558e6acSTreehugger Robot 	while (fat_is_valid_cl(fat, startcl)) {
313*9558e6acSTreehugger Robot 		if (startcl == endcl) {
314*9558e6acSTreehugger Robot 			if (notlast)
315*9558e6acSTreehugger Robot 				break;
316*9558e6acSTreehugger Robot 			e = delbuf + endoff;
317*9558e6acSTreehugger Robot 		}
318*9558e6acSTreehugger Robot 		off = (startcl - CLUST_FIRST) * boot->bpbSecPerClust + boot->FirstCluster;
319*9558e6acSTreehugger Robot 
320*9558e6acSTreehugger Robot 		off *= boot->bpbBytesPerSec;
321*9558e6acSTreehugger Robot 		if (lseek(fd, off, SEEK_SET) != off) {
322*9558e6acSTreehugger Robot 			perr("Unable to lseek to %" PRId64, off);
323*9558e6acSTreehugger Robot 			return FSFATAL;
324*9558e6acSTreehugger Robot 		}
325*9558e6acSTreehugger Robot 		if (read(fd, delbuf, clsz) != clsz) {
326*9558e6acSTreehugger Robot 			perr("Unable to read directory");
327*9558e6acSTreehugger Robot 			return FSFATAL;
328*9558e6acSTreehugger Robot 		}
329*9558e6acSTreehugger Robot 		while (s < e) {
330*9558e6acSTreehugger Robot 			*s = SLOT_DELETED;
331*9558e6acSTreehugger Robot 			s += 32;
332*9558e6acSTreehugger Robot 		}
333*9558e6acSTreehugger Robot 		if (lseek(fd, off, SEEK_SET) != off) {
334*9558e6acSTreehugger Robot 			perr("Unable to lseek to %" PRId64, off);
335*9558e6acSTreehugger Robot 			return FSFATAL;
336*9558e6acSTreehugger Robot 		}
337*9558e6acSTreehugger Robot 		if (write(fd, delbuf, clsz) != clsz) {
338*9558e6acSTreehugger Robot 			perr("Unable to write directory");
339*9558e6acSTreehugger Robot 			return FSFATAL;
340*9558e6acSTreehugger Robot 		}
341*9558e6acSTreehugger Robot 		if (startcl == endcl)
342*9558e6acSTreehugger Robot 			break;
343*9558e6acSTreehugger Robot 		startcl = fat_get_cl_next(fat, startcl);
344*9558e6acSTreehugger Robot 		s = delbuf;
345*9558e6acSTreehugger Robot 	}
346*9558e6acSTreehugger Robot 	return FSOK;
347*9558e6acSTreehugger Robot }
348*9558e6acSTreehugger Robot 
349*9558e6acSTreehugger Robot static int
removede(struct fat_descriptor * fat,u_char * start,u_char * end,cl_t startcl,cl_t endcl,cl_t curcl,char * path,int type)350*9558e6acSTreehugger Robot removede(struct fat_descriptor *fat, u_char *start,
351*9558e6acSTreehugger Robot     u_char *end, cl_t startcl, cl_t endcl, cl_t curcl,
352*9558e6acSTreehugger Robot     char *path, int type)
353*9558e6acSTreehugger Robot {
354*9558e6acSTreehugger Robot 	switch (type) {
355*9558e6acSTreehugger Robot 	case 0:
356*9558e6acSTreehugger Robot 		pwarn("Invalid long filename entry for %s\n", path);
357*9558e6acSTreehugger Robot 		break;
358*9558e6acSTreehugger Robot 	case 1:
359*9558e6acSTreehugger Robot 		pwarn("Invalid long filename entry at end of directory %s\n",
360*9558e6acSTreehugger Robot 		    path);
361*9558e6acSTreehugger Robot 		break;
362*9558e6acSTreehugger Robot 	case 2:
363*9558e6acSTreehugger Robot 		pwarn("Invalid long filename entry for volume label\n");
364*9558e6acSTreehugger Robot 		break;
365*9558e6acSTreehugger Robot 	}
366*9558e6acSTreehugger Robot 	if (ask(0, "Remove")) {
367*9558e6acSTreehugger Robot 		if (startcl != curcl) {
368*9558e6acSTreehugger Robot 			if (delete(fat,
369*9558e6acSTreehugger Robot 				   startcl, start - buffer,
370*9558e6acSTreehugger Robot 				   endcl, end - buffer,
371*9558e6acSTreehugger Robot 				   endcl == curcl) == FSFATAL)
372*9558e6acSTreehugger Robot 				return FSFATAL;
373*9558e6acSTreehugger Robot 			start = buffer;
374*9558e6acSTreehugger Robot 		}
375*9558e6acSTreehugger Robot 		/* startcl is < CLUST_FIRST for !FAT32 root */
376*9558e6acSTreehugger Robot 		if ((endcl == curcl) || (startcl < CLUST_FIRST))
377*9558e6acSTreehugger Robot 			for (; start < end; start += 32)
378*9558e6acSTreehugger Robot 				*start = SLOT_DELETED;
379*9558e6acSTreehugger Robot 		return FSDIRMOD;
380*9558e6acSTreehugger Robot 	}
381*9558e6acSTreehugger Robot 	return FSERROR;
382*9558e6acSTreehugger Robot }
383*9558e6acSTreehugger Robot 
384*9558e6acSTreehugger Robot /*
385*9558e6acSTreehugger Robot  * Check an in-memory file entry
386*9558e6acSTreehugger Robot  */
387*9558e6acSTreehugger Robot static int
checksize(struct fat_descriptor * fat,u_char * p,struct dosDirEntry * dir)388*9558e6acSTreehugger Robot checksize(struct fat_descriptor *fat, u_char *p, struct dosDirEntry *dir)
389*9558e6acSTreehugger Robot {
390*9558e6acSTreehugger Robot 	int ret = FSOK;
391*9558e6acSTreehugger Robot 	size_t chainsize;
392*9558e6acSTreehugger Robot 	u_int64_t physicalSize;
393*9558e6acSTreehugger Robot 	struct bootblock *boot;
394*9558e6acSTreehugger Robot 
395*9558e6acSTreehugger Robot 	boot = fat_get_boot(fat);
396*9558e6acSTreehugger Robot 
397*9558e6acSTreehugger Robot 	/*
398*9558e6acSTreehugger Robot 	 * Check size on ordinary files
399*9558e6acSTreehugger Robot 	 */
400*9558e6acSTreehugger Robot 	if (dir->head == CLUST_FREE) {
401*9558e6acSTreehugger Robot 		physicalSize = 0;
402*9558e6acSTreehugger Robot 	} else {
403*9558e6acSTreehugger Robot 		if (!fat_is_valid_cl(fat, dir->head) || !fat_is_cl_head(fat, dir->head)) {
404*9558e6acSTreehugger Robot 			pwarn("Directory entry %s of size %u referencing invalid cluster %u\n",
405*9558e6acSTreehugger Robot 			    fullpath(dir), dir->size, dir->head);
406*9558e6acSTreehugger Robot 			if (ask(1, "Truncate")) {
407*9558e6acSTreehugger Robot 				p[28] = p[29] = p[30] = p[31] = 0;
408*9558e6acSTreehugger Robot 				p[26] = p[27] = 0;
409*9558e6acSTreehugger Robot 				if (boot->ClustMask == CLUST32_MASK)
410*9558e6acSTreehugger Robot 					p[20] = p[21] = 0;
411*9558e6acSTreehugger Robot 				dir->size = 0;
412*9558e6acSTreehugger Robot 				dir->head = CLUST_FREE;
413*9558e6acSTreehugger Robot 				return FSDIRMOD;
414*9558e6acSTreehugger Robot 			} else {
415*9558e6acSTreehugger Robot 				return FSERROR;
416*9558e6acSTreehugger Robot 			}
417*9558e6acSTreehugger Robot 		}
418*9558e6acSTreehugger Robot 		ret = checkchain(fat, dir->head, &chainsize);
419*9558e6acSTreehugger Robot 		/*
420*9558e6acSTreehugger Robot 		 * Upon return, chainsize would hold the chain length
421*9558e6acSTreehugger Robot 		 * that checkchain() was able to validate, but if the user
422*9558e6acSTreehugger Robot 		 * refused the proposed repair, it would be unsafe to
423*9558e6acSTreehugger Robot 		 * proceed with directory entry fix, so bail out in that
424*9558e6acSTreehugger Robot 		 * case.
425*9558e6acSTreehugger Robot 		 */
426*9558e6acSTreehugger Robot 		if (ret == FSERROR) {
427*9558e6acSTreehugger Robot 			return (FSERROR);
428*9558e6acSTreehugger Robot 		}
429*9558e6acSTreehugger Robot 		/*
430*9558e6acSTreehugger Robot 		 * The maximum file size on FAT32 is 4GiB - 1, which
431*9558e6acSTreehugger Robot 		 * will occupy a cluster chain of exactly 4GiB in
432*9558e6acSTreehugger Robot 		 * size.  On 32-bit platforms, since size_t is 32-bit,
433*9558e6acSTreehugger Robot 		 * it would wrap back to 0.
434*9558e6acSTreehugger Robot 		 */
435*9558e6acSTreehugger Robot 		physicalSize = (u_int64_t)chainsize * boot->ClusterSize;
436*9558e6acSTreehugger Robot 	}
437*9558e6acSTreehugger Robot 	if (physicalSize < dir->size) {
438*9558e6acSTreehugger Robot 		pwarn("size of %s is %u, should at most be %ju\n",
439*9558e6acSTreehugger Robot 		      fullpath(dir), dir->size, (uintmax_t)physicalSize);
440*9558e6acSTreehugger Robot 		if (ask(1, "Truncate")) {
441*9558e6acSTreehugger Robot 			dir->size = physicalSize;
442*9558e6acSTreehugger Robot 			p[28] = (u_char)physicalSize;
443*9558e6acSTreehugger Robot 			p[29] = (u_char)(physicalSize >> 8);
444*9558e6acSTreehugger Robot 			p[30] = (u_char)(physicalSize >> 16);
445*9558e6acSTreehugger Robot 			p[31] = (u_char)(physicalSize >> 24);
446*9558e6acSTreehugger Robot 			return FSDIRMOD;
447*9558e6acSTreehugger Robot 		} else
448*9558e6acSTreehugger Robot 			return FSERROR;
449*9558e6acSTreehugger Robot 	} else if (physicalSize - dir->size >= boot->ClusterSize) {
450*9558e6acSTreehugger Robot 		pwarn("%s has too many clusters allocated\n",
451*9558e6acSTreehugger Robot 		      fullpath(dir));
452*9558e6acSTreehugger Robot 		if (ask(1, "Drop superfluous clusters")) {
453*9558e6acSTreehugger Robot 			cl_t cl;
454*9558e6acSTreehugger Robot 			u_int32_t sz, len;
455*9558e6acSTreehugger Robot 
456*9558e6acSTreehugger Robot 			for (cl = dir->head, len = sz = 0;
457*9558e6acSTreehugger Robot 			    (sz += boot->ClusterSize) < dir->size; len++)
458*9558e6acSTreehugger Robot 				cl = fat_get_cl_next(fat, cl);
459*9558e6acSTreehugger Robot 			clearchain(fat, fat_get_cl_next(fat, cl));
460*9558e6acSTreehugger Robot 			ret = fat_set_cl_next(fat, cl, CLUST_EOF);
461*9558e6acSTreehugger Robot 			return (FSFATMOD | ret);
462*9558e6acSTreehugger Robot 		} else
463*9558e6acSTreehugger Robot 			return FSERROR;
464*9558e6acSTreehugger Robot 	}
465*9558e6acSTreehugger Robot 	return FSOK;
466*9558e6acSTreehugger Robot }
467*9558e6acSTreehugger Robot 
468*9558e6acSTreehugger Robot static const u_char dot_name[11]    = ".          ";
469*9558e6acSTreehugger Robot static const u_char dotdot_name[11] = "..         ";
470*9558e6acSTreehugger Robot 
471*9558e6acSTreehugger Robot /*
472*9558e6acSTreehugger Robot  * Basic sanity check if the subdirectory have good '.' and '..' entries,
473*9558e6acSTreehugger Robot  * and they are directory entries.  Further sanity checks are performed
474*9558e6acSTreehugger Robot  * when we traverse into it.
475*9558e6acSTreehugger Robot  */
476*9558e6acSTreehugger Robot static int
check_subdirectory(struct fat_descriptor * fat,struct dosDirEntry * dir)477*9558e6acSTreehugger Robot check_subdirectory(struct fat_descriptor *fat, struct dosDirEntry *dir)
478*9558e6acSTreehugger Robot {
479*9558e6acSTreehugger Robot 	u_char *buf, *cp;
480*9558e6acSTreehugger Robot 	off_t off;
481*9558e6acSTreehugger Robot 	cl_t cl;
482*9558e6acSTreehugger Robot 	int retval = FSOK;
483*9558e6acSTreehugger Robot 	int fd;
484*9558e6acSTreehugger Robot 	struct bootblock *boot;
485*9558e6acSTreehugger Robot 
486*9558e6acSTreehugger Robot 	boot = fat_get_boot(fat);
487*9558e6acSTreehugger Robot 	fd = fat_get_fd(fat);
488*9558e6acSTreehugger Robot 
489*9558e6acSTreehugger Robot 	cl = dir->head;
490*9558e6acSTreehugger Robot 	if (dir->parent && !fat_is_valid_cl(fat, cl)) {
491*9558e6acSTreehugger Robot 		return FSERROR;
492*9558e6acSTreehugger Robot 	}
493*9558e6acSTreehugger Robot 
494*9558e6acSTreehugger Robot 	if (!(boot->flags & FAT32) && !dir->parent) {
495*9558e6acSTreehugger Robot 		off = boot->bpbResSectors + boot->bpbFATs *
496*9558e6acSTreehugger Robot 			boot->FATsecs;
497*9558e6acSTreehugger Robot 	} else {
498*9558e6acSTreehugger Robot 		off = (cl - CLUST_FIRST) * boot->bpbSecPerClust + boot->FirstCluster;
499*9558e6acSTreehugger Robot 	}
500*9558e6acSTreehugger Robot 
501*9558e6acSTreehugger Robot 	/*
502*9558e6acSTreehugger Robot 	 * We only need to check the first two entries of the directory,
503*9558e6acSTreehugger Robot 	 * which is found in the first sector of the directory entry,
504*9558e6acSTreehugger Robot 	 * so read in only the first sector.
505*9558e6acSTreehugger Robot 	 */
506*9558e6acSTreehugger Robot 	buf = malloc(boot->bpbBytesPerSec);
507*9558e6acSTreehugger Robot 	if (buf == NULL) {
508*9558e6acSTreehugger Robot 		perr("No space for directory buffer (%u)",
509*9558e6acSTreehugger Robot 		    boot->bpbBytesPerSec);
510*9558e6acSTreehugger Robot 		return FSFATAL;
511*9558e6acSTreehugger Robot 	}
512*9558e6acSTreehugger Robot 
513*9558e6acSTreehugger Robot 	off *= boot->bpbBytesPerSec;
514*9558e6acSTreehugger Robot 	if (lseek(fd, off, SEEK_SET) != off ||
515*9558e6acSTreehugger Robot 	    read(fd, buf, boot->bpbBytesPerSec) != (ssize_t)boot->bpbBytesPerSec) {
516*9558e6acSTreehugger Robot 		perr("Unable to read directory");
517*9558e6acSTreehugger Robot 		free(buf);
518*9558e6acSTreehugger Robot 		return FSFATAL;
519*9558e6acSTreehugger Robot 	}
520*9558e6acSTreehugger Robot 
521*9558e6acSTreehugger Robot 	/*
522*9558e6acSTreehugger Robot 	 * Both `.' and `..' must be present and be the first two entries
523*9558e6acSTreehugger Robot 	 * and be ATTR_DIRECTORY of a valid subdirectory.
524*9558e6acSTreehugger Robot 	 */
525*9558e6acSTreehugger Robot 	cp = buf;
526*9558e6acSTreehugger Robot 	if (memcmp(cp, dot_name, sizeof(dot_name)) != 0 ||
527*9558e6acSTreehugger Robot 	    (cp[11] & ATTR_DIRECTORY) != ATTR_DIRECTORY) {
528*9558e6acSTreehugger Robot 		pwarn("%s: Incorrect `.' for %s.\n", __func__, dir->name);
529*9558e6acSTreehugger Robot 		retval |= FSERROR;
530*9558e6acSTreehugger Robot 	}
531*9558e6acSTreehugger Robot 	cp += 32;
532*9558e6acSTreehugger Robot 	if (memcmp(cp, dotdot_name, sizeof(dotdot_name)) != 0 ||
533*9558e6acSTreehugger Robot 	    (cp[11] & ATTR_DIRECTORY) != ATTR_DIRECTORY) {
534*9558e6acSTreehugger Robot 		pwarn("%s: Incorrect `..' for %s. \n", __func__, dir->name);
535*9558e6acSTreehugger Robot 		retval |= FSERROR;
536*9558e6acSTreehugger Robot 	}
537*9558e6acSTreehugger Robot 
538*9558e6acSTreehugger Robot 	free(buf);
539*9558e6acSTreehugger Robot 	return retval;
540*9558e6acSTreehugger Robot }
541*9558e6acSTreehugger Robot 
542*9558e6acSTreehugger Robot /*
543*9558e6acSTreehugger Robot  * Read a directory and
544*9558e6acSTreehugger Robot  *   - resolve long name records
545*9558e6acSTreehugger Robot  *   - enter file and directory records into the parent's list
546*9558e6acSTreehugger Robot  *   - push directories onto the todo-stack
547*9558e6acSTreehugger Robot  */
548*9558e6acSTreehugger Robot static int
readDosDirSection(struct fat_descriptor * fat,struct dosDirEntry * dir)549*9558e6acSTreehugger Robot readDosDirSection(struct fat_descriptor *fat, struct dosDirEntry *dir)
550*9558e6acSTreehugger Robot {
551*9558e6acSTreehugger Robot 	struct bootblock *boot;
552*9558e6acSTreehugger Robot 	struct dosDirEntry dirent, *d;
553*9558e6acSTreehugger Robot 	u_char *p, *vallfn, *invlfn, *empty;
554*9558e6acSTreehugger Robot 	off_t off;
555*9558e6acSTreehugger Robot 	int fd, i, j, k, iosize, entries;
556*9558e6acSTreehugger Robot 	bool is_legacyroot;
557*9558e6acSTreehugger Robot 	cl_t cl, valcl = ~0, invcl = ~0, empcl = ~0;
558*9558e6acSTreehugger Robot 	char *t;
559*9558e6acSTreehugger Robot 	u_int lidx = 0;
560*9558e6acSTreehugger Robot 	int shortSum;
561*9558e6acSTreehugger Robot 	int mod = FSOK;
562*9558e6acSTreehugger Robot 	size_t dirclusters;
563*9558e6acSTreehugger Robot #define	THISMOD	0x8000			/* Only used within this routine */
564*9558e6acSTreehugger Robot 
565*9558e6acSTreehugger Robot 	boot = fat_get_boot(fat);
566*9558e6acSTreehugger Robot 	fd = fat_get_fd(fat);
567*9558e6acSTreehugger Robot 
568*9558e6acSTreehugger Robot 	cl = dir->head;
569*9558e6acSTreehugger Robot 	if (dir->parent && (!fat_is_valid_cl(fat, cl))) {
570*9558e6acSTreehugger Robot 		/*
571*9558e6acSTreehugger Robot 		 * Already handled somewhere else.
572*9558e6acSTreehugger Robot 		 */
573*9558e6acSTreehugger Robot 		return FSOK;
574*9558e6acSTreehugger Robot 	}
575*9558e6acSTreehugger Robot 	shortSum = -1;
576*9558e6acSTreehugger Robot 	vallfn = invlfn = empty = NULL;
577*9558e6acSTreehugger Robot 
578*9558e6acSTreehugger Robot 	/*
579*9558e6acSTreehugger Robot 	 * If we are checking the legacy root (for FAT12/FAT16),
580*9558e6acSTreehugger Robot 	 * we will operate on the whole directory; otherwise, we
581*9558e6acSTreehugger Robot 	 * will operate on one cluster at a time, and also take
582*9558e6acSTreehugger Robot 	 * this opportunity to examine the chain.
583*9558e6acSTreehugger Robot 	 *
584*9558e6acSTreehugger Robot 	 * Derive how many entries we are going to encounter from
585*9558e6acSTreehugger Robot 	 * the I/O size.
586*9558e6acSTreehugger Robot 	 */
587*9558e6acSTreehugger Robot 	is_legacyroot = (dir->parent == NULL && !(boot->flags & FAT32));
588*9558e6acSTreehugger Robot 	if (is_legacyroot) {
589*9558e6acSTreehugger Robot 		iosize = boot->bpbRootDirEnts * 32;
590*9558e6acSTreehugger Robot 		entries = boot->bpbRootDirEnts;
591*9558e6acSTreehugger Robot 	} else {
592*9558e6acSTreehugger Robot 		iosize = boot->bpbSecPerClust * boot->bpbBytesPerSec;
593*9558e6acSTreehugger Robot 		entries = iosize / 32;
594*9558e6acSTreehugger Robot 		mod |= checkchain(fat, dir->head, &dirclusters);
595*9558e6acSTreehugger Robot 	}
596*9558e6acSTreehugger Robot 
597*9558e6acSTreehugger Robot 	do {
598*9558e6acSTreehugger Robot 		if (is_legacyroot) {
599*9558e6acSTreehugger Robot 			/*
600*9558e6acSTreehugger Robot 			 * Special case for FAT12/FAT16 root -- read
601*9558e6acSTreehugger Robot 			 * in the whole root directory.
602*9558e6acSTreehugger Robot 			 */
603*9558e6acSTreehugger Robot 			off = boot->bpbResSectors + boot->bpbFATs *
604*9558e6acSTreehugger Robot 			    boot->FATsecs;
605*9558e6acSTreehugger Robot 		} else {
606*9558e6acSTreehugger Robot 			/*
607*9558e6acSTreehugger Robot 			 * Otherwise, read in a cluster of the
608*9558e6acSTreehugger Robot 			 * directory.
609*9558e6acSTreehugger Robot 			 */
610*9558e6acSTreehugger Robot 			off = (cl - CLUST_FIRST) * boot->bpbSecPerClust + boot->FirstCluster;
611*9558e6acSTreehugger Robot 		}
612*9558e6acSTreehugger Robot 
613*9558e6acSTreehugger Robot 		off *= boot->bpbBytesPerSec;
614*9558e6acSTreehugger Robot 		if (lseek(fd, off, SEEK_SET) != off ||
615*9558e6acSTreehugger Robot 		    read(fd, buffer, iosize) != iosize) {
616*9558e6acSTreehugger Robot 			perr("Unable to read directory");
617*9558e6acSTreehugger Robot 			return FSFATAL;
618*9558e6acSTreehugger Robot 		}
619*9558e6acSTreehugger Robot 
620*9558e6acSTreehugger Robot 		for (p = buffer, i = 0; i < entries; i++, p += 32) {
621*9558e6acSTreehugger Robot 			if (dir->fsckflags & DIREMPWARN) {
622*9558e6acSTreehugger Robot 				*p = SLOT_EMPTY;
623*9558e6acSTreehugger Robot 				continue;
624*9558e6acSTreehugger Robot 			}
625*9558e6acSTreehugger Robot 
626*9558e6acSTreehugger Robot 			if (*p == SLOT_EMPTY || *p == SLOT_DELETED) {
627*9558e6acSTreehugger Robot 				if (*p == SLOT_EMPTY) {
628*9558e6acSTreehugger Robot 					dir->fsckflags |= DIREMPTY;
629*9558e6acSTreehugger Robot 					empty = p;
630*9558e6acSTreehugger Robot 					empcl = cl;
631*9558e6acSTreehugger Robot 				}
632*9558e6acSTreehugger Robot 				continue;
633*9558e6acSTreehugger Robot 			}
634*9558e6acSTreehugger Robot 
635*9558e6acSTreehugger Robot 			if (dir->fsckflags & DIREMPTY) {
636*9558e6acSTreehugger Robot 				if (!(dir->fsckflags & DIREMPWARN)) {
637*9558e6acSTreehugger Robot 					pwarn("%s has entries after end of directory\n",
638*9558e6acSTreehugger Robot 					      fullpath(dir));
639*9558e6acSTreehugger Robot 					if (ask(1, "Extend")) {
640*9558e6acSTreehugger Robot 						u_char *q;
641*9558e6acSTreehugger Robot 
642*9558e6acSTreehugger Robot 						dir->fsckflags &= ~DIREMPTY;
643*9558e6acSTreehugger Robot 						if (delete(fat,
644*9558e6acSTreehugger Robot 							   empcl, empty - buffer,
645*9558e6acSTreehugger Robot 							   cl, p - buffer, 1) == FSFATAL)
646*9558e6acSTreehugger Robot 							return FSFATAL;
647*9558e6acSTreehugger Robot 						q = ((empcl == cl) ? empty : buffer);
648*9558e6acSTreehugger Robot 						assert(q != NULL);
649*9558e6acSTreehugger Robot 						for (; q < p; q += 32)
650*9558e6acSTreehugger Robot 							*q = SLOT_DELETED;
651*9558e6acSTreehugger Robot 						mod |= THISMOD|FSDIRMOD;
652*9558e6acSTreehugger Robot 					} else if (ask(0, "Truncate"))
653*9558e6acSTreehugger Robot 						dir->fsckflags |= DIREMPWARN;
654*9558e6acSTreehugger Robot 				}
655*9558e6acSTreehugger Robot 				if (dir->fsckflags & DIREMPWARN) {
656*9558e6acSTreehugger Robot 					*p = SLOT_DELETED;
657*9558e6acSTreehugger Robot 					mod |= THISMOD|FSDIRMOD;
658*9558e6acSTreehugger Robot 					continue;
659*9558e6acSTreehugger Robot 				} else if (dir->fsckflags & DIREMPTY)
660*9558e6acSTreehugger Robot 					mod |= FSERROR;
661*9558e6acSTreehugger Robot 				empty = NULL;
662*9558e6acSTreehugger Robot 			}
663*9558e6acSTreehugger Robot 
664*9558e6acSTreehugger Robot 			if (p[11] == ATTR_WIN95) {
665*9558e6acSTreehugger Robot 				if (*p & LRFIRST) {
666*9558e6acSTreehugger Robot 					if (shortSum != -1) {
667*9558e6acSTreehugger Robot 						if (!invlfn) {
668*9558e6acSTreehugger Robot 							invlfn = vallfn;
669*9558e6acSTreehugger Robot 							invcl = valcl;
670*9558e6acSTreehugger Robot 						}
671*9558e6acSTreehugger Robot 					}
672*9558e6acSTreehugger Robot 					memset(longName, 0, sizeof longName);
673*9558e6acSTreehugger Robot 					shortSum = p[13];
674*9558e6acSTreehugger Robot 					vallfn = p;
675*9558e6acSTreehugger Robot 					valcl = cl;
676*9558e6acSTreehugger Robot 				} else if (shortSum != p[13]
677*9558e6acSTreehugger Robot 					   || lidx != (*p & LRNOMASK)) {
678*9558e6acSTreehugger Robot 					if (!invlfn) {
679*9558e6acSTreehugger Robot 						invlfn = vallfn;
680*9558e6acSTreehugger Robot 						invcl = valcl;
681*9558e6acSTreehugger Robot 					}
682*9558e6acSTreehugger Robot 					if (!invlfn) {
683*9558e6acSTreehugger Robot 						invlfn = p;
684*9558e6acSTreehugger Robot 						invcl = cl;
685*9558e6acSTreehugger Robot 					}
686*9558e6acSTreehugger Robot 					vallfn = NULL;
687*9558e6acSTreehugger Robot 				}
688*9558e6acSTreehugger Robot 				lidx = *p & LRNOMASK;
689*9558e6acSTreehugger Robot 				if (lidx == 0) {
690*9558e6acSTreehugger Robot 					pwarn("invalid long name\n");
691*9558e6acSTreehugger Robot 					if (!invlfn) {
692*9558e6acSTreehugger Robot 						invlfn = vallfn;
693*9558e6acSTreehugger Robot 						invcl = valcl;
694*9558e6acSTreehugger Robot 					}
695*9558e6acSTreehugger Robot 					vallfn = NULL;
696*9558e6acSTreehugger Robot 					continue;
697*9558e6acSTreehugger Robot 				}
698*9558e6acSTreehugger Robot 				t = longName + --lidx * 13;
699*9558e6acSTreehugger Robot 				for (k = 1; k < 11 && t < longName +
700*9558e6acSTreehugger Robot 				    sizeof(longName); k += 2) {
701*9558e6acSTreehugger Robot 					if (!p[k] && !p[k + 1])
702*9558e6acSTreehugger Robot 						break;
703*9558e6acSTreehugger Robot 					*t++ = p[k];
704*9558e6acSTreehugger Robot 					/*
705*9558e6acSTreehugger Robot 					 * Warn about those unusable chars in msdosfs here?	XXX
706*9558e6acSTreehugger Robot 					 */
707*9558e6acSTreehugger Robot 					if (p[k + 1])
708*9558e6acSTreehugger Robot 						t[-1] = '?';
709*9558e6acSTreehugger Robot 				}
710*9558e6acSTreehugger Robot 				if (k >= 11)
711*9558e6acSTreehugger Robot 					for (k = 14; k < 26 && t < longName + sizeof(longName); k += 2) {
712*9558e6acSTreehugger Robot 						if (!p[k] && !p[k + 1])
713*9558e6acSTreehugger Robot 							break;
714*9558e6acSTreehugger Robot 						*t++ = p[k];
715*9558e6acSTreehugger Robot 						if (p[k + 1])
716*9558e6acSTreehugger Robot 							t[-1] = '?';
717*9558e6acSTreehugger Robot 					}
718*9558e6acSTreehugger Robot 				if (k >= 26)
719*9558e6acSTreehugger Robot 					for (k = 28; k < 32 && t < longName + sizeof(longName); k += 2) {
720*9558e6acSTreehugger Robot 						if (!p[k] && !p[k + 1])
721*9558e6acSTreehugger Robot 							break;
722*9558e6acSTreehugger Robot 						*t++ = p[k];
723*9558e6acSTreehugger Robot 						if (p[k + 1])
724*9558e6acSTreehugger Robot 							t[-1] = '?';
725*9558e6acSTreehugger Robot 					}
726*9558e6acSTreehugger Robot 				if (t >= longName + sizeof(longName)) {
727*9558e6acSTreehugger Robot 					pwarn("long filename too long\n");
728*9558e6acSTreehugger Robot 					if (!invlfn) {
729*9558e6acSTreehugger Robot 						invlfn = vallfn;
730*9558e6acSTreehugger Robot 						invcl = valcl;
731*9558e6acSTreehugger Robot 					}
732*9558e6acSTreehugger Robot 					vallfn = NULL;
733*9558e6acSTreehugger Robot 				}
734*9558e6acSTreehugger Robot 				if (p[26] | (p[27] << 8)) {
735*9558e6acSTreehugger Robot 					pwarn("long filename record cluster start != 0\n");
736*9558e6acSTreehugger Robot 					if (!invlfn) {
737*9558e6acSTreehugger Robot 						invlfn = vallfn;
738*9558e6acSTreehugger Robot 						invcl = cl;
739*9558e6acSTreehugger Robot 					}
740*9558e6acSTreehugger Robot 					vallfn = NULL;
741*9558e6acSTreehugger Robot 				}
742*9558e6acSTreehugger Robot 				continue;	/* long records don't carry further
743*9558e6acSTreehugger Robot 						 * information */
744*9558e6acSTreehugger Robot 			}
745*9558e6acSTreehugger Robot 
746*9558e6acSTreehugger Robot 			/*
747*9558e6acSTreehugger Robot 			 * This is a standard msdosfs directory entry.
748*9558e6acSTreehugger Robot 			 */
749*9558e6acSTreehugger Robot 			memset(&dirent, 0, sizeof dirent);
750*9558e6acSTreehugger Robot 
751*9558e6acSTreehugger Robot 			/*
752*9558e6acSTreehugger Robot 			 * it's a short name record, but we need to know
753*9558e6acSTreehugger Robot 			 * more, so get the flags first.
754*9558e6acSTreehugger Robot 			 */
755*9558e6acSTreehugger Robot 			dirent.flags = p[11];
756*9558e6acSTreehugger Robot 
757*9558e6acSTreehugger Robot 			/*
758*9558e6acSTreehugger Robot 			 * Translate from 850 to ISO here		XXX
759*9558e6acSTreehugger Robot 			 */
760*9558e6acSTreehugger Robot 			for (j = 0; j < 8; j++)
761*9558e6acSTreehugger Robot 				dirent.name[j] = p[j];
762*9558e6acSTreehugger Robot 			dirent.name[8] = '\0';
763*9558e6acSTreehugger Robot 			for (k = 7; k >= 0 && dirent.name[k] == ' '; k--)
764*9558e6acSTreehugger Robot 				dirent.name[k] = '\0';
765*9558e6acSTreehugger Robot 			if (k < 0 || dirent.name[k] != '\0')
766*9558e6acSTreehugger Robot 				k++;
767*9558e6acSTreehugger Robot 			if (dirent.name[0] == SLOT_E5)
768*9558e6acSTreehugger Robot 				dirent.name[0] = 0xe5;
769*9558e6acSTreehugger Robot 
770*9558e6acSTreehugger Robot 			if (dirent.flags & ATTR_VOLUME) {
771*9558e6acSTreehugger Robot 				if (vallfn || invlfn) {
772*9558e6acSTreehugger Robot 					mod |= removede(fat,
773*9558e6acSTreehugger Robot 							invlfn ? invlfn : vallfn, p,
774*9558e6acSTreehugger Robot 							invlfn ? invcl : valcl, -1, 0,
775*9558e6acSTreehugger Robot 							fullpath(dir), 2);
776*9558e6acSTreehugger Robot 					vallfn = NULL;
777*9558e6acSTreehugger Robot 					invlfn = NULL;
778*9558e6acSTreehugger Robot 				}
779*9558e6acSTreehugger Robot 				continue;
780*9558e6acSTreehugger Robot 			}
781*9558e6acSTreehugger Robot 
782*9558e6acSTreehugger Robot 			if (p[8] != ' ')
783*9558e6acSTreehugger Robot 				dirent.name[k++] = '.';
784*9558e6acSTreehugger Robot 			for (j = 0; j < 3; j++)
785*9558e6acSTreehugger Robot 				dirent.name[k++] = p[j+8];
786*9558e6acSTreehugger Robot 			dirent.name[k] = '\0';
787*9558e6acSTreehugger Robot 			for (k--; k >= 0 && dirent.name[k] == ' '; k--)
788*9558e6acSTreehugger Robot 				dirent.name[k] = '\0';
789*9558e6acSTreehugger Robot 
790*9558e6acSTreehugger Robot 			if (vallfn && shortSum != calcShortSum(p)) {
791*9558e6acSTreehugger Robot 				if (!invlfn) {
792*9558e6acSTreehugger Robot 					invlfn = vallfn;
793*9558e6acSTreehugger Robot 					invcl = valcl;
794*9558e6acSTreehugger Robot 				}
795*9558e6acSTreehugger Robot 				vallfn = NULL;
796*9558e6acSTreehugger Robot 			}
797*9558e6acSTreehugger Robot 			dirent.head = p[26] | (p[27] << 8);
798*9558e6acSTreehugger Robot 			if (boot->ClustMask == CLUST32_MASK)
799*9558e6acSTreehugger Robot 				dirent.head |= (p[20] << 16) | (p[21] << 24);
800*9558e6acSTreehugger Robot 			dirent.size = p[28] | (p[29] << 8) | (p[30] << 16) | (p[31] << 24);
801*9558e6acSTreehugger Robot 			if (vallfn) {
802*9558e6acSTreehugger Robot 				strlcpy(dirent.lname, longName,
803*9558e6acSTreehugger Robot 				    sizeof(dirent.lname));
804*9558e6acSTreehugger Robot 				longName[0] = '\0';
805*9558e6acSTreehugger Robot 				shortSum = -1;
806*9558e6acSTreehugger Robot 			}
807*9558e6acSTreehugger Robot 
808*9558e6acSTreehugger Robot 			dirent.parent = dir;
809*9558e6acSTreehugger Robot 			dirent.next = dir->child;
810*9558e6acSTreehugger Robot 
811*9558e6acSTreehugger Robot 			if (invlfn) {
812*9558e6acSTreehugger Robot 				mod |= k = removede(fat,
813*9558e6acSTreehugger Robot 						    invlfn, vallfn ? vallfn : p,
814*9558e6acSTreehugger Robot 						    invcl, vallfn ? valcl : cl, cl,
815*9558e6acSTreehugger Robot 						    fullpath(&dirent), 0);
816*9558e6acSTreehugger Robot 				if (mod & FSFATAL)
817*9558e6acSTreehugger Robot 					return FSFATAL;
818*9558e6acSTreehugger Robot 				if (vallfn
819*9558e6acSTreehugger Robot 				    ? (valcl == cl && vallfn != buffer)
820*9558e6acSTreehugger Robot 				    : p != buffer)
821*9558e6acSTreehugger Robot 					if (k & FSDIRMOD)
822*9558e6acSTreehugger Robot 						mod |= THISMOD;
823*9558e6acSTreehugger Robot 			}
824*9558e6acSTreehugger Robot 
825*9558e6acSTreehugger Robot 			vallfn = NULL; /* not used any longer */
826*9558e6acSTreehugger Robot 			invlfn = NULL;
827*9558e6acSTreehugger Robot 
828*9558e6acSTreehugger Robot 			/*
829*9558e6acSTreehugger Robot 			 * Check if the directory entry is sane.
830*9558e6acSTreehugger Robot 			 *
831*9558e6acSTreehugger Robot 			 * '.' and '..' are skipped, their sanity is
832*9558e6acSTreehugger Robot 			 * checked somewhere else.
833*9558e6acSTreehugger Robot 			 *
834*9558e6acSTreehugger Robot 			 * For everything else, check if we have a new,
835*9558e6acSTreehugger Robot 			 * valid cluster chain (beginning of a file or
836*9558e6acSTreehugger Robot 			 * directory that was never previously claimed
837*9558e6acSTreehugger Robot 			 * by another file) when it's a non-empty file
838*9558e6acSTreehugger Robot 			 * or a directory. The sanity of the cluster
839*9558e6acSTreehugger Robot 			 * chain is checked at a later time when we
840*9558e6acSTreehugger Robot 			 * traverse into the directory, or examine the
841*9558e6acSTreehugger Robot 			 * file's directory entry.
842*9558e6acSTreehugger Robot 			 *
843*9558e6acSTreehugger Robot 			 * The only possible fix is to delete the entry
844*9558e6acSTreehugger Robot 			 * if it's a directory; for file, we have to
845*9558e6acSTreehugger Robot 			 * truncate the size to 0.
846*9558e6acSTreehugger Robot 			 */
847*9558e6acSTreehugger Robot 			if (!(dirent.flags & ATTR_DIRECTORY) ||
848*9558e6acSTreehugger Robot 			    (strcmp(dirent.name, ".") != 0 &&
849*9558e6acSTreehugger Robot 			    strcmp(dirent.name, "..") != 0)) {
850*9558e6acSTreehugger Robot 				if ((dirent.size != 0 || (dirent.flags & ATTR_DIRECTORY)) &&
851*9558e6acSTreehugger Robot 				    ((!fat_is_valid_cl(fat, dirent.head) ||
852*9558e6acSTreehugger Robot 				    !fat_is_cl_head(fat, dirent.head)))) {
853*9558e6acSTreehugger Robot 					if (!fat_is_valid_cl(fat, dirent.head)) {
854*9558e6acSTreehugger Robot 						pwarn("%s starts with cluster out of range(%u)\n",
855*9558e6acSTreehugger Robot 						    fullpath(&dirent),
856*9558e6acSTreehugger Robot 						    dirent.head);
857*9558e6acSTreehugger Robot 					} else {
858*9558e6acSTreehugger Robot 						pwarn("%s doesn't start a new cluster chain\n",
859*9558e6acSTreehugger Robot 						    fullpath(&dirent));
860*9558e6acSTreehugger Robot 					}
861*9558e6acSTreehugger Robot 
862*9558e6acSTreehugger Robot 					if (dirent.flags & ATTR_DIRECTORY) {
863*9558e6acSTreehugger Robot 						if (ask(0, "Remove")) {
864*9558e6acSTreehugger Robot 							*p = SLOT_DELETED;
865*9558e6acSTreehugger Robot 							mod |= THISMOD|FSDIRMOD;
866*9558e6acSTreehugger Robot 						} else
867*9558e6acSTreehugger Robot 							mod |= FSERROR;
868*9558e6acSTreehugger Robot 						continue;
869*9558e6acSTreehugger Robot 					} else {
870*9558e6acSTreehugger Robot 						if (ask(1, "Truncate")) {
871*9558e6acSTreehugger Robot 							p[28] = p[29] = p[30] = p[31] = 0;
872*9558e6acSTreehugger Robot 							p[26] = p[27] = 0;
873*9558e6acSTreehugger Robot 							if (boot->ClustMask == CLUST32_MASK)
874*9558e6acSTreehugger Robot 								p[20] = p[21] = 0;
875*9558e6acSTreehugger Robot 							dirent.size = 0;
876*9558e6acSTreehugger Robot 							dirent.head = 0;
877*9558e6acSTreehugger Robot 							mod |= THISMOD|FSDIRMOD;
878*9558e6acSTreehugger Robot 						} else
879*9558e6acSTreehugger Robot 							mod |= FSERROR;
880*9558e6acSTreehugger Robot 					}
881*9558e6acSTreehugger Robot 				}
882*9558e6acSTreehugger Robot 			}
883*9558e6acSTreehugger Robot 			if (dirent.flags & ATTR_DIRECTORY) {
884*9558e6acSTreehugger Robot 				/*
885*9558e6acSTreehugger Robot 				 * gather more info for directories
886*9558e6acSTreehugger Robot 				 */
887*9558e6acSTreehugger Robot 				struct dirTodoNode *n;
888*9558e6acSTreehugger Robot 
889*9558e6acSTreehugger Robot 				if (dirent.size) {
890*9558e6acSTreehugger Robot 					pwarn("Directory %s has size != 0\n",
891*9558e6acSTreehugger Robot 					      fullpath(&dirent));
892*9558e6acSTreehugger Robot 					if (ask(1, "Correct")) {
893*9558e6acSTreehugger Robot 						p[28] = p[29] = p[30] = p[31] = 0;
894*9558e6acSTreehugger Robot 						dirent.size = 0;
895*9558e6acSTreehugger Robot 						mod |= THISMOD|FSDIRMOD;
896*9558e6acSTreehugger Robot 					} else
897*9558e6acSTreehugger Robot 						mod |= FSERROR;
898*9558e6acSTreehugger Robot 				}
899*9558e6acSTreehugger Robot 				/*
900*9558e6acSTreehugger Robot 				 * handle `.' and `..' specially
901*9558e6acSTreehugger Robot 				 */
902*9558e6acSTreehugger Robot 				if (strcmp(dirent.name, ".") == 0) {
903*9558e6acSTreehugger Robot 					if (dirent.head != dir->head) {
904*9558e6acSTreehugger Robot 						pwarn("`.' entry in %s has incorrect start cluster\n",
905*9558e6acSTreehugger Robot 						      fullpath(dir));
906*9558e6acSTreehugger Robot 						if (ask(1, "Correct")) {
907*9558e6acSTreehugger Robot 							dirent.head = dir->head;
908*9558e6acSTreehugger Robot 							p[26] = (u_char)dirent.head;
909*9558e6acSTreehugger Robot 							p[27] = (u_char)(dirent.head >> 8);
910*9558e6acSTreehugger Robot 							if (boot->ClustMask == CLUST32_MASK) {
911*9558e6acSTreehugger Robot 								p[20] = (u_char)(dirent.head >> 16);
912*9558e6acSTreehugger Robot 								p[21] = (u_char)(dirent.head >> 24);
913*9558e6acSTreehugger Robot 							}
914*9558e6acSTreehugger Robot 							mod |= THISMOD|FSDIRMOD;
915*9558e6acSTreehugger Robot 						} else
916*9558e6acSTreehugger Robot 							mod |= FSERROR;
917*9558e6acSTreehugger Robot 					}
918*9558e6acSTreehugger Robot 					continue;
919*9558e6acSTreehugger Robot 				} else if (strcmp(dirent.name, "..") == 0) {
920*9558e6acSTreehugger Robot 					if (dir->parent) {		/* XXX */
921*9558e6acSTreehugger Robot 						if (!dir->parent->parent) {
922*9558e6acSTreehugger Robot 							if (dirent.head) {
923*9558e6acSTreehugger Robot 								pwarn("`..' entry in %s has non-zero start cluster\n",
924*9558e6acSTreehugger Robot 								      fullpath(dir));
925*9558e6acSTreehugger Robot 								if (ask(1, "Correct")) {
926*9558e6acSTreehugger Robot 									dirent.head = 0;
927*9558e6acSTreehugger Robot 									p[26] = p[27] = 0;
928*9558e6acSTreehugger Robot 									if (boot->ClustMask == CLUST32_MASK)
929*9558e6acSTreehugger Robot 										p[20] = p[21] = 0;
930*9558e6acSTreehugger Robot 									mod |= THISMOD|FSDIRMOD;
931*9558e6acSTreehugger Robot 								} else
932*9558e6acSTreehugger Robot 									mod |= FSERROR;
933*9558e6acSTreehugger Robot 							}
934*9558e6acSTreehugger Robot 						} else if (dirent.head != dir->parent->head) {
935*9558e6acSTreehugger Robot 							pwarn("`..' entry in %s has incorrect start cluster\n",
936*9558e6acSTreehugger Robot 							      fullpath(dir));
937*9558e6acSTreehugger Robot 							if (ask(1, "Correct")) {
938*9558e6acSTreehugger Robot 								dirent.head = dir->parent->head;
939*9558e6acSTreehugger Robot 								p[26] = (u_char)dirent.head;
940*9558e6acSTreehugger Robot 								p[27] = (u_char)(dirent.head >> 8);
941*9558e6acSTreehugger Robot 								if (boot->ClustMask == CLUST32_MASK) {
942*9558e6acSTreehugger Robot 									p[20] = (u_char)(dirent.head >> 16);
943*9558e6acSTreehugger Robot 									p[21] = (u_char)(dirent.head >> 24);
944*9558e6acSTreehugger Robot 								}
945*9558e6acSTreehugger Robot 								mod |= THISMOD|FSDIRMOD;
946*9558e6acSTreehugger Robot 							} else
947*9558e6acSTreehugger Robot 								mod |= FSERROR;
948*9558e6acSTreehugger Robot 						}
949*9558e6acSTreehugger Robot 					}
950*9558e6acSTreehugger Robot 					continue;
951*9558e6acSTreehugger Robot 				} else {
952*9558e6acSTreehugger Robot 					/*
953*9558e6acSTreehugger Robot 					 * Only one directory entry can point
954*9558e6acSTreehugger Robot 					 * to dir->head, it's '.'.
955*9558e6acSTreehugger Robot 					 */
956*9558e6acSTreehugger Robot 					if (dirent.head == dir->head) {
957*9558e6acSTreehugger Robot 						pwarn("%s entry in %s has incorrect start cluster\n",
958*9558e6acSTreehugger Robot 								dirent.name, fullpath(dir));
959*9558e6acSTreehugger Robot 						if (ask(1, "Remove")) {
960*9558e6acSTreehugger Robot 							*p = SLOT_DELETED;
961*9558e6acSTreehugger Robot 							mod |= THISMOD|FSDIRMOD;
962*9558e6acSTreehugger Robot 						} else
963*9558e6acSTreehugger Robot 							mod |= FSERROR;
964*9558e6acSTreehugger Robot 						continue;
965*9558e6acSTreehugger Robot 					} else if ((check_subdirectory(fat,
966*9558e6acSTreehugger Robot 					    &dirent) & FSERROR) == FSERROR) {
967*9558e6acSTreehugger Robot 						/*
968*9558e6acSTreehugger Robot 						 * A subdirectory should have
969*9558e6acSTreehugger Robot 						 * a dot (.) entry and a dot-dot
970*9558e6acSTreehugger Robot 						 * (..) entry of ATTR_DIRECTORY,
971*9558e6acSTreehugger Robot 						 * we will inspect further when
972*9558e6acSTreehugger Robot 						 * traversing into it.
973*9558e6acSTreehugger Robot 						 */
974*9558e6acSTreehugger Robot 						if (ask(1, "Remove")) {
975*9558e6acSTreehugger Robot 							*p = SLOT_DELETED;
976*9558e6acSTreehugger Robot 							mod |= THISMOD|FSDIRMOD;
977*9558e6acSTreehugger Robot 						} else
978*9558e6acSTreehugger Robot 							mod |= FSERROR;
979*9558e6acSTreehugger Robot 						continue;
980*9558e6acSTreehugger Robot 					}
981*9558e6acSTreehugger Robot 				}
982*9558e6acSTreehugger Robot 
983*9558e6acSTreehugger Robot 				/* create directory tree node */
984*9558e6acSTreehugger Robot 				if (!(d = newDosDirEntry())) {
985*9558e6acSTreehugger Robot 					perr("No space for directory");
986*9558e6acSTreehugger Robot 					return FSFATAL;
987*9558e6acSTreehugger Robot 				}
988*9558e6acSTreehugger Robot 				memcpy(d, &dirent, sizeof(struct dosDirEntry));
989*9558e6acSTreehugger Robot 				/* link it into the tree */
990*9558e6acSTreehugger Robot 				dir->child = d;
991*9558e6acSTreehugger Robot 
992*9558e6acSTreehugger Robot 				/* Enter this directory into the todo list */
993*9558e6acSTreehugger Robot 				if (!(n = newDirTodo())) {
994*9558e6acSTreehugger Robot 					perr("No space for todo list");
995*9558e6acSTreehugger Robot 					return FSFATAL;
996*9558e6acSTreehugger Robot 				}
997*9558e6acSTreehugger Robot 				n->next = pendingDirectories;
998*9558e6acSTreehugger Robot 				n->dir = d;
999*9558e6acSTreehugger Robot 				pendingDirectories = n;
1000*9558e6acSTreehugger Robot 			} else {
1001*9558e6acSTreehugger Robot 				mod |= k = checksize(fat, p, &dirent);
1002*9558e6acSTreehugger Robot 				if (k & FSDIRMOD)
1003*9558e6acSTreehugger Robot 					mod |= THISMOD;
1004*9558e6acSTreehugger Robot 			}
1005*9558e6acSTreehugger Robot 			boot->NumFiles++;
1006*9558e6acSTreehugger Robot 		}
1007*9558e6acSTreehugger Robot 
1008*9558e6acSTreehugger Robot 		if (is_legacyroot) {
1009*9558e6acSTreehugger Robot 			/*
1010*9558e6acSTreehugger Robot 			 * Don't bother to write back right now because
1011*9558e6acSTreehugger Robot 			 * we may continue to make modification to the
1012*9558e6acSTreehugger Robot 			 * non-FAT32 root directory below.
1013*9558e6acSTreehugger Robot 			 */
1014*9558e6acSTreehugger Robot 			break;
1015*9558e6acSTreehugger Robot 		} else if (mod & THISMOD) {
1016*9558e6acSTreehugger Robot 			if (lseek(fd, off, SEEK_SET) != off
1017*9558e6acSTreehugger Robot 			    || write(fd, buffer, iosize) != iosize) {
1018*9558e6acSTreehugger Robot 				perr("Unable to write directory");
1019*9558e6acSTreehugger Robot 				return FSFATAL;
1020*9558e6acSTreehugger Robot 			}
1021*9558e6acSTreehugger Robot 			mod &= ~THISMOD;
1022*9558e6acSTreehugger Robot 		}
1023*9558e6acSTreehugger Robot 	} while (fat_is_valid_cl(fat, (cl = fat_get_cl_next(fat, cl))));
1024*9558e6acSTreehugger Robot 	if (invlfn || vallfn)
1025*9558e6acSTreehugger Robot 		mod |= removede(fat,
1026*9558e6acSTreehugger Robot 				invlfn ? invlfn : vallfn, p,
1027*9558e6acSTreehugger Robot 				invlfn ? invcl : valcl, -1, 0,
1028*9558e6acSTreehugger Robot 				fullpath(dir), 1);
1029*9558e6acSTreehugger Robot 
1030*9558e6acSTreehugger Robot 	/*
1031*9558e6acSTreehugger Robot 	 * The root directory of non-FAT32 filesystems is in a special
1032*9558e6acSTreehugger Robot 	 * area and may have been modified above removede() without
1033*9558e6acSTreehugger Robot 	 * being written out.
1034*9558e6acSTreehugger Robot 	 */
1035*9558e6acSTreehugger Robot 	if ((mod & FSDIRMOD) && is_legacyroot) {
1036*9558e6acSTreehugger Robot 		if (lseek(fd, off, SEEK_SET) != off
1037*9558e6acSTreehugger Robot 		    || write(fd, buffer, iosize) != iosize) {
1038*9558e6acSTreehugger Robot 			perr("Unable to write directory");
1039*9558e6acSTreehugger Robot 			return FSFATAL;
1040*9558e6acSTreehugger Robot 		}
1041*9558e6acSTreehugger Robot 		mod &= ~THISMOD;
1042*9558e6acSTreehugger Robot 	}
1043*9558e6acSTreehugger Robot 	return mod & ~THISMOD;
1044*9558e6acSTreehugger Robot }
1045*9558e6acSTreehugger Robot 
1046*9558e6acSTreehugger Robot int
handleDirTree(struct fat_descriptor * fat)1047*9558e6acSTreehugger Robot handleDirTree(struct fat_descriptor *fat)
1048*9558e6acSTreehugger Robot {
1049*9558e6acSTreehugger Robot 	int mod;
1050*9558e6acSTreehugger Robot 
1051*9558e6acSTreehugger Robot 	mod = readDosDirSection(fat, rootDir);
1052*9558e6acSTreehugger Robot 	if (mod & FSFATAL)
1053*9558e6acSTreehugger Robot 		return FSFATAL;
1054*9558e6acSTreehugger Robot 
1055*9558e6acSTreehugger Robot 	/*
1056*9558e6acSTreehugger Robot 	 * process the directory todo list
1057*9558e6acSTreehugger Robot 	 */
1058*9558e6acSTreehugger Robot 	while (pendingDirectories) {
1059*9558e6acSTreehugger Robot 		struct dosDirEntry *dir = pendingDirectories->dir;
1060*9558e6acSTreehugger Robot 		struct dirTodoNode *n = pendingDirectories->next;
1061*9558e6acSTreehugger Robot 
1062*9558e6acSTreehugger Robot 		/*
1063*9558e6acSTreehugger Robot 		 * remove TODO entry now, the list might change during
1064*9558e6acSTreehugger Robot 		 * directory reads
1065*9558e6acSTreehugger Robot 		 */
1066*9558e6acSTreehugger Robot 		freeDirTodo(pendingDirectories);
1067*9558e6acSTreehugger Robot 		pendingDirectories = n;
1068*9558e6acSTreehugger Robot 
1069*9558e6acSTreehugger Robot 		/*
1070*9558e6acSTreehugger Robot 		 * handle subdirectory
1071*9558e6acSTreehugger Robot 		 */
1072*9558e6acSTreehugger Robot 		mod |= readDosDirSection(fat, dir);
1073*9558e6acSTreehugger Robot 		if (mod & FSFATAL)
1074*9558e6acSTreehugger Robot 			return FSFATAL;
1075*9558e6acSTreehugger Robot 	}
1076*9558e6acSTreehugger Robot 
1077*9558e6acSTreehugger Robot 	return mod;
1078*9558e6acSTreehugger Robot }
1079*9558e6acSTreehugger Robot 
1080*9558e6acSTreehugger Robot /*
1081*9558e6acSTreehugger Robot  * Try to reconnect a FAT chain into dir
1082*9558e6acSTreehugger Robot  */
1083*9558e6acSTreehugger Robot static u_char *lfbuf;
1084*9558e6acSTreehugger Robot static cl_t lfcl;
1085*9558e6acSTreehugger Robot static off_t lfoff;
1086*9558e6acSTreehugger Robot 
1087*9558e6acSTreehugger Robot int
reconnect(struct fat_descriptor * fat,cl_t head,size_t length)1088*9558e6acSTreehugger Robot reconnect(struct fat_descriptor *fat, cl_t head, size_t length)
1089*9558e6acSTreehugger Robot {
1090*9558e6acSTreehugger Robot 	struct bootblock *boot = fat_get_boot(fat);
1091*9558e6acSTreehugger Robot 	struct dosDirEntry d;
1092*9558e6acSTreehugger Robot 	int len, dosfs;
1093*9558e6acSTreehugger Robot 	u_char *p;
1094*9558e6acSTreehugger Robot 
1095*9558e6acSTreehugger Robot 	dosfs = fat_get_fd(fat);
1096*9558e6acSTreehugger Robot 
1097*9558e6acSTreehugger Robot 	if (!ask(1, "Reconnect"))
1098*9558e6acSTreehugger Robot 		return FSERROR;
1099*9558e6acSTreehugger Robot 
1100*9558e6acSTreehugger Robot 	if (!lostDir) {
1101*9558e6acSTreehugger Robot 		for (lostDir = rootDir->child; lostDir; lostDir = lostDir->next) {
1102*9558e6acSTreehugger Robot 			if (!strcmp(lostDir->name, LOSTDIR))
1103*9558e6acSTreehugger Robot 				break;
1104*9558e6acSTreehugger Robot 		}
1105*9558e6acSTreehugger Robot 		if (!lostDir) {		/* Create LOSTDIR?		XXX */
1106*9558e6acSTreehugger Robot 			pwarn("No %s directory\n", LOSTDIR);
1107*9558e6acSTreehugger Robot 			return FSERROR;
1108*9558e6acSTreehugger Robot 		}
1109*9558e6acSTreehugger Robot 	}
1110*9558e6acSTreehugger Robot 	if (!lfbuf) {
1111*9558e6acSTreehugger Robot 		lfbuf = malloc(boot->ClusterSize);
1112*9558e6acSTreehugger Robot 		if (!lfbuf) {
1113*9558e6acSTreehugger Robot 			perr("No space for buffer");
1114*9558e6acSTreehugger Robot 			return FSFATAL;
1115*9558e6acSTreehugger Robot 		}
1116*9558e6acSTreehugger Robot 		p = NULL;
1117*9558e6acSTreehugger Robot 	} else
1118*9558e6acSTreehugger Robot 		p = lfbuf;
1119*9558e6acSTreehugger Robot 	while (1) {
1120*9558e6acSTreehugger Robot 		if (p)
1121*9558e6acSTreehugger Robot 			for (; p < lfbuf + boot->ClusterSize; p += 32)
1122*9558e6acSTreehugger Robot 				if (*p == SLOT_EMPTY
1123*9558e6acSTreehugger Robot 				    || *p == SLOT_DELETED)
1124*9558e6acSTreehugger Robot 					break;
1125*9558e6acSTreehugger Robot 		if (p && p < lfbuf + boot->ClusterSize)
1126*9558e6acSTreehugger Robot 			break;
1127*9558e6acSTreehugger Robot 		lfcl = p ? fat_get_cl_next(fat, lfcl) : lostDir->head;
1128*9558e6acSTreehugger Robot 		if (lfcl < CLUST_FIRST || lfcl >= boot->NumClusters) {
1129*9558e6acSTreehugger Robot 			/* Extend LOSTDIR?				XXX */
1130*9558e6acSTreehugger Robot 			pwarn("No space in %s\n", LOSTDIR);
1131*9558e6acSTreehugger Robot 			lfcl = (lostDir->head < boot->NumClusters) ? lostDir->head : 0;
1132*9558e6acSTreehugger Robot 			return FSERROR;
1133*9558e6acSTreehugger Robot 		}
1134*9558e6acSTreehugger Robot 		lfoff = (lfcl - CLUST_FIRST) * boot->ClusterSize
1135*9558e6acSTreehugger Robot 		    + boot->FirstCluster * boot->bpbBytesPerSec;
1136*9558e6acSTreehugger Robot 
1137*9558e6acSTreehugger Robot 		if (lseek(dosfs, lfoff, SEEK_SET) != lfoff
1138*9558e6acSTreehugger Robot 		    || (size_t)read(dosfs, lfbuf, boot->ClusterSize) != boot->ClusterSize) {
1139*9558e6acSTreehugger Robot 			perr("could not read LOST.DIR");
1140*9558e6acSTreehugger Robot 			return FSFATAL;
1141*9558e6acSTreehugger Robot 		}
1142*9558e6acSTreehugger Robot 		p = lfbuf;
1143*9558e6acSTreehugger Robot 	}
1144*9558e6acSTreehugger Robot 
1145*9558e6acSTreehugger Robot 	boot->NumFiles++;
1146*9558e6acSTreehugger Robot 	/* Ensure uniqueness of entry here!				XXX */
1147*9558e6acSTreehugger Robot 	memset(&d, 0, sizeof d);
1148*9558e6acSTreehugger Robot 	/* worst case -1 = 4294967295, 10 digits */
1149*9558e6acSTreehugger Robot 	len = snprintf(d.name, sizeof(d.name), "%u", head);
1150*9558e6acSTreehugger Robot 	d.flags = 0;
1151*9558e6acSTreehugger Robot 	d.head = head;
1152*9558e6acSTreehugger Robot 	d.size = length * boot->ClusterSize;
1153*9558e6acSTreehugger Robot 
1154*9558e6acSTreehugger Robot 	memcpy(p, d.name, len);
1155*9558e6acSTreehugger Robot 	memset(p + len, ' ', 11 - len);
1156*9558e6acSTreehugger Robot 	memset(p + 11, 0, 32 - 11);
1157*9558e6acSTreehugger Robot 	p[26] = (u_char)d.head;
1158*9558e6acSTreehugger Robot 	p[27] = (u_char)(d.head >> 8);
1159*9558e6acSTreehugger Robot 	if (boot->ClustMask == CLUST32_MASK) {
1160*9558e6acSTreehugger Robot 		p[20] = (u_char)(d.head >> 16);
1161*9558e6acSTreehugger Robot 		p[21] = (u_char)(d.head >> 24);
1162*9558e6acSTreehugger Robot 	}
1163*9558e6acSTreehugger Robot 	p[28] = (u_char)d.size;
1164*9558e6acSTreehugger Robot 	p[29] = (u_char)(d.size >> 8);
1165*9558e6acSTreehugger Robot 	p[30] = (u_char)(d.size >> 16);
1166*9558e6acSTreehugger Robot 	p[31] = (u_char)(d.size >> 24);
1167*9558e6acSTreehugger Robot 	if (lseek(dosfs, lfoff, SEEK_SET) != lfoff
1168*9558e6acSTreehugger Robot 	    || (size_t)write(dosfs, lfbuf, boot->ClusterSize) != boot->ClusterSize) {
1169*9558e6acSTreehugger Robot 		perr("could not write LOST.DIR");
1170*9558e6acSTreehugger Robot 		return FSFATAL;
1171*9558e6acSTreehugger Robot 	}
1172*9558e6acSTreehugger Robot 	return FSDIRMOD;
1173*9558e6acSTreehugger Robot }
1174*9558e6acSTreehugger Robot 
1175*9558e6acSTreehugger Robot void
finishlf(void)1176*9558e6acSTreehugger Robot finishlf(void)
1177*9558e6acSTreehugger Robot {
1178*9558e6acSTreehugger Robot 	if (lfbuf)
1179*9558e6acSTreehugger Robot 		free(lfbuf);
1180*9558e6acSTreehugger Robot 	lfbuf = NULL;
1181*9558e6acSTreehugger Robot }
1182