1c2c66affSColin Finck /* check.c - Check and repair a PC/MS-DOS filesystem
2c2c66affSColin Finck
3c2c66affSColin Finck Copyright (C) 1993 Werner Almesberger <werner.almesberger@lrc.di.epfl.ch>
4c2c66affSColin Finck Copyright (C) 1998 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
5c2c66affSColin Finck Copyright (C) 2008-2014 Daniel Baumann <mail@daniel-baumann.ch>
6c2c66affSColin Finck Copyright (C) 2015 Andreas Bombe <aeb@debian.org>
7c2c66affSColin Finck
8c2c66affSColin Finck This program is free software: you can redistribute it and/or modify
9c2c66affSColin Finck it under the terms of the GNU General Public License as published by
10c2c66affSColin Finck the Free Software Foundation, either version 3 of the License, or
11c2c66affSColin Finck (at your option) any later version.
12c2c66affSColin Finck
13c2c66affSColin Finck This program is distributed in the hope that it will be useful,
14c2c66affSColin Finck but WITHOUT ANY WARRANTY; without even the implied warranty of
15c2c66affSColin Finck MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16c2c66affSColin Finck GNU General Public License for more details.
17c2c66affSColin Finck
18c2c66affSColin Finck You should have received a copy of the GNU General Public License
19c2c66affSColin Finck along with this program. If not, see <http://www.gnu.org/licenses/>.
20c2c66affSColin Finck
21c2c66affSColin Finck The complete text of the GNU General Public License
22c2c66affSColin Finck can be found in /usr/share/common-licenses/GPL-3 file.
23c2c66affSColin Finck */
24c2c66affSColin Finck
25c2c66affSColin Finck /* FAT32, VFAT, Atari format support, and various fixes additions May 1998
26c2c66affSColin Finck * by Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> */
27c2c66affSColin Finck
28c2c66affSColin Finck #include "vfatlib.h"
29c2c66affSColin Finck
30c2c66affSColin Finck #define NDEBUG
31c2c66affSColin Finck #include <debug.h>
32c2c66affSColin Finck
33c2c66affSColin Finck
34c2c66affSColin Finck /* the longest path on the filesystem that can be handled by path_name() */
35469289edSPierre Schweitzer #define PATH_NAME_MAX 1023
36c2c66affSColin Finck
37c2c66affSColin Finck static DOS_FILE *root;
38c2c66affSColin Finck
39c2c66affSColin Finck /* get start field of a dir entry */
40c2c66affSColin Finck #define FSTART(p,fs) \
41c2c66affSColin Finck ((uint32_t)le16toh(p->dir_ent.start) | \
42c2c66affSColin Finck (fs->fat_bits == 32 ? le16toh(p->dir_ent.starthi) << 16 : 0))
43c2c66affSColin Finck
44c2c66affSColin Finck #define MODIFY(p,i,v) \
45c2c66affSColin Finck do { \
46c2c66affSColin Finck if (p->offset) { \
47c2c66affSColin Finck p->dir_ent.i = v; \
48c2c66affSColin Finck fs_write(p->offset+offsetof(DIR_ENT,i), \
49c2c66affSColin Finck sizeof(p->dir_ent.i),&p->dir_ent.i); \
50c2c66affSColin Finck } \
51c2c66affSColin Finck } while(0)
52c2c66affSColin Finck
53c2c66affSColin Finck #define MODIFY_START(p,v,fs) \
54c2c66affSColin Finck do { \
55c2c66affSColin Finck uint32_t __v = (v); \
56c2c66affSColin Finck if (!p->offset) { \
57c2c66affSColin Finck /* writing to fake entry for FAT32 root dir */ \
58c2c66affSColin Finck if (!__v) die("Oops, deleting FAT32 root dir!"); \
59c2c66affSColin Finck fs->root_cluster = __v; \
60c2c66affSColin Finck p->dir_ent.start = htole16(__v&0xffff); \
61c2c66affSColin Finck p->dir_ent.starthi = htole16(__v>>16); \
62c2c66affSColin Finck __v = htole32(__v); \
63c2c66affSColin Finck fs_write(offsetof(struct boot_sector,root_cluster), \
64c2c66affSColin Finck sizeof(((struct boot_sector *)0)->root_cluster), \
65c2c66affSColin Finck &__v); \
66c2c66affSColin Finck } \
67c2c66affSColin Finck else { \
68c2c66affSColin Finck MODIFY(p,start,htole16((__v)&0xffff)); \
69c2c66affSColin Finck if (fs->fat_bits == 32) \
70c2c66affSColin Finck MODIFY(p,starthi,htole16((__v)>>16)); \
71c2c66affSColin Finck } \
72c2c66affSColin Finck } while(0)
73c2c66affSColin Finck
alloc_rootdir_entry(DOS_FS * fs,DIR_ENT * de,const char * pattern,int gen_name)74469289edSPierre Schweitzer off_t alloc_rootdir_entry(DOS_FS * fs, DIR_ENT * de, const char *pattern, int gen_name)
75c2c66affSColin Finck {
76c2c66affSColin Finck static int curr_num = 0;
77c2c66affSColin Finck off_t offset;
78c2c66affSColin Finck
79c2c66affSColin Finck if (fs->root_cluster) {
80c2c66affSColin Finck DIR_ENT d2;
81c2c66affSColin Finck int i = 0, got = 0;
82c2c66affSColin Finck uint32_t clu_num, prev = 0;
83c2c66affSColin Finck off_t offset2;
84c2c66affSColin Finck
85c2c66affSColin Finck clu_num = fs->root_cluster;
86c2c66affSColin Finck offset = cluster_start(fs, clu_num);
87c2c66affSColin Finck while (clu_num > 0 && clu_num != -1) {
88c2c66affSColin Finck fs_read(offset, sizeof(DIR_ENT), &d2);
89c2c66affSColin Finck if (IS_FREE(d2.name) && d2.attr != VFAT_LN_ATTR) {
90c2c66affSColin Finck got = 1;
91c2c66affSColin Finck break;
92c2c66affSColin Finck }
93c2c66affSColin Finck i += sizeof(DIR_ENT);
94c2c66affSColin Finck offset += sizeof(DIR_ENT);
95c2c66affSColin Finck if ((i % fs->cluster_size) == 0) {
96c2c66affSColin Finck prev = clu_num;
97c2c66affSColin Finck if ((clu_num = next_cluster(fs, clu_num)) == 0 || clu_num == -1)
98c2c66affSColin Finck break;
99c2c66affSColin Finck offset = cluster_start(fs, clu_num);
100c2c66affSColin Finck }
101c2c66affSColin Finck }
102c2c66affSColin Finck if (!got) {
103c2c66affSColin Finck /* no free slot, need to extend root dir: alloc next free cluster
104c2c66affSColin Finck * after previous one */
105c2c66affSColin Finck if (!prev)
106c2c66affSColin Finck die("Root directory has no cluster allocated!");
107c2c66affSColin Finck for (clu_num = prev + 1; clu_num != prev; clu_num++) {
108c2c66affSColin Finck FAT_ENTRY entry;
109c2c66affSColin Finck
110c2c66affSColin Finck if (clu_num >= fs->data_clusters + 2)
111c2c66affSColin Finck clu_num = 2;
112c2c66affSColin Finck get_fat(&entry, fs->fat, clu_num, fs);
113c2c66affSColin Finck if (!entry.value)
114c2c66affSColin Finck break;
115c2c66affSColin Finck }
116c2c66affSColin Finck if (clu_num == prev)
117c2c66affSColin Finck die("Root directory full and no free cluster");
118c2c66affSColin Finck set_fat(fs, prev, clu_num);
119c2c66affSColin Finck set_fat(fs, clu_num, -1);
120c2c66affSColin Finck set_owner(fs, clu_num, get_owner(fs, fs->root_cluster));
121c2c66affSColin Finck /* clear new cluster */
122c2c66affSColin Finck memset(&d2, 0, sizeof(d2));
123c2c66affSColin Finck offset = cluster_start(fs, clu_num);
124c2c66affSColin Finck for (i = 0; i < fs->cluster_size; i += sizeof(DIR_ENT))
125c2c66affSColin Finck fs_write(offset + i, sizeof(d2), &d2);
126c2c66affSColin Finck }
127c2c66affSColin Finck memset(de, 0, sizeof(DIR_ENT));
128469289edSPierre Schweitzer if (gen_name) {
129c2c66affSColin Finck while (1) {
130c2c66affSColin Finck char expanded[12];
131c2c66affSColin Finck sprintf(expanded, pattern, curr_num);
132c2c66affSColin Finck memcpy(de->name, expanded, MSDOS_NAME);
133c2c66affSColin Finck clu_num = fs->root_cluster;
134c2c66affSColin Finck i = 0;
135c2c66affSColin Finck offset2 = cluster_start(fs, clu_num);
136c2c66affSColin Finck while (clu_num > 0 && clu_num != -1) {
137c2c66affSColin Finck fs_read(offset2, sizeof(DIR_ENT), &d2);
138c2c66affSColin Finck if (offset2 != offset &&
139c2c66affSColin Finck !strncmp((const char *)d2.name, (const char *)de->name,
140c2c66affSColin Finck MSDOS_NAME))
141c2c66affSColin Finck break;
142c2c66affSColin Finck i += sizeof(DIR_ENT);
143c2c66affSColin Finck offset2 += sizeof(DIR_ENT);
144c2c66affSColin Finck if ((i % fs->cluster_size) == 0) {
145c2c66affSColin Finck if ((clu_num = next_cluster(fs, clu_num)) == 0 ||
146c2c66affSColin Finck clu_num == -1)
147c2c66affSColin Finck break;
148c2c66affSColin Finck offset2 = cluster_start(fs, clu_num);
149c2c66affSColin Finck }
150c2c66affSColin Finck }
151c2c66affSColin Finck if (clu_num == 0 || clu_num == -1)
152c2c66affSColin Finck break;
153c2c66affSColin Finck if (++curr_num >= 10000)
154c2c66affSColin Finck die("Unable to create unique name");
155c2c66affSColin Finck }
156c2c66affSColin Finck } else {
157469289edSPierre Schweitzer memcpy(de->name, pattern, MSDOS_NAME);
158469289edSPierre Schweitzer }
159469289edSPierre Schweitzer } else {
160c2c66affSColin Finck DIR_ENT *root;
161c2c66affSColin Finck int next_free = 0, scan;
162c2c66affSColin Finck
163c2c66affSColin Finck root = alloc(fs->root_entries * sizeof(DIR_ENT));
164c2c66affSColin Finck fs_read(fs->root_start, fs->root_entries * sizeof(DIR_ENT), root);
165c2c66affSColin Finck
166c2c66affSColin Finck while (next_free < fs->root_entries)
167c2c66affSColin Finck if (IS_FREE(root[next_free].name) &&
168c2c66affSColin Finck root[next_free].attr != VFAT_LN_ATTR)
169c2c66affSColin Finck break;
170c2c66affSColin Finck else
171c2c66affSColin Finck next_free++;
172c2c66affSColin Finck if (next_free == fs->root_entries)
173c2c66affSColin Finck die("Root directory is full.");
174c2c66affSColin Finck offset = fs->root_start + next_free * sizeof(DIR_ENT);
175c2c66affSColin Finck memset(de, 0, sizeof(DIR_ENT));
176469289edSPierre Schweitzer if (gen_name) {
177c2c66affSColin Finck while (1) {
178c2c66affSColin Finck char expanded[12];
179c2c66affSColin Finck sprintf(expanded, pattern, curr_num);
180c2c66affSColin Finck memcpy(de->name, expanded, MSDOS_NAME);
181c2c66affSColin Finck for (scan = 0; scan < fs->root_entries; scan++)
182c2c66affSColin Finck if (scan != next_free &&
183c2c66affSColin Finck !strncmp((const char *)root[scan].name,
184c2c66affSColin Finck (const char *)de->name, MSDOS_NAME))
185c2c66affSColin Finck break;
186c2c66affSColin Finck if (scan == fs->root_entries)
187c2c66affSColin Finck break;
188c2c66affSColin Finck if (++curr_num >= 10000)
189c2c66affSColin Finck die("Unable to create unique name");
190c2c66affSColin Finck }
191469289edSPierre Schweitzer } else {
192469289edSPierre Schweitzer memcpy(de->name, pattern, MSDOS_NAME);
193469289edSPierre Schweitzer }
194c2c66affSColin Finck free(root);
195c2c66affSColin Finck }
196c2c66affSColin Finck ++n_files;
197c2c66affSColin Finck return offset;
198c2c66affSColin Finck }
199c2c66affSColin Finck
200c2c66affSColin Finck /**
201c2c66affSColin Finck * Construct a full path (starting with '/') for the specified dentry,
202c2c66affSColin Finck * relative to the partition. All components are "long" names where possible.
203c2c66affSColin Finck *
204c2c66affSColin Finck * @param[in] file Information about dentry (file or directory) of interest
205c2c66affSColin Finck *
206c2c66affSColin Finck * return Pointer to static string containing file's full path
207c2c66affSColin Finck */
path_name(DOS_FILE * file)208c2c66affSColin Finck static char *path_name(DOS_FILE * file)
209c2c66affSColin Finck {
210c2c66affSColin Finck static char path[PATH_NAME_MAX * 2];
211c2c66affSColin Finck
212c2c66affSColin Finck if (!file)
213c2c66affSColin Finck *path = 0; /* Reached the root directory */
214c2c66affSColin Finck else {
215c2c66affSColin Finck if (strlen(path_name(file->parent)) > PATH_NAME_MAX)
216c2c66affSColin Finck die("Path name too long.");
217c2c66affSColin Finck if (strcmp(path, "/") != 0)
218c2c66affSColin Finck strcat(path, "/");
219c2c66affSColin Finck
220c2c66affSColin Finck /* Append the long name to the path,
221c2c66affSColin Finck * or the short name if there isn't a long one
222c2c66affSColin Finck */
223c2c66affSColin Finck strcpy(strrchr(path, 0),
224c2c66affSColin Finck file->lfn ? file->lfn : file_name(file->dir_ent.name));
225c2c66affSColin Finck }
226c2c66affSColin Finck return path;
227c2c66affSColin Finck }
228c2c66affSColin Finck
229c2c66affSColin Finck static const int day_n[] =
230c2c66affSColin Finck { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, 0 };
231c2c66affSColin Finck /* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */
232c2c66affSColin Finck
233c2c66affSColin Finck /* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
234c2c66affSColin Finck
date_dos2unix(unsigned short time,unsigned short date)235c2c66affSColin Finck static time_t date_dos2unix(unsigned short time, unsigned short date)
236c2c66affSColin Finck {
237c2c66affSColin Finck int month, year;
238c2c66affSColin Finck time_t secs;
239c2c66affSColin Finck
240c2c66affSColin Finck month = ((date >> 5) & 15) - 1;
241c2c66affSColin Finck if (month < 0) {
242c2c66affSColin Finck /* make sure that nothing bad happens if the month bits were zero */
243c2c66affSColin Finck month = 0;
244c2c66affSColin Finck }
245c2c66affSColin Finck year = date >> 9;
246c2c66affSColin Finck secs =
247c2c66affSColin Finck (time & 31) * 2 + 60 * ((time >> 5) & 63) + (time >> 11) * 3600 +
248c2c66affSColin Finck 86400 * ((date & 31) - 1 + day_n[month] + (year / 4) + year * 365 -
249c2c66affSColin Finck ((year & 3) == 0 && month < 2 ? 1 : 0) + 3653);
250c2c66affSColin Finck /* days since 1.1.70 plus 80's leap day */
251c2c66affSColin Finck return secs;
252c2c66affSColin Finck }
253c2c66affSColin Finck
254469289edSPierre Schweitzer #ifdef __REACTOS__ // Old version!
255c2c66affSColin Finck
file_stat(DOS_FILE * file)256c2c66affSColin Finck static char *file_stat(DOS_FILE * file)
257c2c66affSColin Finck {
258c2c66affSColin Finck static char temp[100];
259c2c66affSColin Finck char tmp[100];
260c2c66affSColin Finck time_t date;
261c2c66affSColin Finck LARGE_INTEGER time;
262c2c66affSColin Finck TIME_FIELDS time_fields;
263c2c66affSColin Finck
264c2c66affSColin Finck date = date_dos2unix(le16toh(file->dir_ent.time), le16toh(file->dir_ent.date));
265c2c66affSColin Finck
266c2c66affSColin Finck RtlSecondsSince1970ToTime(date, &time);
267c2c66affSColin Finck RtlTimeToTimeFields(&time, &time_fields);
268c2c66affSColin Finck
269c2c66affSColin Finck _snprintf(tmp, sizeof(tmp), "%d:%d:%d %d.%d.%d",
270c2c66affSColin Finck time_fields.Hour, time_fields.Minute, time_fields.Second,
271c2c66affSColin Finck time_fields.Day, time_fields.Month, time_fields.Year);
272c2c66affSColin Finck
273c2c66affSColin Finck _snprintf(temp, sizeof(temp), " Size %u bytes, date %s", le32toh(file->dir_ent.size), tmp);
274c2c66affSColin Finck return temp;
275c2c66affSColin Finck }
276c2c66affSColin Finck
277c2c66affSColin Finck #else
278c2c66affSColin Finck
file_stat(DOS_FILE * file)279c2c66affSColin Finck static char *file_stat(DOS_FILE * file)
280c2c66affSColin Finck {
281c2c66affSColin Finck static char temp[100];
282c2c66affSColin Finck struct tm *tm;
283c2c66affSColin Finck char tmp[100];
284c2c66affSColin Finck time_t date;
285c2c66affSColin Finck
286c2c66affSColin Finck date =
287c2c66affSColin Finck date_dos2unix(le16toh(file->dir_ent.time), le16toh(file->dir_ent.date));
288c2c66affSColin Finck tm = localtime(&date);
289c2c66affSColin Finck strftime(tmp, 99, "%H:%M:%S %b %d %Y", tm);
290c2c66affSColin Finck sprintf(temp, " Size %u bytes, date %s", le32toh(file->dir_ent.size), tmp);
291c2c66affSColin Finck return temp;
292c2c66affSColin Finck }
293c2c66affSColin Finck
294c2c66affSColin Finck #endif
295c2c66affSColin Finck
bad_name(DOS_FILE * file)296c2c66affSColin Finck static int bad_name(DOS_FILE * file)
297c2c66affSColin Finck {
298c2c66affSColin Finck int i, spc, suspicious = 0;
299c2c66affSColin Finck const char *bad_chars = atari_format ? "*?\\/:" : "*?<>|\"\\/:";
300c2c66affSColin Finck const unsigned char *name = file->dir_ent.name;
301c2c66affSColin Finck const unsigned char *ext = name + 8;
302c2c66affSColin Finck
303c2c66affSColin Finck /* Do not complain about (and auto-correct) the extended attribute files
304c2c66affSColin Finck * of OS/2. */
305c2c66affSColin Finck if (strncmp((const char *)name, "EA DATA SF", 11) == 0 ||
306c2c66affSColin Finck strncmp((const char *)name, "WP ROOT SF", 11) == 0)
307c2c66affSColin Finck return 0;
308c2c66affSColin Finck
309c2c66affSColin Finck /* check if we have neither a long filename nor a short name */
310c2c66affSColin Finck if ((file->lfn == NULL) && (file->dir_ent.lcase & FAT_NO_83NAME)) {
311c2c66affSColin Finck return 1;
312c2c66affSColin Finck }
313c2c66affSColin Finck
314c2c66affSColin Finck /* don't complain about the dummy 11 bytes used by patched Linux
315c2c66affSColin Finck kernels */
316c2c66affSColin Finck if (file->dir_ent.lcase & FAT_NO_83NAME)
317c2c66affSColin Finck return 0;
318c2c66affSColin Finck
319c2c66affSColin Finck for (i = 0; i < MSDOS_NAME; i++) {
320c2c66affSColin Finck if (name[i] < ' ' || name[i] == 0x7f)
321c2c66affSColin Finck return 1;
322c2c66affSColin Finck if (name[i] > 0x7f)
323c2c66affSColin Finck ++suspicious;
324c2c66affSColin Finck if (strchr(bad_chars, name[i]))
325c2c66affSColin Finck return 1;
326c2c66affSColin Finck }
327c2c66affSColin Finck
328c2c66affSColin Finck spc = 0;
329c2c66affSColin Finck for (i = 0; i < 8; i++) {
330c2c66affSColin Finck if (name[i] == ' ')
331c2c66affSColin Finck spc = 1;
332c2c66affSColin Finck else if (spc)
333c2c66affSColin Finck /* non-space after a space not allowed, space terminates the name
334c2c66affSColin Finck * part */
335c2c66affSColin Finck return 1;
336c2c66affSColin Finck }
337c2c66affSColin Finck
338c2c66affSColin Finck spc = 0;
339c2c66affSColin Finck for (i = 0; i < 3; i++) {
340c2c66affSColin Finck if (ext[i] == ' ')
341c2c66affSColin Finck spc = 1;
342c2c66affSColin Finck else if (spc)
343c2c66affSColin Finck /* non-space after a space not allowed, space terminates the ext
344c2c66affSColin Finck * part */
345c2c66affSColin Finck return 1;
346c2c66affSColin Finck }
347c2c66affSColin Finck
348c2c66affSColin Finck /* Under GEMDOS, chars >= 128 are never allowed. */
349c2c66affSColin Finck if (atari_format && suspicious)
350c2c66affSColin Finck return 1;
351c2c66affSColin Finck
352469289edSPierre Schweitzer #ifdef __REACTOS__ // Old !!!!!!!!!!!!!!!
353c2c66affSColin Finck
354c2c66affSColin Finck /* Only complain about too much suspicious chars in interactive mode,
355c2c66affSColin Finck * never correct them automatically. The chars are all basically ok, so we
356c2c66affSColin Finck * shouldn't auto-correct such names. */
357c2c66affSColin Finck if (interactive && suspicious > 6)
358c2c66affSColin Finck return 1;
359c2c66affSColin Finck return 0;
360c2c66affSColin Finck
361c2c66affSColin Finck #else
362c2c66affSColin Finck
363c2c66affSColin Finck /* Under MS-DOS and Windows, chars >= 128 in short names are valid
364c2c66affSColin Finck * (but these characters can be visualised differently depending on
365c2c66affSColin Finck * local codepage: CP437, CP866, etc). The chars are all basically ok,
366c2c66affSColin Finck * so we shouldn't auto-correct such names. */
367c2c66affSColin Finck return 0;
368c2c66affSColin Finck
369c2c66affSColin Finck #endif
370c2c66affSColin Finck }
371c2c66affSColin Finck
lfn_remove(off_t from,off_t to)372c2c66affSColin Finck static void lfn_remove(off_t from, off_t to)
373c2c66affSColin Finck {
374c2c66affSColin Finck DIR_ENT empty;
375c2c66affSColin Finck
376c2c66affSColin Finck /* New dir entry is zeroed except first byte, which is set to 0xe5.
377c2c66affSColin Finck * This is to avoid that some FAT-reading OSes (not Linux! ;) stop reading
378c2c66affSColin Finck * a directory at the first zero entry...
379c2c66affSColin Finck */
380c2c66affSColin Finck memset(&empty, 0, sizeof(empty));
381c2c66affSColin Finck empty.name[0] = DELETED_FLAG;
382c2c66affSColin Finck
383c2c66affSColin Finck for (; from < to; from += sizeof(empty)) {
384c2c66affSColin Finck fs_write(from, sizeof(DIR_ENT), &empty);
385c2c66affSColin Finck }
386c2c66affSColin Finck }
387c2c66affSColin Finck
drop_file(DOS_FS * fs,DOS_FILE * file)388c2c66affSColin Finck static void drop_file(DOS_FS * fs, DOS_FILE * file)
389c2c66affSColin Finck {
390c2c66affSColin Finck uint32_t cluster;
391c2c66affSColin Finck
392c2c66affSColin Finck MODIFY(file, name[0], DELETED_FLAG);
393c2c66affSColin Finck if (file->lfn)
394c2c66affSColin Finck lfn_remove(file->lfn_offset, file->offset);
395c2c66affSColin Finck for (cluster = FSTART(file, fs); cluster > 0 && cluster <
396c2c66affSColin Finck fs->data_clusters + 2; cluster = next_cluster(fs, cluster))
397c2c66affSColin Finck set_owner(fs, cluster, NULL);
398c2c66affSColin Finck --n_files;
399c2c66affSColin Finck }
400c2c66affSColin Finck
truncate_file(DOS_FS * fs,DOS_FILE * file,uint32_t clusters)401c2c66affSColin Finck static void truncate_file(DOS_FS * fs, DOS_FILE * file, uint32_t clusters)
402c2c66affSColin Finck {
403c2c66affSColin Finck int deleting;
404c2c66affSColin Finck uint32_t walk, next;
405c2c66affSColin Finck
406c2c66affSColin Finck walk = FSTART(file, fs);
407c2c66affSColin Finck if ((deleting = !clusters))
408c2c66affSColin Finck MODIFY_START(file, 0, fs);
409c2c66affSColin Finck while (walk > 0 && walk != -1) {
410c2c66affSColin Finck next = next_cluster(fs, walk);
411c2c66affSColin Finck if (deleting)
412c2c66affSColin Finck set_fat(fs, walk, 0);
413c2c66affSColin Finck else if ((deleting = !--clusters))
414c2c66affSColin Finck set_fat(fs, walk, -1);
415c2c66affSColin Finck walk = next;
416c2c66affSColin Finck }
417c2c66affSColin Finck }
418c2c66affSColin Finck
auto_rename(DOS_FILE * file)419c2c66affSColin Finck static void auto_rename(DOS_FILE * file)
420c2c66affSColin Finck {
421c2c66affSColin Finck DOS_FILE *first, *walk;
422c2c66affSColin Finck uint32_t number;
423c2c66affSColin Finck
424c2c66affSColin Finck if (!file->offset)
425c2c66affSColin Finck return; /* cannot rename FAT32 root dir */
426c2c66affSColin Finck first = file->parent ? file->parent->first : root;
427c2c66affSColin Finck number = 0;
428c2c66affSColin Finck while (1) {
429c2c66affSColin Finck char num[8];
430c2c66affSColin Finck sprintf(num, "%07lu", (unsigned long)number);
431c2c66affSColin Finck memcpy(file->dir_ent.name, "FSCK", 4);
432c2c66affSColin Finck memcpy(file->dir_ent.name + 4, num, 7);
433c2c66affSColin Finck for (walk = first; walk; walk = walk->next)
434c2c66affSColin Finck if (walk != file
435c2c66affSColin Finck && !strncmp((const char *)walk->dir_ent.name,
436c2c66affSColin Finck (const char *)file->dir_ent.name, MSDOS_NAME))
437c2c66affSColin Finck break;
438c2c66affSColin Finck if (!walk) {
439c2c66affSColin Finck if (file->dir_ent.lcase & FAT_NO_83NAME) {
440c2c66affSColin Finck /* as we only assign a new 8.3 filename, reset flag that 8.3 name is not
441c2c66affSColin Finck present */
442c2c66affSColin Finck file->dir_ent.lcase &= ~FAT_NO_83NAME;
443c2c66affSColin Finck /* reset the attributes, only keep DIR and VOLUME */
444c2c66affSColin Finck file->dir_ent.attr &= ~(ATTR_DIR | ATTR_VOLUME);
445c2c66affSColin Finck fs_write(file->offset, MSDOS_NAME + 2, &file->dir_ent);
446c2c66affSColin Finck } else {
447c2c66affSColin Finck fs_write(file->offset, MSDOS_NAME, file->dir_ent.name);
448c2c66affSColin Finck }
449c2c66affSColin Finck if (file->lfn)
450c2c66affSColin Finck lfn_fix_checksum(file->lfn_offset, file->offset,
451c2c66affSColin Finck (const char *)file->dir_ent.name);
452c2c66affSColin Finck return;
453c2c66affSColin Finck }
454c2c66affSColin Finck number++;
455c2c66affSColin Finck if (number > 9999999) {
456c2c66affSColin Finck die("Too many files need repair.");
457c2c66affSColin Finck }
458c2c66affSColin Finck }
459c2c66affSColin Finck die("Can't generate a unique name.");
460c2c66affSColin Finck }
461c2c66affSColin Finck
rename_file(DOS_FILE * file)462c2c66affSColin Finck static void rename_file(DOS_FILE * file)
463c2c66affSColin Finck {
464469289edSPierre Schweitzer #ifndef __REACTOS__
465469289edSPierre Schweitzer unsigned char name[46];
466469289edSPierre Schweitzer unsigned char *walk, *here;
467469289edSPierre Schweitzer #endif
468c2c66affSColin Finck
469c2c66affSColin Finck if (!file->offset) {
470469289edSPierre Schweitzer #ifndef __REACTOS__
471469289edSPierre Schweitzer printf("Cannot rename FAT32 root dir\n");
472469289edSPierre Schweitzer #else
473c2c66affSColin Finck VfatPrint( "Cannot rename FAT32 root dir\n" );
474469289edSPierre Schweitzer #endif
475c2c66affSColin Finck return; /* cannot rename FAT32 root dir */
476c2c66affSColin Finck }
477c2c66affSColin Finck while (1) {
478469289edSPierre Schweitzer #ifndef __REACTOS__
479469289edSPierre Schweitzer printf("New name: ");
480c2c66affSColin Finck fflush(stdout);
481c2c66affSColin Finck if (fgets((char *)name, 45, stdin)) {
482469289edSPierre Schweitzer if ((here = (unsigned char *)strchr((const char *)name, '\n')))
483469289edSPierre Schweitzer *here = 0;
484469289edSPierre Schweitzer for (walk = (unsigned char *)strrchr((const char *)name, 0);
485469289edSPierre Schweitzer walk >= name && (*walk == ' ' || *walk == '\t'); walk--) ;
486c2c66affSColin Finck walk[1] = 0;
487c2c66affSColin Finck for (walk = name; *walk == ' ' || *walk == '\t'; walk++) ;
488c2c66affSColin Finck if (file_cvt(walk, file->dir_ent.name)) {
489469289edSPierre Schweitzer if (file->dir_ent.lcase & FAT_NO_83NAME) {
490469289edSPierre Schweitzer /* as we only assign a new 8.3 filename, reset flag that 8.3 name is not
491469289edSPierre Schweitzer present */
492469289edSPierre Schweitzer file->dir_ent.lcase &= ~FAT_NO_83NAME;
493469289edSPierre Schweitzer /* reset the attributes, only keep DIR and VOLUME */
494469289edSPierre Schweitzer file->dir_ent.attr &= ~(ATTR_DIR | ATTR_VOLUME);
495469289edSPierre Schweitzer fs_write(file->offset, MSDOS_NAME + 2, &file->dir_ent);
496469289edSPierre Schweitzer } else {
497c2c66affSColin Finck fs_write(file->offset, MSDOS_NAME, file->dir_ent.name);
498469289edSPierre Schweitzer }
499469289edSPierre Schweitzer if (file->lfn)
500469289edSPierre Schweitzer lfn_fix_checksum(file->lfn_offset, file->offset,
501469289edSPierre Schweitzer (const char *)file->dir_ent.name);
502c2c66affSColin Finck return;
503c2c66affSColin Finck }
504c2c66affSColin Finck }
505c2c66affSColin Finck #else
506c2c66affSColin Finck return;
507c2c66affSColin Finck #endif
508c2c66affSColin Finck }
509c2c66affSColin Finck }
510c2c66affSColin Finck
handle_dot(DOS_FS * fs,DOS_FILE * file,int dots)511c2c66affSColin Finck static int handle_dot(DOS_FS * fs, DOS_FILE * file, int dots)
512c2c66affSColin Finck {
513c2c66affSColin Finck const char *name;
514c2c66affSColin Finck
515c2c66affSColin Finck name =
516c2c66affSColin Finck strncmp((const char *)file->dir_ent.name, MSDOS_DOT,
517c2c66affSColin Finck MSDOS_NAME) ? ".." : ".";
518c2c66affSColin Finck if (!(file->dir_ent.attr & ATTR_DIR)) {
519c2c66affSColin Finck printf("%s\n Is a non-directory.\n", path_name(file));
520c2c66affSColin Finck if (interactive)
521c2c66affSColin Finck printf("1) Drop it\n2) Auto-rename\n3) Rename\n"
522c2c66affSColin Finck "4) Convert to directory\n");
523469289edSPierre Schweitzer #ifndef __REACTOS__
524469289edSPierre Schweitzer else
525469289edSPierre Schweitzer #else
526b0bf7dfbSPierre Schweitzer else if (rw)
527469289edSPierre Schweitzer #endif
528c2c66affSColin Finck printf(" Auto-renaming it.\n");
529469289edSPierre Schweitzer #ifdef __REACTOS__
530b0bf7dfbSPierre Schweitzer if (rw || interactive) {
531469289edSPierre Schweitzer #endif
532c2c66affSColin Finck switch (interactive ? get_key("1234", "?") : '2') {
533c2c66affSColin Finck case '1':
534c2c66affSColin Finck drop_file(fs, file);
535c2c66affSColin Finck return 1;
536c2c66affSColin Finck case '2':
537c2c66affSColin Finck auto_rename(file);
538c2c66affSColin Finck printf(" Renamed to %s\n", file_name(file->dir_ent.name));
539c2c66affSColin Finck return 0;
540c2c66affSColin Finck case '3':
541c2c66affSColin Finck rename_file(file);
542c2c66affSColin Finck return 0;
543c2c66affSColin Finck case '4':
544c2c66affSColin Finck MODIFY(file, size, htole32(0));
545c2c66affSColin Finck MODIFY(file, attr, file->dir_ent.attr | ATTR_DIR);
546c2c66affSColin Finck break;
547469289edSPierre Schweitzer #ifdef __REACTOS__
548c2c66affSColin Finck }
549469289edSPierre Schweitzer #endif
550c2c66affSColin Finck }
551b0bf7dfbSPierre Schweitzer }
552c2c66affSColin Finck if (!dots) {
553c2c66affSColin Finck printf("Root contains directory \"%s\". Dropping it.\n", name);
554c2c66affSColin Finck drop_file(fs, file);
555c2c66affSColin Finck return 1;
556c2c66affSColin Finck }
557c2c66affSColin Finck return 0;
558c2c66affSColin Finck }
559c2c66affSColin Finck
check_file(DOS_FS * fs,DOS_FILE * file)560c2c66affSColin Finck static int check_file(DOS_FS * fs, DOS_FILE * file)
561c2c66affSColin Finck {
562c2c66affSColin Finck DOS_FILE *owner;
563c2c66affSColin Finck int restart;
564c2c66affSColin Finck uint32_t expect, curr, this, clusters, prev, walk, clusters2;
565c2c66affSColin Finck
566c2c66affSColin Finck if (file->dir_ent.attr & ATTR_DIR) {
567c2c66affSColin Finck if (le32toh(file->dir_ent.size)) {
568469289edSPierre Schweitzer #ifndef __REACTOS__
569469289edSPierre Schweitzer printf("%s\n Directory has non-zero size. Fixing it.\n",
570469289edSPierre Schweitzer path_name(file));
571469289edSPierre Schweitzer #else
572b0bf7dfbSPierre Schweitzer printf("%s\n Directory has non-zero size.%s\n",
573b0bf7dfbSPierre Schweitzer path_name(file), (rw) ? " Fixing it." : "");
574469289edSPierre Schweitzer if (rw)
575469289edSPierre Schweitzer #endif
576469289edSPierre Schweitzer MODIFY(file, size, htole32(0));
577c2c66affSColin Finck }
578c2c66affSColin Finck if (file->parent
579c2c66affSColin Finck && !strncmp((const char *)file->dir_ent.name, MSDOS_DOT,
580c2c66affSColin Finck MSDOS_NAME)) {
581c2c66affSColin Finck expect = FSTART(file->parent, fs);
582c2c66affSColin Finck if (FSTART(file, fs) != expect) {
583c2c66affSColin Finck printf("%s\n Start (%lu) does not point to parent (%lu)\n",
584c2c66affSColin Finck path_name(file), (unsigned long)FSTART(file, fs), (long)expect);
585469289edSPierre Schweitzer #ifdef __REACTOS__
586469289edSPierre Schweitzer if (rw)
587469289edSPierre Schweitzer #endif
588469289edSPierre Schweitzer MODIFY_START(file, expect, fs);
589c2c66affSColin Finck }
590c2c66affSColin Finck return 0;
591c2c66affSColin Finck }
592c2c66affSColin Finck if (file->parent
593c2c66affSColin Finck && !strncmp((const char *)file->dir_ent.name, MSDOS_DOTDOT,
594c2c66affSColin Finck MSDOS_NAME)) {
595c2c66affSColin Finck expect =
596c2c66affSColin Finck file->parent->parent ? FSTART(file->parent->parent, fs) : 0;
597c2c66affSColin Finck if (fs->root_cluster && expect == fs->root_cluster)
598c2c66affSColin Finck expect = 0;
599c2c66affSColin Finck if (FSTART(file, fs) != expect) {
600c2c66affSColin Finck printf("%s\n Start (%lu) does not point to .. (%lu)\n",
601c2c66affSColin Finck path_name(file), (unsigned long)FSTART(file, fs), (unsigned long)expect);
602469289edSPierre Schweitzer #ifdef __REACTOS__
603469289edSPierre Schweitzer if (rw)
604469289edSPierre Schweitzer #endif
605469289edSPierre Schweitzer MODIFY_START(file, expect, fs);
606c2c66affSColin Finck }
607c2c66affSColin Finck return 0;
608c2c66affSColin Finck }
609c2c66affSColin Finck if (FSTART(file, fs) == 0) {
610469289edSPierre Schweitzer #ifndef __REACTOS__
611469289edSPierre Schweitzer printf("%s\n Start does point to root directory. Deleting dir. \n",
612469289edSPierre Schweitzer path_name(file));
613469289edSPierre Schweitzer #else
614b0bf7dfbSPierre Schweitzer printf("%s\n Start does point to root directory.%s\n",
615b0bf7dfbSPierre Schweitzer path_name(file), (rw) ? " Deleting dir. " : "");
616469289edSPierre Schweitzer if (rw)
617469289edSPierre Schweitzer #endif
618469289edSPierre Schweitzer MODIFY(file, name[0], DELETED_FLAG);
619c2c66affSColin Finck return 0;
620c2c66affSColin Finck }
621c2c66affSColin Finck }
622c2c66affSColin Finck if (FSTART(file, fs) == 1) {
623c2c66affSColin Finck printf("%s\n Bad start cluster 1. Truncating file.\n",
624c2c66affSColin Finck path_name(file));
625c2c66affSColin Finck if (!file->offset)
626c2c66affSColin Finck die("Bad FAT32 root directory! (bad start cluster 1)\n");
627469289edSPierre Schweitzer #ifdef __REACTOS__
628469289edSPierre Schweitzer if (rw)
629469289edSPierre Schweitzer #endif
630469289edSPierre Schweitzer MODIFY_START(file, 0, fs);
631c2c66affSColin Finck }
632c2c66affSColin Finck if (FSTART(file, fs) >= fs->data_clusters + 2) {
633c2c66affSColin Finck printf
634469289edSPierre Schweitzer #ifndef __REACTOS__
635469289edSPierre Schweitzer ("%s\n Start cluster beyond limit (%lu > %lu). Truncating file.\n",
636469289edSPierre Schweitzer path_name(file), (unsigned long)FSTART(file, fs),
637469289edSPierre Schweitzer (unsigned long)(fs->data_clusters + 1));
638469289edSPierre Schweitzer #else
639b0bf7dfbSPierre Schweitzer ("%s\n Start cluster beyond limit (%lu > %lu).%s\n",
640c2c66affSColin Finck path_name(file), (unsigned long)FSTART(file, fs),
641b0bf7dfbSPierre Schweitzer (unsigned long)(fs->data_clusters + 1),
642b0bf7dfbSPierre Schweitzer (rw) ? " Truncating file." : "");
643469289edSPierre Schweitzer #endif
644c2c66affSColin Finck if (!file->offset)
645c2c66affSColin Finck die("Bad FAT32 root directory! (start cluster beyond limit: %lu > %lu)\n",
646c2c66affSColin Finck (unsigned long)FSTART(file, fs),
647c2c66affSColin Finck (unsigned long)(fs->data_clusters + 1));
648469289edSPierre Schweitzer #ifdef __REACTOS__
649469289edSPierre Schweitzer if (rw)
650469289edSPierre Schweitzer #endif
651469289edSPierre Schweitzer MODIFY_START(file, 0, fs);
652c2c66affSColin Finck }
653c2c66affSColin Finck clusters = prev = 0;
654c2c66affSColin Finck for (curr = FSTART(file, fs) ? FSTART(file, fs) :
655c2c66affSColin Finck -1; curr != -1; curr = next_cluster(fs, curr)) {
656c2c66affSColin Finck FAT_ENTRY curEntry;
657c2c66affSColin Finck get_fat(&curEntry, fs->fat, curr, fs);
658c2c66affSColin Finck
659c2c66affSColin Finck if (!curEntry.value || bad_cluster(fs, curr)) {
660469289edSPierre Schweitzer #ifndef __REACTOS__
661469289edSPierre Schweitzer printf("%s\n Contains a %s cluster (%lu). Assuming EOF.\n",
662469289edSPierre Schweitzer path_name(file), curEntry.value ? "bad" : "free", (unsigned long)curr);
663469289edSPierre Schweitzer #else
664b0bf7dfbSPierre Schweitzer printf("%s\n Contains a %s cluster (%lu).%s\n",
665b0bf7dfbSPierre Schweitzer path_name(file), curEntry.value ? "bad" : "free", (unsigned long)curr,
666b0bf7dfbSPierre Schweitzer (rw) ? " Assuming EOF." : "");
667469289edSPierre Schweitzer #endif
668c2c66affSColin Finck if (prev)
669*c5983e30SPierre Schweitzer #ifdef __REACTOS__
670*c5983e30SPierre Schweitzer {
671*c5983e30SPierre Schweitzer if (rw)
672*c5983e30SPierre Schweitzer #endif
673c2c66affSColin Finck set_fat(fs, prev, -1);
674*c5983e30SPierre Schweitzer #ifdef __REACTOS__
675*c5983e30SPierre Schweitzer }
676*c5983e30SPierre Schweitzer #endif
677c2c66affSColin Finck else if (!file->offset)
678c2c66affSColin Finck die("FAT32 root dir starts with a bad cluster!");
679c2c66affSColin Finck else
680469289edSPierre Schweitzer #ifdef __REACTOS__
681469289edSPierre Schweitzer if (rw)
682469289edSPierre Schweitzer #endif
683469289edSPierre Schweitzer MODIFY_START(file, 0, fs);
684c2c66affSColin Finck break;
685c2c66affSColin Finck }
686c2c66affSColin Finck if (!(file->dir_ent.attr & ATTR_DIR) && le32toh(file->dir_ent.size) <=
687c2c66affSColin Finck (uint64_t)clusters * fs->cluster_size) {
688469289edSPierre Schweitzer #ifdef __REACTOS__
689b0bf7dfbSPierre Schweitzer if (rw) {
690469289edSPierre Schweitzer #endif
691c2c66affSColin Finck printf
692c2c66affSColin Finck ("%s\n File size is %u bytes, cluster chain length is > %llu "
693c2c66affSColin Finck "bytes.\n Truncating file to %u bytes.\n", path_name(file),
694c2c66affSColin Finck le32toh(file->dir_ent.size),
695c2c66affSColin Finck (unsigned long long)clusters * fs->cluster_size,
696c2c66affSColin Finck le32toh(file->dir_ent.size));
697c2c66affSColin Finck truncate_file(fs, file, clusters);
698469289edSPierre Schweitzer #ifdef __REACTOS__
699b0bf7dfbSPierre Schweitzer } else {
700b0bf7dfbSPierre Schweitzer printf
701b0bf7dfbSPierre Schweitzer ("%s\n File size is %u bytes, cluster chain length is > %llu "
702b0bf7dfbSPierre Schweitzer "bytes.\n", path_name(file),
703b0bf7dfbSPierre Schweitzer le32toh(file->dir_ent.size),
704b0bf7dfbSPierre Schweitzer (unsigned long long)clusters * fs->cluster_size);
705b0bf7dfbSPierre Schweitzer }
706469289edSPierre Schweitzer #endif
707c2c66affSColin Finck break;
708c2c66affSColin Finck }
709c2c66affSColin Finck if ((owner = get_owner(fs, curr))) {
710c2c66affSColin Finck int do_trunc = 0;
711c2c66affSColin Finck printf("%s and\n", path_name(owner));
712c2c66affSColin Finck printf("%s\n share clusters.\n", path_name(file));
713c2c66affSColin Finck clusters2 = 0;
714c2c66affSColin Finck for (walk = FSTART(owner, fs); walk > 0 && walk != -1; walk =
715c2c66affSColin Finck next_cluster(fs, walk))
716c2c66affSColin Finck if (walk == curr)
717c2c66affSColin Finck break;
718c2c66affSColin Finck else
719c2c66affSColin Finck clusters2++;
720c2c66affSColin Finck restart = file->dir_ent.attr & ATTR_DIR;
721469289edSPierre Schweitzer #ifndef __REACTOS__
722469289edSPierre Schweitzer if (!owner->offset) {
723469289edSPierre Schweitzer #else
724b0bf7dfbSPierre Schweitzer if (!owner->offset && rw) {
725469289edSPierre Schweitzer #endif
726c2c66affSColin Finck printf(" Truncating second to %llu bytes because first "
727c2c66affSColin Finck "is FAT32 root dir.\n",
728469289edSPierre Schweitzer (unsigned long long)clusters * fs->cluster_size);
729c2c66affSColin Finck do_trunc = 2;
730469289edSPierre Schweitzer #ifndef __REACTOS__
731469289edSPierre Schweitzer } else if (!file->offset) {
732469289edSPierre Schweitzer #else
733b0bf7dfbSPierre Schweitzer } else if (!file->offset && rw) {
734469289edSPierre Schweitzer #endif
735c2c66affSColin Finck printf(" Truncating first to %llu bytes because second "
736c2c66affSColin Finck "is FAT32 root dir.\n",
737469289edSPierre Schweitzer (unsigned long long)clusters2 * fs->cluster_size);
738c2c66affSColin Finck do_trunc = 1;
739c2c66affSColin Finck } else if (interactive)
740c2c66affSColin Finck printf("1) Truncate first to %llu bytes%s\n"
741c2c66affSColin Finck "2) Truncate second to %llu bytes\n",
742469289edSPierre Schweitzer (unsigned long long)clusters2 * fs->cluster_size,
743c2c66affSColin Finck restart ? " and restart" : "",
744469289edSPierre Schweitzer (unsigned long long)clusters * fs->cluster_size);
745469289edSPierre Schweitzer else
746469289edSPierre Schweitzer #ifdef __REACTOS__
747469289edSPierre Schweitzer if (rw)
748469289edSPierre Schweitzer #endif
749c2c66affSColin Finck printf(" Truncating second to %llu bytes.\n",
750469289edSPierre Schweitzer (unsigned long long)clusters * fs->cluster_size);
751469289edSPierre Schweitzer #ifndef __REACTOS__
752469289edSPierre Schweitzer if (do_trunc != 2
753469289edSPierre Schweitzer && (do_trunc == 1
754469289edSPierre Schweitzer #else
755b0bf7dfbSPierre Schweitzer if ((do_trunc != 2 && rw)
756b0bf7dfbSPierre Schweitzer && ((do_trunc == 1 && rw)
757469289edSPierre Schweitzer #endif
758c2c66affSColin Finck || (interactive && get_key("12", "?") == '1'))) {
759c2c66affSColin Finck prev = 0;
760c2c66affSColin Finck clusters = 0;
761c2c66affSColin Finck for (this = FSTART(owner, fs); this > 0 && this != -1; this =
762c2c66affSColin Finck next_cluster(fs, this)) {
763c2c66affSColin Finck if (this == curr) {
764c2c66affSColin Finck if (prev)
765c2c66affSColin Finck set_fat(fs, prev, -1);
766c2c66affSColin Finck else
767c2c66affSColin Finck MODIFY_START(owner, 0, fs);
768c2c66affSColin Finck MODIFY(owner, size,
769c2c66affSColin Finck htole32((uint64_t)clusters *
770c2c66affSColin Finck fs->cluster_size));
771c2c66affSColin Finck if (restart)
772c2c66affSColin Finck return 1;
773c2c66affSColin Finck while (this > 0 && this != -1) {
774c2c66affSColin Finck set_owner(fs, this, NULL);
775c2c66affSColin Finck this = next_cluster(fs, this);
776c2c66affSColin Finck }
777c2c66affSColin Finck this = curr;
778c2c66affSColin Finck break;
779c2c66affSColin Finck }
780c2c66affSColin Finck clusters++;
781c2c66affSColin Finck prev = this;
782c2c66affSColin Finck }
783c2c66affSColin Finck if (this != curr)
784c2c66affSColin Finck die("Internal error: didn't find cluster %d in chain"
785c2c66affSColin Finck " starting at %d", curr, FSTART(owner, fs));
786c2c66affSColin Finck } else {
787c2c66affSColin Finck if (prev)
788c2c66affSColin Finck set_fat(fs, prev, -1);
789c2c66affSColin Finck else
790c2c66affSColin Finck MODIFY_START(file, 0, fs);
791c2c66affSColin Finck break;
792c2c66affSColin Finck }
793c2c66affSColin Finck }
794c2c66affSColin Finck set_owner(fs, curr, file);
795c2c66affSColin Finck clusters++;
796c2c66affSColin Finck prev = curr;
797c2c66affSColin Finck }
798c2c66affSColin Finck if (!(file->dir_ent.attr & ATTR_DIR) && le32toh(file->dir_ent.size) >
799469289edSPierre Schweitzer #ifndef __REACTOS__
800469289edSPierre Schweitzer (uint64_t)clusters * fs->cluster_size) {
801469289edSPierre Schweitzer #else
802b0bf7dfbSPierre Schweitzer (uint64_t)clusters * fs->cluster_size && rw) {
803469289edSPierre Schweitzer #endif
804c2c66affSColin Finck printf
805c2c66affSColin Finck ("%s\n File size is %u bytes, cluster chain length is %llu bytes."
806c2c66affSColin Finck "\n Truncating file to %llu bytes.\n", path_name(file),
807c2c66affSColin Finck le32toh(file->dir_ent.size),
808c2c66affSColin Finck (unsigned long long)clusters * fs->cluster_size,
809c2c66affSColin Finck (unsigned long long)clusters * fs->cluster_size);
810c2c66affSColin Finck MODIFY(file, size,
811c2c66affSColin Finck htole32((uint64_t)clusters * fs->cluster_size));
812c2c66affSColin Finck }
813c2c66affSColin Finck return 0;
814c2c66affSColin Finck }
815c2c66affSColin Finck
816c2c66affSColin Finck static int check_files(DOS_FS * fs, DOS_FILE * start)
817c2c66affSColin Finck {
818c2c66affSColin Finck while (start) {
819c2c66affSColin Finck if (check_file(fs, start))
820c2c66affSColin Finck return 1;
821c2c66affSColin Finck start = start->next;
822c2c66affSColin Finck }
823c2c66affSColin Finck return 0;
824c2c66affSColin Finck }
825c2c66affSColin Finck
826c2c66affSColin Finck static int check_dir(DOS_FS * fs, DOS_FILE ** root, int dots)
827c2c66affSColin Finck {
828c2c66affSColin Finck DOS_FILE *parent, **walk, **scan;
829c2c66affSColin Finck int dot, dotdot, skip, redo;
830c2c66affSColin Finck int good, bad;
831c2c66affSColin Finck
832c2c66affSColin Finck if (!*root)
833c2c66affSColin Finck return 0;
834c2c66affSColin Finck parent = (*root)->parent;
835c2c66affSColin Finck good = bad = 0;
836c2c66affSColin Finck for (walk = root; *walk; walk = &(*walk)->next)
837c2c66affSColin Finck if (bad_name(*walk))
838c2c66affSColin Finck bad++;
839c2c66affSColin Finck else
840c2c66affSColin Finck good++;
841c2c66affSColin Finck if (*root && parent && good + bad > 4 && bad > good / 2) {
842c2c66affSColin Finck printf("%s\n Has a large number of bad entries. (%d/%d)\n",
843c2c66affSColin Finck path_name(parent), bad, good + bad);
844c2c66affSColin Finck if (!dots)
845c2c66affSColin Finck printf(" Not dropping root directory.\n");
846469289edSPierre Schweitzer #ifndef __REACTOS__
847469289edSPierre Schweitzer else if (!interactive)
848469289edSPierre Schweitzer #else
849b0bf7dfbSPierre Schweitzer else if (!interactive || !rw)
850469289edSPierre Schweitzer #endif
851c2c66affSColin Finck printf(" Not dropping it in auto-mode.\n");
852c2c66affSColin Finck else if (get_key("yn", "Drop directory ? (y/n)") == 'y') {
853c2c66affSColin Finck truncate_file(fs, parent, 0);
854c2c66affSColin Finck MODIFY(parent, name[0], DELETED_FLAG);
855c2c66affSColin Finck /* buglet: deleted directory stays in the list. */
856c2c66affSColin Finck return 1;
857c2c66affSColin Finck }
858c2c66affSColin Finck }
859c2c66affSColin Finck dot = dotdot = redo = 0;
860c2c66affSColin Finck walk = root;
861c2c66affSColin Finck while (*walk) {
862c2c66affSColin Finck if (!strncmp
863c2c66affSColin Finck ((const char *)((*walk)->dir_ent.name), MSDOS_DOT, MSDOS_NAME)
864c2c66affSColin Finck || !strncmp((const char *)((*walk)->dir_ent.name), MSDOS_DOTDOT,
865c2c66affSColin Finck MSDOS_NAME)) {
866c2c66affSColin Finck if (handle_dot(fs, *walk, dots)) {
867c2c66affSColin Finck *walk = (*walk)->next;
868c2c66affSColin Finck continue;
869c2c66affSColin Finck }
870c2c66affSColin Finck if (!strncmp
871c2c66affSColin Finck ((const char *)((*walk)->dir_ent.name), MSDOS_DOT, MSDOS_NAME))
872c2c66affSColin Finck dot++;
873c2c66affSColin Finck else
874c2c66affSColin Finck dotdot++;
875c2c66affSColin Finck }
876c2c66affSColin Finck if (!((*walk)->dir_ent.attr & ATTR_VOLUME) && bad_name(*walk)) {
877469289edSPierre Schweitzer #ifndef __REACTOS__
878469289edSPierre Schweitzer puts(path_name(*walk));
879469289edSPierre Schweitzer printf(" Bad short file name (%s).\n",
880469289edSPierre Schweitzer file_name((*walk)->dir_ent.name));
881469289edSPierre Schweitzer #else
882c2c66affSColin Finck printf("%s\n Bad short file name (%s).\n",
883c2c66affSColin Finck path_name(*walk), file_name((*walk)->dir_ent.name));
884469289edSPierre Schweitzer #endif
885c2c66affSColin Finck if (interactive)
886c2c66affSColin Finck printf("1) Drop file\n2) Rename file\n3) Auto-rename\n"
887c2c66affSColin Finck "4) Keep it\n");
888469289edSPierre Schweitzer else
889469289edSPierre Schweitzer #ifdef __REACTOS__
890469289edSPierre Schweitzer if (rw)
891469289edSPierre Schweitzer #endif
892c2c66affSColin Finck printf(" Auto-renaming it.\n");
893469289edSPierre Schweitzer #ifdef __REACTOS__
894b0bf7dfbSPierre Schweitzer if (rw || interactive) {
895469289edSPierre Schweitzer #endif
896c2c66affSColin Finck switch (interactive ? get_key("1234", "?") : '3') {
897c2c66affSColin Finck case '1':
898c2c66affSColin Finck drop_file(fs, *walk);
899c2c66affSColin Finck walk = &(*walk)->next;
900c2c66affSColin Finck continue;
901c2c66affSColin Finck case '2':
902c2c66affSColin Finck rename_file(*walk);
903c2c66affSColin Finck redo = 1;
904c2c66affSColin Finck break;
905c2c66affSColin Finck case '3':
906c2c66affSColin Finck auto_rename(*walk);
907c2c66affSColin Finck printf(" Renamed to %s\n", file_name((*walk)->dir_ent.name));
908c2c66affSColin Finck break;
909c2c66affSColin Finck case '4':
910c2c66affSColin Finck break;
911469289edSPierre Schweitzer #ifdef __REACTOS__
912c2c66affSColin Finck }
913469289edSPierre Schweitzer #endif
914c2c66affSColin Finck }
915b0bf7dfbSPierre Schweitzer }
916c2c66affSColin Finck /* don't check for duplicates of the volume label */
917c2c66affSColin Finck if (!((*walk)->dir_ent.attr & ATTR_VOLUME)) {
918c2c66affSColin Finck scan = &(*walk)->next;
919c2c66affSColin Finck skip = 0;
920c2c66affSColin Finck while (*scan && !skip) {
921c2c66affSColin Finck if (!((*scan)->dir_ent.attr & ATTR_VOLUME) &&
922c2c66affSColin Finck !memcmp((*walk)->dir_ent.name, (*scan)->dir_ent.name,
923c2c66affSColin Finck MSDOS_NAME)) {
924c2c66affSColin Finck printf("%s\n Duplicate directory entry.\n First %s\n",
925c2c66affSColin Finck path_name(*walk), file_stat(*walk));
926c2c66affSColin Finck printf(" Second %s\n", file_stat(*scan));
927c2c66affSColin Finck if (interactive)
928c2c66affSColin Finck printf
929c2c66affSColin Finck ("1) Drop first\n2) Drop second\n3) Rename first\n"
930c2c66affSColin Finck "4) Rename second\n5) Auto-rename first\n"
931c2c66affSColin Finck "6) Auto-rename second\n");
932469289edSPierre Schweitzer else
933469289edSPierre Schweitzer #ifdef __REACTOS__
934469289edSPierre Schweitzer if (rw)
935469289edSPierre Schweitzer #endif
936c2c66affSColin Finck printf(" Auto-renaming second.\n");
937469289edSPierre Schweitzer #ifdef __REACTOS__
938b0bf7dfbSPierre Schweitzer if (rw || interactive) {
939469289edSPierre Schweitzer #endif
940c2c66affSColin Finck switch (interactive ? get_key("123456", "?") : '6') {
941c2c66affSColin Finck case '1':
942c2c66affSColin Finck drop_file(fs, *walk);
943c2c66affSColin Finck *walk = (*walk)->next;
944c2c66affSColin Finck skip = 1;
945c2c66affSColin Finck break;
946c2c66affSColin Finck case '2':
947c2c66affSColin Finck drop_file(fs, *scan);
948c2c66affSColin Finck *scan = (*scan)->next;
949c2c66affSColin Finck continue;
950c2c66affSColin Finck case '3':
951c2c66affSColin Finck rename_file(*walk);
952c2c66affSColin Finck printf(" Renamed to %s\n", path_name(*walk));
953c2c66affSColin Finck redo = 1;
954c2c66affSColin Finck break;
955c2c66affSColin Finck case '4':
956c2c66affSColin Finck rename_file(*scan);
957c2c66affSColin Finck printf(" Renamed to %s\n", path_name(*walk));
958c2c66affSColin Finck redo = 1;
959c2c66affSColin Finck break;
960c2c66affSColin Finck case '5':
961c2c66affSColin Finck auto_rename(*walk);
962c2c66affSColin Finck printf(" Renamed to %s\n",
963c2c66affSColin Finck file_name((*walk)->dir_ent.name));
964c2c66affSColin Finck break;
965c2c66affSColin Finck case '6':
966c2c66affSColin Finck auto_rename(*scan);
967c2c66affSColin Finck printf(" Renamed to %s\n",
968c2c66affSColin Finck file_name((*scan)->dir_ent.name));
969c2c66affSColin Finck break;
970469289edSPierre Schweitzer #ifdef __REACTOS__
971c2c66affSColin Finck }
972469289edSPierre Schweitzer #endif
973c2c66affSColin Finck }
974b0bf7dfbSPierre Schweitzer }
975c2c66affSColin Finck scan = &(*scan)->next;
976c2c66affSColin Finck }
977c2c66affSColin Finck if (skip)
978c2c66affSColin Finck continue;
979c2c66affSColin Finck }
980c2c66affSColin Finck if (!redo)
981c2c66affSColin Finck walk = &(*walk)->next;
982c2c66affSColin Finck else {
983c2c66affSColin Finck walk = root;
984c2c66affSColin Finck dot = dotdot = redo = 0;
985c2c66affSColin Finck }
986c2c66affSColin Finck }
987c2c66affSColin Finck if (dots && !dot)
988c2c66affSColin Finck printf("%s\n \".\" is missing. Can't fix this yet.\n",
989c2c66affSColin Finck path_name(parent));
990c2c66affSColin Finck if (dots && !dotdot)
991c2c66affSColin Finck printf("%s\n \"..\" is missing. Can't fix this yet.\n",
992c2c66affSColin Finck path_name(parent));
993c2c66affSColin Finck return 0;
994c2c66affSColin Finck }
995c2c66affSColin Finck
996c2c66affSColin Finck /**
997c2c66affSColin Finck * Check a dentry's cluster chain for bad clusters.
998c2c66affSColin Finck * If requested, we verify readability and mark unreadable clusters as bad.
999c2c66affSColin Finck *
1000c2c66affSColin Finck * @param[inout] fs Information about the filesystem
1001c2c66affSColin Finck * @param[in] file dentry to check
1002c2c66affSColin Finck * @param[in] read_test Nonzero == verify that dentry's clusters can
1003c2c66affSColin Finck * be read
1004c2c66affSColin Finck */
1005c2c66affSColin Finck static void test_file(DOS_FS * fs, DOS_FILE * file, int read_test)
1006c2c66affSColin Finck {
1007c2c66affSColin Finck DOS_FILE *owner;
1008c2c66affSColin Finck uint32_t walk, prev, clusters, next_clu;
1009c2c66affSColin Finck
1010c2c66affSColin Finck prev = clusters = 0;
1011c2c66affSColin Finck for (walk = FSTART(file, fs); walk > 1 && walk < fs->data_clusters + 2;
1012c2c66affSColin Finck walk = next_clu) {
1013c2c66affSColin Finck next_clu = next_cluster(fs, walk);
1014c2c66affSColin Finck
1015c2c66affSColin Finck /* In this stage we are checking only for a loop within our own
1016c2c66affSColin Finck * cluster chain.
1017c2c66affSColin Finck * Cross-linking of clusters is handled in check_file()
1018c2c66affSColin Finck */
1019c2c66affSColin Finck if ((owner = get_owner(fs, walk))) {
1020c2c66affSColin Finck if (owner == file) {
1021c2c66affSColin Finck printf("%s\n Circular cluster chain. Truncating to %lu "
1022c2c66affSColin Finck "cluster%s.\n", path_name(file), (unsigned long)clusters,
1023c2c66affSColin Finck clusters == 1 ? "" : "s");
1024c2c66affSColin Finck if (prev)
1025c2c66affSColin Finck set_fat(fs, prev, -1);
1026c2c66affSColin Finck else if (!file->offset)
1027c2c66affSColin Finck die("Bad FAT32 root directory! (bad start cluster)\n");
1028c2c66affSColin Finck else
1029c2c66affSColin Finck MODIFY_START(file, 0, fs);
1030c2c66affSColin Finck }
1031c2c66affSColin Finck break;
1032c2c66affSColin Finck }
1033c2c66affSColin Finck if (bad_cluster(fs, walk))
1034c2c66affSColin Finck break;
1035c2c66affSColin Finck if (read_test) {
1036c2c66affSColin Finck if (fs_test(cluster_start(fs, walk), fs->cluster_size)) {
1037c2c66affSColin Finck prev = walk;
1038c2c66affSColin Finck clusters++;
1039c2c66affSColin Finck } else {
1040c2c66affSColin Finck printf("%s\n Cluster %lu (%lu) is unreadable. Skipping it.\n",
1041c2c66affSColin Finck path_name(file), (unsigned long)clusters, (unsigned long)walk);
1042c2c66affSColin Finck if (prev)
1043c2c66affSColin Finck set_fat(fs, prev, next_cluster(fs, walk));
1044c2c66affSColin Finck else
1045c2c66affSColin Finck MODIFY_START(file, next_cluster(fs, walk), fs);
1046c2c66affSColin Finck set_fat(fs, walk, -2);
1047c2c66affSColin Finck }
1048469289edSPierre Schweitzer } else {
1049469289edSPierre Schweitzer prev = walk;
1050469289edSPierre Schweitzer clusters++;
1051c2c66affSColin Finck }
1052c2c66affSColin Finck set_owner(fs, walk, file);
1053c2c66affSColin Finck }
1054c2c66affSColin Finck /* Revert ownership (for now) */
1055c2c66affSColin Finck for (walk = FSTART(file, fs); walk > 1 && walk < fs->data_clusters + 2;
1056c2c66affSColin Finck walk = next_cluster(fs, walk))
1057c2c66affSColin Finck if (bad_cluster(fs, walk))
1058c2c66affSColin Finck break;
1059c2c66affSColin Finck else if (get_owner(fs, walk) == file)
1060c2c66affSColin Finck set_owner(fs, walk, NULL);
1061c2c66affSColin Finck else
1062c2c66affSColin Finck break;
1063c2c66affSColin Finck }
1064c2c66affSColin Finck
1065c2c66affSColin Finck static void undelete(DOS_FS * fs, DOS_FILE * file)
1066c2c66affSColin Finck {
1067c2c66affSColin Finck uint32_t clusters, left, prev, walk;
1068c2c66affSColin Finck
1069c2c66affSColin Finck clusters = left = (le32toh(file->dir_ent.size) + fs->cluster_size - 1) /
1070c2c66affSColin Finck fs->cluster_size;
1071c2c66affSColin Finck prev = 0;
1072c2c66affSColin Finck
1073c2c66affSColin Finck walk = FSTART(file, fs);
1074c2c66affSColin Finck
1075c2c66affSColin Finck while (left && (walk >= 2) && (walk < fs->data_clusters + 2)) {
1076c2c66affSColin Finck
1077c2c66affSColin Finck FAT_ENTRY curEntry;
1078c2c66affSColin Finck get_fat(&curEntry, fs->fat, walk, fs);
1079c2c66affSColin Finck
1080c2c66affSColin Finck if (!curEntry.value)
1081c2c66affSColin Finck break;
1082c2c66affSColin Finck
1083c2c66affSColin Finck left--;
1084c2c66affSColin Finck if (prev)
1085c2c66affSColin Finck set_fat(fs, prev, walk);
1086c2c66affSColin Finck prev = walk;
1087c2c66affSColin Finck walk++;
1088c2c66affSColin Finck }
1089c2c66affSColin Finck if (prev)
1090c2c66affSColin Finck set_fat(fs, prev, -1);
1091c2c66affSColin Finck else
1092c2c66affSColin Finck MODIFY_START(file, 0, fs);
1093c2c66affSColin Finck if (left)
1094c2c66affSColin Finck printf("Warning: Did only undelete %lu of %lu cluster%s.\n",
1095c2c66affSColin Finck (unsigned long)clusters - left, (unsigned long)clusters, clusters == 1 ? "" : "s");
1096c2c66affSColin Finck
1097c2c66affSColin Finck }
1098c2c66affSColin Finck
1099c2c66affSColin Finck static void new_dir(void)
1100c2c66affSColin Finck {
1101c2c66affSColin Finck lfn_reset();
1102c2c66affSColin Finck }
1103c2c66affSColin Finck
1104c2c66affSColin Finck /**
1105c2c66affSColin Finck * Create a description for a referenced dentry and insert it in our dentry
1106c2c66affSColin Finck * tree. Then, go check the dentry's cluster chain for bad clusters and
1107c2c66affSColin Finck * cluster loops.
1108c2c66affSColin Finck *
1109c2c66affSColin Finck * @param[inout] fs Information about the filesystem
1110c2c66affSColin Finck * @param[out] chain
1111c2c66affSColin Finck * @param[in] parent Information about parent directory of this file
1112c2c66affSColin Finck * NULL == no parent ('file' is root directory)
1113c2c66affSColin Finck * @param[in] offset Partition-relative byte offset of directory entry of interest
1114c2c66affSColin Finck * 0 == Root directory
1115c2c66affSColin Finck * @param cp
1116c2c66affSColin Finck */
1117c2c66affSColin Finck static void add_file(DOS_FS * fs, DOS_FILE *** chain, DOS_FILE * parent,
1118c2c66affSColin Finck off_t offset, FDSC ** cp)
1119c2c66affSColin Finck {
1120c2c66affSColin Finck DOS_FILE *new;
1121c2c66affSColin Finck DIR_ENT de;
1122c2c66affSColin Finck FD_TYPE type;
1123c2c66affSColin Finck
1124c2c66affSColin Finck if (offset)
1125c2c66affSColin Finck fs_read(offset, sizeof(DIR_ENT), &de);
1126c2c66affSColin Finck else {
1127c2c66affSColin Finck /* Construct a DIR_ENT for the root directory */
1128c2c66affSColin Finck memset(&de, 0, sizeof de);
1129c2c66affSColin Finck memcpy(de.name, " ", MSDOS_NAME);
1130c2c66affSColin Finck de.attr = ATTR_DIR;
1131c2c66affSColin Finck de.start = htole16(fs->root_cluster & 0xffff);
1132c2c66affSColin Finck de.starthi = htole16((fs->root_cluster >> 16) & 0xffff);
1133c2c66affSColin Finck }
1134c2c66affSColin Finck if ((type = file_type(cp, (char *)de.name)) != fdt_none) {
1135c2c66affSColin Finck if (type == fdt_undelete && (de.attr & ATTR_DIR))
1136c2c66affSColin Finck die("Can't undelete directories.");
1137c2c66affSColin Finck file_modify(cp, (char *)de.name);
1138c2c66affSColin Finck fs_write(offset, 1, &de);
1139c2c66affSColin Finck }
1140c2c66affSColin Finck if (IS_FREE(de.name)) {
1141c2c66affSColin Finck lfn_check_orphaned();
1142c2c66affSColin Finck return;
1143c2c66affSColin Finck }
1144c2c66affSColin Finck if (de.attr == VFAT_LN_ATTR) {
1145c2c66affSColin Finck lfn_add_slot(&de, offset);
1146c2c66affSColin Finck return;
1147c2c66affSColin Finck }
1148c2c66affSColin Finck new = qalloc(&mem_queue, sizeof(DOS_FILE));
1149c2c66affSColin Finck new->lfn = lfn_get(&de, &new->lfn_offset);
1150c2c66affSColin Finck new->offset = offset;
1151c2c66affSColin Finck memcpy(&new->dir_ent, &de, sizeof(de));
1152c2c66affSColin Finck new->next = new->first = NULL;
1153c2c66affSColin Finck new->parent = parent;
1154c2c66affSColin Finck if (type == fdt_undelete)
1155c2c66affSColin Finck undelete(fs, new);
1156c2c66affSColin Finck **chain = new;
1157c2c66affSColin Finck *chain = &new->next;
1158c2c66affSColin Finck if (list) {
1159c2c66affSColin Finck printf("Checking file %s", path_name(new));
1160c2c66affSColin Finck if (new->lfn)
1161c2c66affSColin Finck printf(" (%s)", file_name(new->dir_ent.name)); /* (8.3) */
1162c2c66affSColin Finck printf("\n");
1163c2c66affSColin Finck }
1164c2c66affSColin Finck /* Don't include root directory, '.', or '..' in the total file count */
1165c2c66affSColin Finck if (offset &&
1166c2c66affSColin Finck strncmp((const char *)de.name, MSDOS_DOT, MSDOS_NAME) != 0 &&
1167c2c66affSColin Finck strncmp((const char *)de.name, MSDOS_DOTDOT, MSDOS_NAME) != 0)
1168c2c66affSColin Finck ++n_files;
1169c2c66affSColin Finck test_file(fs, new, test); /* Bad cluster check */
1170c2c66affSColin Finck }
1171c2c66affSColin Finck
1172c2c66affSColin Finck static int subdirs(DOS_FS * fs, DOS_FILE * parent, FDSC ** cp);
1173c2c66affSColin Finck
1174c2c66affSColin Finck static int scan_dir(DOS_FS * fs, DOS_FILE * this, FDSC ** cp)
1175c2c66affSColin Finck {
1176c2c66affSColin Finck DOS_FILE **chain;
1177c2c66affSColin Finck int i;
1178c2c66affSColin Finck uint32_t clu_num;
1179c2c66affSColin Finck
1180c2c66affSColin Finck chain = &this->first;
1181c2c66affSColin Finck i = 0;
1182c2c66affSColin Finck clu_num = FSTART(this, fs);
1183c2c66affSColin Finck new_dir();
1184c2c66affSColin Finck while (clu_num > 0 && clu_num != -1) {
1185c2c66affSColin Finck add_file(fs, &chain, this,
1186c2c66affSColin Finck cluster_start(fs, clu_num) + (i % fs->cluster_size), cp);
1187c2c66affSColin Finck i += sizeof(DIR_ENT);
1188c2c66affSColin Finck if (!(i % fs->cluster_size))
1189c2c66affSColin Finck if ((clu_num = next_cluster(fs, clu_num)) == 0 || clu_num == -1)
1190c2c66affSColin Finck break;
1191c2c66affSColin Finck }
1192c2c66affSColin Finck lfn_check_orphaned();
1193c2c66affSColin Finck if (check_dir(fs, &this->first, this->offset))
1194c2c66affSColin Finck return 0;
1195c2c66affSColin Finck if (check_files(fs, this->first))
1196c2c66affSColin Finck return 1;
1197c2c66affSColin Finck return subdirs(fs, this, cp);
1198c2c66affSColin Finck }
1199c2c66affSColin Finck
1200c2c66affSColin Finck /**
1201c2c66affSColin Finck * Recursively scan subdirectories of the specified parent directory.
1202c2c66affSColin Finck *
1203c2c66affSColin Finck * @param[inout] fs Information about the filesystem
1204c2c66affSColin Finck * @param[in] parent Identifies the directory to scan
1205c2c66affSColin Finck * @param[in] cp
1206c2c66affSColin Finck *
1207c2c66affSColin Finck * @return 0 Success
1208c2c66affSColin Finck * @return 1 Error
1209c2c66affSColin Finck */
1210c2c66affSColin Finck static int subdirs(DOS_FS * fs, DOS_FILE * parent, FDSC ** cp)
1211c2c66affSColin Finck {
1212c2c66affSColin Finck DOS_FILE *walk;
1213c2c66affSColin Finck
1214c2c66affSColin Finck for (walk = parent ? parent->first : root; walk; walk = walk->next)
1215c2c66affSColin Finck if (walk->dir_ent.attr & ATTR_DIR)
1216c2c66affSColin Finck if (strncmp((const char *)walk->dir_ent.name, MSDOS_DOT, MSDOS_NAME)
1217c2c66affSColin Finck && strncmp((const char *)walk->dir_ent.name, MSDOS_DOTDOT,
1218c2c66affSColin Finck MSDOS_NAME))
1219c2c66affSColin Finck if (scan_dir(fs, walk, file_cd(cp, (char *)walk->dir_ent.name)))
1220c2c66affSColin Finck return 1;
1221c2c66affSColin Finck return 0;
1222c2c66affSColin Finck }
1223c2c66affSColin Finck
1224c2c66affSColin Finck /**
1225c2c66affSColin Finck * Scan all directory and file information for errors.
1226c2c66affSColin Finck *
1227c2c66affSColin Finck * @param[inout] fs Information about the filesystem
1228c2c66affSColin Finck *
1229c2c66affSColin Finck * @return 0 Success
1230c2c66affSColin Finck * @return 1 Error
1231c2c66affSColin Finck */
1232c2c66affSColin Finck int scan_root(DOS_FS * fs)
1233c2c66affSColin Finck {
1234c2c66affSColin Finck DOS_FILE **chain;
1235c2c66affSColin Finck int i;
1236c2c66affSColin Finck
1237c2c66affSColin Finck root = NULL;
1238c2c66affSColin Finck chain = &root;
1239c2c66affSColin Finck new_dir();
1240c2c66affSColin Finck if (fs->root_cluster) {
1241c2c66affSColin Finck add_file(fs, &chain, NULL, 0, &fp_root);
1242c2c66affSColin Finck } else {
1243c2c66affSColin Finck for (i = 0; i < fs->root_entries; i++)
1244c2c66affSColin Finck add_file(fs, &chain, NULL, fs->root_start + i * sizeof(DIR_ENT),
1245c2c66affSColin Finck &fp_root);
1246c2c66affSColin Finck }
1247c2c66affSColin Finck lfn_check_orphaned();
1248c2c66affSColin Finck (void)check_dir(fs, &root, 0);
1249c2c66affSColin Finck if (check_files(fs, root))
1250c2c66affSColin Finck return 1;
1251c2c66affSColin Finck return subdirs(fs, NULL, &fp_root);
1252c2c66affSColin Finck }
1253