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