ReactOS 0.4.16-dev-340-g0540c21
check.c File Reference
#include "vfatlib.h"
#include <debug.h>
Include dependency graph for check.c:

Go to the source code of this file.

Macros

#define NDEBUG
 
#define PATH_NAME_MAX   1023
 
#define FSTART(p, fs)
 
#define MODIFY(p, i, v)
 
#define MODIFY_START(p, v, fs)
 

Functions

off_t alloc_rootdir_entry (DOS_FS *fs, DIR_ENT *de, const char *pattern, int gen_name)
 
static charpath_name (DOS_FILE *file)
 
static time_t date_dos2unix (unsigned short time, unsigned short date)
 
static charfile_stat (DOS_FILE *file)
 
static int bad_name (DOS_FILE *file)
 
static void lfn_remove (off_t from, off_t to)
 
static void drop_file (DOS_FS *fs, DOS_FILE *file)
 
static void truncate_file (DOS_FS *fs, DOS_FILE *file, uint32_t clusters)
 
static void auto_rename (DOS_FILE *file)
 
static void rename_file (DOS_FILE *file)
 
static int handle_dot (DOS_FS *fs, DOS_FILE *file, int dots)
 
static int check_file (DOS_FS *fs, DOS_FILE *file)
 
static int check_files (DOS_FS *fs, DOS_FILE *start)
 
static int check_dir (DOS_FS *fs, DOS_FILE **root, int dots)
 
static void test_file (DOS_FS *fs, DOS_FILE *file, int read_test)
 
static void undelete (DOS_FS *fs, DOS_FILE *file)
 
static void new_dir (void)
 
static void add_file (DOS_FS *fs, DOS_FILE ***chain, DOS_FILE *parent, off_t offset, FDSC **cp)
 
static int subdirs (DOS_FS *fs, DOS_FILE *parent, FDSC **cp)
 
static int scan_dir (DOS_FS *fs, DOS_FILE *this, FDSC **cp)
 
int scan_root (DOS_FS *fs)
 

Variables

static DOS_FILEroot
 
static const int day_n []
 

Macro Definition Documentation

◆ FSTART

#define FSTART (   p,
  fs 
)
Value:
((uint32_t)le16toh(p->dir_ent.start) | \
(fs->fat_bits == 32 ? le16toh(p->dir_ent.starthi) << 16 : 0))
GLfloat GLfloat p
Definition: glext.h:8902
#define uint32_t
Definition: nsiface.idl:61
Definition: ffs.h:70

Definition at line 40 of file check.c.

◆ MODIFY

#define MODIFY (   p,
  i,
  v 
)
Value:
do { \
if (p->offset) { \
p->dir_ent.i = v; \
fs_write(p->offset+offsetof(DIR_ENT,i), \
sizeof(p->dir_ent.i),&p->dir_ent.i); \
} \
} while(0)
const GLdouble * v
Definition: gl.h:2040
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define offsetof(TYPE, MEMBER)

Definition at line 44 of file check.c.

◆ MODIFY_START

#define MODIFY_START (   p,
  v,
  fs 
)
Value:
do { \
uint32_t __v = (v); \
if (!p->offset) { \
/* writing to fake entry for FAT32 root dir */ \
if (!__v) die("Oops, deleting FAT32 root dir!"); \
fs->root_cluster = __v; \
p->dir_ent.start = htole16(__v&0xffff); \
p->dir_ent.starthi = htole16(__v>>16); \
__v = htole32(__v); \
fs_write(offsetof(struct boot_sector,root_cluster), \
sizeof(((struct boot_sector *)0)->root_cluster), \
&__v); \
} \
else { \
MODIFY(p,start,htole16((__v)&0xffff)); \
if (fs->fat_bits == 32) \
MODIFY(p,starthi,htole16((__v)>>16)); \
} \
} while(0)
UINT32 uint32_t
Definition: types.h:75
uint32_t root_cluster
Definition: fsck.fat.h:20
GLuint start
Definition: gl.h:1545
__u16 starthi
Definition: mkdosfs.c:7
#define die(str)
Definition: mkdosfs.c:347
#define htole16(x)
Definition: storage32.h:546
#define htole32(x)
Definition: storage32.h:543

Definition at line 53 of file check.c.

◆ NDEBUG

#define NDEBUG

Definition at line 30 of file check.c.

◆ PATH_NAME_MAX

#define PATH_NAME_MAX   1023

Definition at line 35 of file check.c.

Function Documentation

◆ add_file()

static void add_file ( DOS_FS fs,
DOS_FILE ***  chain,
DOS_FILE parent,
off_t  offset,
FDSC **  cp 
)
static

Create a description for a referenced dentry and insert it in our dentry tree. Then, go check the dentry's cluster chain for bad clusters and cluster loops.

Parameters
[in,out]fsInformation about the filesystem
[out]chain
[in]parentInformation about parent directory of this file NULL == no parent ('file' is root directory)
[in]offsetPartition-relative byte offset of directory entry of interest 0 == Root directory
cp

Definition at line 1117 of file check.c.

1119{
1120 DOS_FILE *new;
1121 DIR_ENT de;
1122 FD_TYPE type;
1123
1124 if (offset)
1125 fs_read(offset, sizeof(DIR_ENT), &de);
1126 else {
1127 /* Construct a DIR_ENT for the root directory */
1128 memset(&de, 0, sizeof de);
1129 memcpy(de.name, " ", MSDOS_NAME);
1130 de.attr = ATTR_DIR;
1131 de.start = htole16(fs->root_cluster & 0xffff);
1132 de.starthi = htole16((fs->root_cluster >> 16) & 0xffff);
1133 }
1134 if ((type = file_type(cp, (char *)de.name)) != fdt_none) {
1135 if (type == fdt_undelete && (de.attr & ATTR_DIR))
1136 die("Can't undelete directories.");
1137 file_modify(cp, (char *)de.name);
1138 fs_write(offset, 1, &de);
1139 }
1140 if (IS_FREE(de.name)) {
1142 return;
1143 }
1144 if (de.attr == VFAT_LN_ATTR) {
1145 lfn_add_slot(&de, offset);
1146 return;
1147 }
1148 new = qalloc(&mem_queue, sizeof(DOS_FILE));
1149 new->lfn = lfn_get(&de, &new->lfn_offset);
1150 new->offset = offset;
1151 memcpy(&new->dir_ent, &de, sizeof(de));
1152 new->next = new->first = NULL;
1153 new->parent = parent;
1154 if (type == fdt_undelete)
1155 undelete(fs, new);
1156 **chain = new;
1157 *chain = &new->next;
1158 if (list) {
1159 printf("Checking file %s", path_name(new));
1160 if (new->lfn)
1161 printf(" (%s)", file_name(new->dir_ent.name)); /* (8.3) */
1162 printf("\n");
1163 }
1164 /* Don't include root directory, '.', or '..' in the total file count */
1165 if (offset &&
1166 strncmp((const char *)de.name, MSDOS_DOT, MSDOS_NAME) != 0 &&
1167 strncmp((const char *)de.name, MSDOS_DOTDOT, MSDOS_NAME) != 0)
1168 ++n_files;
1169 test_file(fs, new, test); /* Bad cluster check */
1170}
int strncmp(const char *String1, const char *String2, ACPI_SIZE Count)
Definition: utclib.c:534
Definition: list.h:37
#define NULL
Definition: types.h:112
r parent
Definition: btrfs.c:3010
#define printf
Definition: freeldr.h:97
#define VFAT_LN_ATTR
Definition: fsck.fat.h:78
static char * path_name(DOS_FILE *file)
Definition: check.c:208
static void undelete(DOS_FS *fs, DOS_FILE *file)
Definition: check.c:1065
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
GLintptr offset
Definition: glext.h:5920
void lfn_add_slot(DIR_ENT *de, off_t dir_offset)
Definition: lfn.c:206
void lfn_check_orphaned(void)
Definition: lfn.c:517
char * lfn_get(DIR_ENT *de, off_t *lfn_offset)
Definition: lfn.c:418
FD_TYPE
Definition: file.h:28
@ fdt_none
Definition: file.h:28
@ fdt_undelete
Definition: file.h:28
POINT cp
Definition: magnifier.c:59
#define ATTR_DIR
Definition: mkdosfs.c:370
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
static IBackgroundCopyFile * test_file
Definition: file.c:39
static LPCWSTR file_name
Definition: protocol.c:147
#define MSDOS_DOTDOT
Definition: msdos_fs.h:48
#define MSDOS_DOT
Definition: msdos_fs.h:47
#define IS_FREE(n)
Definition: msdos_fs.h:44
#define MSDOS_NAME
Definition: msdos_fs.h:46
#define mem_queue
Definition: rosglue.h:44
#define n_files
Definition: rosglue.h:43
#define test
Definition: rosglue.h:37
void * qalloc(void **root, int size)
Definition: common.c:139
void file_modify(FDSC **curr, char *fixed)
Definition: file.c:230
FD_TYPE file_type(FDSC **curr, char *fixed)
Definition: file.c:221
void fs_read(off_t pos, int size, void *data)
Definition: io.c:282
void fs_write(off_t pos, int size, void *data)
Definition: io.c:344
#define memset(x, y, z)
Definition: compat.h:39
char * name
Definition: compiler.c:66
struct sock * chain
Definition: tcpcore.h:1
#define new(TYPE, numElems)
Definition: treelist.c:54

Referenced by scan_dir(), and scan_root().

◆ alloc_rootdir_entry()

off_t alloc_rootdir_entry ( DOS_FS fs,
DIR_ENT *  de,
const char pattern,
int  gen_name 
)

Definition at line 74 of file check.c.

75{
76 static int curr_num = 0;
78
79 if (fs->root_cluster) {
80 DIR_ENT d2;
81 int i = 0, got = 0;
82 uint32_t clu_num, prev = 0;
83 off_t offset2;
84
85 clu_num = fs->root_cluster;
86 offset = cluster_start(fs, clu_num);
87 while (clu_num > 0 && clu_num != -1) {
88 fs_read(offset, sizeof(DIR_ENT), &d2);
89 if (IS_FREE(d2.name) && d2.attr != VFAT_LN_ATTR) {
90 got = 1;
91 break;
92 }
93 i += sizeof(DIR_ENT);
94 offset += sizeof(DIR_ENT);
95 if ((i % fs->cluster_size) == 0) {
96 prev = clu_num;
97 if ((clu_num = next_cluster(fs, clu_num)) == 0 || clu_num == -1)
98 break;
99 offset = cluster_start(fs, clu_num);
100 }
101 }
102 if (!got) {
103 /* no free slot, need to extend root dir: alloc next free cluster
104 * after previous one */
105 if (!prev)
106 die("Root directory has no cluster allocated!");
107 for (clu_num = prev + 1; clu_num != prev; clu_num++) {
109
110 if (clu_num >= fs->data_clusters + 2)
111 clu_num = 2;
112 get_fat(&entry, fs->fat, clu_num, fs);
113 if (!entry.value)
114 break;
115 }
116 if (clu_num == prev)
117 die("Root directory full and no free cluster");
118 set_fat(fs, prev, clu_num);
119 set_fat(fs, clu_num, -1);
120 set_owner(fs, clu_num, get_owner(fs, fs->root_cluster));
121 /* clear new cluster */
122 memset(&d2, 0, sizeof(d2));
123 offset = cluster_start(fs, clu_num);
124 for (i = 0; i < fs->cluster_size; i += sizeof(DIR_ENT))
125 fs_write(offset + i, sizeof(d2), &d2);
126 }
127 memset(de, 0, sizeof(DIR_ENT));
128 if (gen_name) {
129 while (1) {
130 char expanded[12];
131 sprintf(expanded, pattern, curr_num);
132 memcpy(de->name, expanded, MSDOS_NAME);
133 clu_num = fs->root_cluster;
134 i = 0;
135 offset2 = cluster_start(fs, clu_num);
136 while (clu_num > 0 && clu_num != -1) {
137 fs_read(offset2, sizeof(DIR_ENT), &d2);
138 if (offset2 != offset &&
139 !strncmp((const char *)d2.name, (const char *)de->name,
140 MSDOS_NAME))
141 break;
142 i += sizeof(DIR_ENT);
143 offset2 += sizeof(DIR_ENT);
144 if ((i % fs->cluster_size) == 0) {
145 if ((clu_num = next_cluster(fs, clu_num)) == 0 ||
146 clu_num == -1)
147 break;
148 offset2 = cluster_start(fs, clu_num);
149 }
150 }
151 if (clu_num == 0 || clu_num == -1)
152 break;
153 if (++curr_num >= 10000)
154 die("Unable to create unique name");
155 }
156 } else {
157 memcpy(de->name, pattern, MSDOS_NAME);
158 }
159 } else {
160 DIR_ENT *root;
161 int next_free = 0, scan;
162
163 root = alloc(fs->root_entries * sizeof(DIR_ENT));
164 fs_read(fs->root_start, fs->root_entries * sizeof(DIR_ENT), root);
165
166 while (next_free < fs->root_entries)
167 if (IS_FREE(root[next_free].name) &&
168 root[next_free].attr != VFAT_LN_ATTR)
169 break;
170 else
171 next_free++;
172 if (next_free == fs->root_entries)
173 die("Root directory is full.");
174 offset = fs->root_start + next_free * sizeof(DIR_ENT);
175 memset(de, 0, sizeof(DIR_ENT));
176 if (gen_name) {
177 while (1) {
178 char expanded[12];
179 sprintf(expanded, pattern, curr_num);
180 memcpy(de->name, expanded, MSDOS_NAME);
181 for (scan = 0; scan < fs->root_entries; scan++)
182 if (scan != next_free &&
183 !strncmp((const char *)root[scan].name,
184 (const char *)de->name, MSDOS_NAME))
185 break;
186 if (scan == fs->root_entries)
187 break;
188 if (++curr_num >= 10000)
189 die("Unable to create unique name");
190 }
191 } else {
192 memcpy(de->name, pattern, MSDOS_NAME);
193 }
194 free(root);
195 }
196 ++n_files;
197 return offset;
198}
#define free
Definition: debug_ros.c:5
static HRESULT get_owner(VARIANT *user, VARIANT *domain, VARIANT *retval)
Definition: process.c:34
__kernel_off_t off_t
Definition: linux.h:201
static DOS_FILE * root
Definition: check.c:37
GLubyte * pattern
Definition: glext.h:7787
uint32_t entry
Definition: isohybrid.c:63
#define sprintf(buf, format,...)
Definition: sprintf.c:55
const char * root_entries[]
Definition: netreg.cpp:25
#define alloc
Definition: rosglue.h:13
uint32_t next_cluster(DOS_FS *fs, uint32_t cluster)
Definition: fat.c:276
void set_owner(DOS_FS *fs, uint32_t cluster, DOS_FILE *owner)
Definition: fat.c:303
off_t cluster_start(DOS_FS *fs, uint32_t cluster)
Definition: fat.c:289
void get_fat(FAT_ENTRY *entry, void *fat, uint32_t cluster, DOS_FS *fs)
Definition: fat.c:41
void set_fat(DOS_FS *fs, uint32_t cluster, int32_t new)
Definition: fat.c:189
Definition: fsck.fat.h:192
Definition: cookie.c:202
Definition: name.c:39
WCHAR * name
Definition: name.c:42

Referenced by reclaim_file(), and write_volume_label().

◆ auto_rename()

static void auto_rename ( DOS_FILE file)
static

Definition at line 419 of file check.c.

420{
421 DOS_FILE *first, *walk;
423
424 if (!file->offset)
425 return; /* cannot rename FAT32 root dir */
426 first = file->parent ? file->parent->first : root;
427 number = 0;
428 while (1) {
429 char num[8];
430 sprintf(num, "%07lu", (unsigned long)number);
431 memcpy(file->dir_ent.name, "FSCK", 4);
432 memcpy(file->dir_ent.name + 4, num, 7);
433 for (walk = first; walk; walk = walk->next)
434 if (walk != file
435 && !strncmp((const char *)walk->dir_ent.name,
436 (const char *)file->dir_ent.name, MSDOS_NAME))
437 break;
438 if (!walk) {
439 if (file->dir_ent.lcase & FAT_NO_83NAME) {
440 /* as we only assign a new 8.3 filename, reset flag that 8.3 name is not
441 present */
442 file->dir_ent.lcase &= ~FAT_NO_83NAME;
443 /* reset the attributes, only keep DIR and VOLUME */
444 file->dir_ent.attr &= ~(ATTR_DIR | ATTR_VOLUME);
445 fs_write(file->offset, MSDOS_NAME + 2, &file->dir_ent);
446 } else {
447 fs_write(file->offset, MSDOS_NAME, file->dir_ent.name);
448 }
449 if (file->lfn)
450 lfn_fix_checksum(file->lfn_offset, file->offset,
451 (const char *)file->dir_ent.name);
452 return;
453 }
454 number++;
455 if (number > 9999999) {
456 die("Too many files need repair.");
457 }
458 }
459 die("Can't generate a unique name.");
460}
#define FAT_NO_83NAME
Definition: fsck.fat.h:238
const GLint * first
Definition: glext.h:5794
GLuint GLuint num
Definition: glext.h:9618
void lfn_fix_checksum(off_t from, off_t to, const char *short_name)
Definition: lfn.c:181
#define ATTR_VOLUME
Definition: mkdosfs.c:369
static unsigned int number
Definition: dsound.c:1479
struct _dos_file * next
Definition: fsck.fat.h:188
DIR_ENT dir_ent
Definition: fsck.fat.h:183
Definition: fci.c:127
cab_ULONG offset
Definition: fci.c:130
char name[1]
Definition: fci.c:135

Referenced by check_dir(), and handle_dot().

◆ bad_name()

static int bad_name ( DOS_FILE file)
static

Definition at line 296 of file check.c.

297{
298 int i, spc, suspicious = 0;
299 const char *bad_chars = atari_format ? "*?\\/:" : "*?<>|\"\\/:";
300 const unsigned char *name = file->dir_ent.name;
301 const unsigned char *ext = name + 8;
302
303 /* Do not complain about (and auto-correct) the extended attribute files
304 * of OS/2. */
305 if (strncmp((const char *)name, "EA DATA SF", 11) == 0 ||
306 strncmp((const char *)name, "WP ROOT SF", 11) == 0)
307 return 0;
308
309 /* check if we have neither a long filename nor a short name */
310 if ((file->lfn == NULL) && (file->dir_ent.lcase & FAT_NO_83NAME)) {
311 return 1;
312 }
313
314 /* don't complain about the dummy 11 bytes used by patched Linux
315 kernels */
316 if (file->dir_ent.lcase & FAT_NO_83NAME)
317 return 0;
318
319 for (i = 0; i < MSDOS_NAME; i++) {
320 if (name[i] < ' ' || name[i] == 0x7f)
321 return 1;
322 if (name[i] > 0x7f)
323 ++suspicious;
324 if (strchr(bad_chars, name[i]))
325 return 1;
326 }
327
328 spc = 0;
329 for (i = 0; i < 8; i++) {
330 if (name[i] == ' ')
331 spc = 1;
332 else if (spc)
333 /* non-space after a space not allowed, space terminates the name
334 * part */
335 return 1;
336 }
337
338 spc = 0;
339 for (i = 0; i < 3; i++) {
340 if (ext[i] == ' ')
341 spc = 1;
342 else if (spc)
343 /* non-space after a space not allowed, space terminates the ext
344 * part */
345 return 1;
346 }
347
348 /* Under GEMDOS, chars >= 128 are never allowed. */
349 if (atari_format && suspicious)
350 return 1;
351
352#ifdef __REACTOS__ // Old !!!!!!!!!!!!!!!
353
354 /* Only complain about too much suspicious chars in interactive mode,
355 * never correct them automatically. The chars are all basically ok, so we
356 * shouldn't auto-correct such names. */
357 if (interactive && suspicious > 6)
358 return 1;
359 return 0;
360
361#else
362
363 /* Under MS-DOS and Windows, chars >= 128 in short names are valid
364 * (but these characters can be visualised differently depending on
365 * local codepage: CP437, CP866, etc). The chars are all basically ok,
366 * so we shouldn't auto-correct such names. */
367 return 0;
368
369#endif
370}
char * strchr(const char *String, int ch)
Definition: utclib.c:501
static const WCHAR *const ext[]
Definition: module.c:53
#define atari_format
Definition: rosglue.h:41
#define interactive
Definition: rosglue.h:34

Referenced by check_dir().

◆ check_dir()

static int check_dir ( DOS_FS fs,
DOS_FILE **  root,
int  dots 
)
static

Definition at line 826 of file check.c.

827{
828 DOS_FILE *parent, **walk, **scan;
829 int dot, dotdot, skip, redo;
830 int good, bad;
831
832 if (!*root)
833 return 0;
834 parent = (*root)->parent;
835 good = bad = 0;
836 for (walk = root; *walk; walk = &(*walk)->next)
837 if (bad_name(*walk))
838 bad++;
839 else
840 good++;
841 if (*root && parent && good + bad > 4 && bad > good / 2) {
842 printf("%s\n Has a large number of bad entries. (%d/%d)\n",
843 path_name(parent), bad, good + bad);
844 if (!dots)
845 printf(" Not dropping root directory.\n");
846#ifndef __REACTOS__
847 else if (!interactive)
848#else
849 else if (!interactive || !rw)
850#endif
851 printf(" Not dropping it in auto-mode.\n");
852 else if (get_key("yn", "Drop directory ? (y/n)") == 'y') {
855 /* buglet: deleted directory stays in the list. */
856 return 1;
857 }
858 }
859 dot = dotdot = redo = 0;
860 walk = root;
861 while (*walk) {
862 if (!strncmp
863 ((const char *)((*walk)->dir_ent.name), MSDOS_DOT, MSDOS_NAME)
864 || !strncmp((const char *)((*walk)->dir_ent.name), MSDOS_DOTDOT,
865 MSDOS_NAME)) {
866 if (handle_dot(fs, *walk, dots)) {
867 *walk = (*walk)->next;
868 continue;
869 }
870 if (!strncmp
871 ((const char *)((*walk)->dir_ent.name), MSDOS_DOT, MSDOS_NAME))
872 dot++;
873 else
874 dotdot++;
875 }
876 if (!((*walk)->dir_ent.attr & ATTR_VOLUME) && bad_name(*walk)) {
877#ifndef __REACTOS__
878 puts(path_name(*walk));
879 printf(" Bad short file name (%s).\n",
880 file_name((*walk)->dir_ent.name));
881#else
882 printf("%s\n Bad short file name (%s).\n",
883 path_name(*walk), file_name((*walk)->dir_ent.name));
884#endif
885 if (interactive)
886 printf("1) Drop file\n2) Rename file\n3) Auto-rename\n"
887 "4) Keep it\n");
888 else
889#ifdef __REACTOS__
890 if (rw)
891#endif
892 printf(" Auto-renaming it.\n");
893#ifdef __REACTOS__
894 if (rw || interactive) {
895#endif
896 switch (interactive ? get_key("1234", "?") : '3') {
897 case '1':
898 drop_file(fs, *walk);
899 walk = &(*walk)->next;
900 continue;
901 case '2':
902 rename_file(*walk);
903 redo = 1;
904 break;
905 case '3':
906 auto_rename(*walk);
907 printf(" Renamed to %s\n", file_name((*walk)->dir_ent.name));
908 break;
909 case '4':
910 break;
911#ifdef __REACTOS__
912 }
913#endif
914 }
915 }
916 /* don't check for duplicates of the volume label */
917 if (!((*walk)->dir_ent.attr & ATTR_VOLUME)) {
918 scan = &(*walk)->next;
919 skip = 0;
920 while (*scan && !skip) {
921 if (!((*scan)->dir_ent.attr & ATTR_VOLUME) &&
922 !memcmp((*walk)->dir_ent.name, (*scan)->dir_ent.name,
923 MSDOS_NAME)) {
924 printf("%s\n Duplicate directory entry.\n First %s\n",
925 path_name(*walk), file_stat(*walk));
926 printf(" Second %s\n", file_stat(*scan));
927 if (interactive)
928 printf
929 ("1) Drop first\n2) Drop second\n3) Rename first\n"
930 "4) Rename second\n5) Auto-rename first\n"
931 "6) Auto-rename second\n");
932 else
933#ifdef __REACTOS__
934 if (rw)
935#endif
936 printf(" Auto-renaming second.\n");
937#ifdef __REACTOS__
938 if (rw || interactive) {
939#endif
940 switch (interactive ? get_key("123456", "?") : '6') {
941 case '1':
942 drop_file(fs, *walk);
943 *walk = (*walk)->next;
944 skip = 1;
945 break;
946 case '2':
947 drop_file(fs, *scan);
948 *scan = (*scan)->next;
949 continue;
950 case '3':
951 rename_file(*walk);
952 printf(" Renamed to %s\n", path_name(*walk));
953 redo = 1;
954 break;
955 case '4':
956 rename_file(*scan);
957 printf(" Renamed to %s\n", path_name(*walk));
958 redo = 1;
959 break;
960 case '5':
961 auto_rename(*walk);
962 printf(" Renamed to %s\n",
963 file_name((*walk)->dir_ent.name));
964 break;
965 case '6':
966 auto_rename(*scan);
967 printf(" Renamed to %s\n",
968 file_name((*scan)->dir_ent.name));
969 break;
970#ifdef __REACTOS__
971 }
972#endif
973 }
974 }
975 scan = &(*scan)->next;
976 }
977 if (skip)
978 continue;
979 }
980 if (!redo)
981 walk = &(*walk)->next;
982 else {
983 walk = root;
984 dot = dotdot = redo = 0;
985 }
986 }
987 if (dots && !dot)
988 printf("%s\n \".\" is missing. Can't fix this yet.\n",
990 if (dots && !dotdot)
991 printf("%s\n \"..\" is missing. Can't fix this yet.\n",
993 return 0;
994}
int memcmp(void *Buffer1, void *Buffer2, ACPI_SIZE Count)
Definition: utclib.c:112
#define skip(...)
Definition: atltest.h:64
int puts(const char *string)
Definition: crtsupp.c:23
static void drop_file(DOS_FS *fs, DOS_FILE *file)
Definition: check.c:388
static void rename_file(DOS_FILE *file)
Definition: check.c:462
#define MODIFY(p, i, v)
Definition: check.c:44
static int bad_name(DOS_FILE *file)
Definition: check.c:296
static void truncate_file(DOS_FS *fs, DOS_FILE *file, uint32_t clusters)
Definition: check.c:401
static void auto_rename(DOS_FILE *file)
Definition: check.c:419
static char * file_stat(DOS_FILE *file)
Definition: check.c:279
static int handle_dot(DOS_FS *fs, DOS_FILE *file, int dots)
Definition: check.c:511
#define DELETED_FLAG
Definition: msdos_fs.h:43
#define rw
Definition: rosglue.h:38
char get_key(const char *valid, const char *prompt)
Definition: common.c:184

Referenced by check_directory(), scan_dir(), and scan_root().

◆ check_file()

static int check_file ( DOS_FS fs,
DOS_FILE file 
)
static

Definition at line 560 of file check.c.

561{
562 DOS_FILE *owner;
563 int restart;
564 uint32_t expect, curr, this, clusters, prev, walk, clusters2;
565
566 if (file->dir_ent.attr & ATTR_DIR) {
567 if (le32toh(file->dir_ent.size)) {
568#ifndef __REACTOS__
569 printf("%s\n Directory has non-zero size. Fixing it.\n",
570 path_name(file));
571#else
572 printf("%s\n Directory has non-zero size.%s\n",
573 path_name(file), (rw) ? " Fixing it." : "");
574 if (rw)
575#endif
576 MODIFY(file, size, htole32(0));
577 }
578 if (file->parent
579 && !strncmp((const char *)file->dir_ent.name, MSDOS_DOT,
580 MSDOS_NAME)) {
581 expect = FSTART(file->parent, fs);
582 if (FSTART(file, fs) != expect) {
583 printf("%s\n Start (%lu) does not point to parent (%lu)\n",
584 path_name(file), (unsigned long)FSTART(file, fs), (long)expect);
585#ifdef __REACTOS__
586 if (rw)
587#endif
589 }
590 return 0;
591 }
592 if (file->parent
593 && !strncmp((const char *)file->dir_ent.name, MSDOS_DOTDOT,
594 MSDOS_NAME)) {
595 expect =
596 file->parent->parent ? FSTART(file->parent->parent, fs) : 0;
597 if (fs->root_cluster && expect == fs->root_cluster)
598 expect = 0;
599 if (FSTART(file, fs) != expect) {
600 printf("%s\n Start (%lu) does not point to .. (%lu)\n",
601 path_name(file), (unsigned long)FSTART(file, fs), (unsigned long)expect);
602#ifdef __REACTOS__
603 if (rw)
604#endif
606 }
607 return 0;
608 }
609 if (FSTART(file, fs) == 0) {
610#ifndef __REACTOS__
611 printf("%s\n Start does point to root directory. Deleting dir. \n",
612 path_name(file));
613#else
614 printf("%s\n Start does point to root directory.%s\n",
615 path_name(file), (rw) ? " Deleting dir. " : "");
616 if (rw)
617#endif
619 return 0;
620 }
621 }
622 if (FSTART(file, fs) == 1) {
623 printf("%s\n Bad start cluster 1. Truncating file.\n",
624 path_name(file));
625 if (!file->offset)
626 die("Bad FAT32 root directory! (bad start cluster 1)\n");
627#ifdef __REACTOS__
628 if (rw)
629#endif
630 MODIFY_START(file, 0, fs);
631 }
632 if (FSTART(file, fs) >= fs->data_clusters + 2) {
633 printf
634#ifndef __REACTOS__
635 ("%s\n Start cluster beyond limit (%lu > %lu). Truncating file.\n",
636 path_name(file), (unsigned long)FSTART(file, fs),
637 (unsigned long)(fs->data_clusters + 1));
638#else
639 ("%s\n Start cluster beyond limit (%lu > %lu).%s\n",
640 path_name(file), (unsigned long)FSTART(file, fs),
641 (unsigned long)(fs->data_clusters + 1),
642 (rw) ? " Truncating file." : "");
643#endif
644 if (!file->offset)
645 die("Bad FAT32 root directory! (start cluster beyond limit: %lu > %lu)\n",
646 (unsigned long)FSTART(file, fs),
647 (unsigned long)(fs->data_clusters + 1));
648#ifdef __REACTOS__
649 if (rw)
650#endif
651 MODIFY_START(file, 0, fs);
652 }
653 clusters = prev = 0;
654 for (curr = FSTART(file, fs) ? FSTART(file, fs) :
655 -1; curr != -1; curr = next_cluster(fs, curr)) {
656 FAT_ENTRY curEntry;
657 get_fat(&curEntry, fs->fat, curr, fs);
658
659 if (!curEntry.value || bad_cluster(fs, curr)) {
660#ifndef __REACTOS__
661 printf("%s\n Contains a %s cluster (%lu). Assuming EOF.\n",
662 path_name(file), curEntry.value ? "bad" : "free", (unsigned long)curr);
663#else
664 printf("%s\n Contains a %s cluster (%lu).%s\n",
665 path_name(file), curEntry.value ? "bad" : "free", (unsigned long)curr,
666 (rw) ? " Assuming EOF." : "");
667#endif
668 if (prev)
669#ifdef __REACTOS__
670 {
671 if (rw)
672#endif
673 set_fat(fs, prev, -1);
674#ifdef __REACTOS__
675 }
676#endif
677 else if (!file->offset)
678 die("FAT32 root dir starts with a bad cluster!");
679 else
680#ifdef __REACTOS__
681 if (rw)
682#endif
683 MODIFY_START(file, 0, fs);
684 break;
685 }
686 if (!(file->dir_ent.attr & ATTR_DIR) && le32toh(file->dir_ent.size) <=
687 (uint64_t)clusters * fs->cluster_size) {
688#ifdef __REACTOS__
689 if (rw) {
690#endif
691 printf
692 ("%s\n File size is %u bytes, cluster chain length is > %llu "
693 "bytes.\n Truncating file to %u bytes.\n", path_name(file),
694 le32toh(file->dir_ent.size),
695 (unsigned long long)clusters * fs->cluster_size,
696 le32toh(file->dir_ent.size));
697 truncate_file(fs, file, clusters);
698#ifdef __REACTOS__
699 } else {
700 printf
701 ("%s\n File size is %u bytes, cluster chain length is > %llu "
702 "bytes.\n", path_name(file),
703 le32toh(file->dir_ent.size),
704 (unsigned long long)clusters * fs->cluster_size);
705 }
706#endif
707 break;
708 }
709 if ((owner = get_owner(fs, curr))) {
710 int do_trunc = 0;
711 printf("%s and\n", path_name(owner));
712 printf("%s\n share clusters.\n", path_name(file));
713 clusters2 = 0;
714 for (walk = FSTART(owner, fs); walk > 0 && walk != -1; walk =
715 next_cluster(fs, walk))
716 if (walk == curr)
717 break;
718 else
719 clusters2++;
720 restart = file->dir_ent.attr & ATTR_DIR;
721#ifndef __REACTOS__
722 if (!owner->offset) {
723#else
724 if (!owner->offset && rw) {
725#endif
726 printf(" Truncating second to %llu bytes because first "
727 "is FAT32 root dir.\n",
728 (unsigned long long)clusters * fs->cluster_size);
729 do_trunc = 2;
730#ifndef __REACTOS__
731 } else if (!file->offset) {
732#else
733 } else if (!file->offset && rw) {
734#endif
735 printf(" Truncating first to %llu bytes because second "
736 "is FAT32 root dir.\n",
737 (unsigned long long)clusters2 * fs->cluster_size);
738 do_trunc = 1;
739 } else if (interactive)
740 printf("1) Truncate first to %llu bytes%s\n"
741 "2) Truncate second to %llu bytes\n",
742 (unsigned long long)clusters2 * fs->cluster_size,
743 restart ? " and restart" : "",
744 (unsigned long long)clusters * fs->cluster_size);
745 else
746#ifdef __REACTOS__
747 if (rw)
748#endif
749 printf(" Truncating second to %llu bytes.\n",
750 (unsigned long long)clusters * fs->cluster_size);
751#ifndef __REACTOS__
752 if (do_trunc != 2
753 && (do_trunc == 1
754#else
755 if ((do_trunc != 2 && rw)
756 && ((do_trunc == 1 && rw)
757#endif
758 || (interactive && get_key("12", "?") == '1'))) {
759 prev = 0;
760 clusters = 0;
761 for (this = FSTART(owner, fs); this > 0 && this != -1; this =
762 next_cluster(fs, this)) {
763 if (this == curr) {
764 if (prev)
765 set_fat(fs, prev, -1);
766 else
767 MODIFY_START(owner, 0, fs);
768 MODIFY(owner, size,
769 htole32((uint64_t)clusters *
770 fs->cluster_size));
771 if (restart)
772 return 1;
773 while (this > 0 && this != -1) {
774 set_owner(fs, this, NULL);
775 this = next_cluster(fs, this);
776 }
777 this = curr;
778 break;
779 }
780 clusters++;
781 prev = this;
782 }
783 if (this != curr)
784 die("Internal error: didn't find cluster %d in chain"
785 " starting at %d", curr, FSTART(owner, fs));
786 } else {
787 if (prev)
788 set_fat(fs, prev, -1);
789 else
790 MODIFY_START(file, 0, fs);
791 break;
792 }
793 }
794 set_owner(fs, curr, file);
795 clusters++;
796 prev = curr;
797 }
798 if (!(file->dir_ent.attr & ATTR_DIR) && le32toh(file->dir_ent.size) >
799#ifndef __REACTOS__
800 (uint64_t)clusters * fs->cluster_size) {
801#else
802 (uint64_t)clusters * fs->cluster_size && rw) {
803#endif
804 printf
805 ("%s\n File size is %u bytes, cluster chain length is %llu bytes."
806 "\n Truncating file to %llu bytes.\n", path_name(file),
807 le32toh(file->dir_ent.size),
808 (unsigned long long)clusters * fs->cluster_size,
809 (unsigned long long)clusters * fs->cluster_size);
811 htole32((uint64_t)clusters * fs->cluster_size));
812 }
813 return 0;
814}
#define expect(EXPECTED, GOT)
Definition: SystemMenu.c:483
void restart(int argc, const char *argv[])
Definition: cmds.c:2115
UINT64 uint64_t
Definition: types.h:77
#define FSTART(p, fs)
Definition: check.c:40
#define MODIFY_START(p, v, fs)
Definition: check.c:53
GLsizeiptr size
Definition: glext.h:5919
#define uint64_t
Definition: nsiface.idl:62
#define long
Definition: qsort.c:33
int bad_cluster(DOS_FS *fs, uint32_t cluster)
Definition: fat.c:258
uint32_t value
Definition: fsck.fat.h:193
off_t offset
Definition: fsck.fat.h:185
cab_ULONG size
Definition: fci.c:129

Referenced by check_files().

◆ check_files()

static int check_files ( DOS_FS fs,
DOS_FILE start 
)
static

Definition at line 816 of file check.c.

817{
818 while (start) {
819 if (check_file(fs, start))
820 return 1;
821 start = start->next;
822 }
823 return 0;
824}
static int check_file(DOS_FS *fs, DOS_FILE *file)
Definition: check.c:560

Referenced by scan_dir(), and scan_root().

◆ date_dos2unix()

static time_t date_dos2unix ( unsigned short  time,
unsigned short  date 
)
static

Definition at line 235 of file check.c.

236{
237 int month, year;
238 time_t secs;
239
240 month = ((date >> 5) & 15) - 1;
241 if (month < 0) {
242 /* make sure that nothing bad happens if the month bits were zero */
243 month = 0;
244 }
245 year = date >> 9;
246 secs =
247 (time & 31) * 2 + 60 * ((time >> 5) & 63) + (time >> 11) * 3600 +
248 86400 * ((date & 31) - 1 + day_n[month] + (year / 4) + year * 365 -
249 ((year & 3) == 0 && month < 2 ? 1 : 0) + 3653);
250 /* days since 1.1.70 plus 80's leap day */
251 return secs;
252}
static const WCHAR month[12][4]
Definition: session.c:2150
__kernel_time_t time_t
Definition: linux.h:252
static const int day_n[]
Definition: check.c:229
__u16 date
Definition: mkdosfs.c:8
__u16 time
Definition: mkdosfs.c:8

Referenced by file_stat().

◆ drop_file()

static void drop_file ( DOS_FS fs,
DOS_FILE file 
)
static

Definition at line 388 of file check.c.

389{
390 uint32_t cluster;
391
393 if (file->lfn)
394 lfn_remove(file->lfn_offset, file->offset);
395 for (cluster = FSTART(file, fs); cluster > 0 && cluster <
396 fs->data_clusters + 2; cluster = next_cluster(fs, cluster))
397 set_owner(fs, cluster, NULL);
398 --n_files;
399}
static void lfn_remove(off_t from, off_t to)
Definition: check.c:372

Referenced by check_dir(), handle_dot(), and main().

◆ file_stat()

static char * file_stat ( DOS_FILE file)
static

Definition at line 279 of file check.c.

280{
281 static char temp[100];
282 struct tm *tm;
283 char tmp[100];
284 time_t date;
285
286 date =
287 date_dos2unix(le16toh(file->dir_ent.time), le16toh(file->dir_ent.date));
288 tm = localtime(&date);
289 strftime(tmp, 99, "%H:%M:%S %b %d %Y", tm);
290 sprintf(temp, " Size %u bytes, date %s", le32toh(file->dir_ent.size), tmp);
291 return temp;
292}
static time_t date_dos2unix(unsigned short time, unsigned short date)
Definition: check.c:235
static calc_node_t temp
Definition: rpn_ieee.c:38
_CRTIMP struct tm *__cdecl localtime(const time_t *_Time)
Definition: time.h:416
size_t CDECL strftime(char *str, size_t max, const char *format, const struct tm *mstm)
Definition: strftime.c:294
cab_UWORD date
Definition: fci.c:132
cab_UWORD time
Definition: fci.c:133
Definition: time.h:68

Referenced by check_dir(), and File::length().

◆ handle_dot()

static int handle_dot ( DOS_FS fs,
DOS_FILE file,
int  dots 
)
static

Definition at line 511 of file check.c.

512{
513 const char *name;
514
515 name =
516 strncmp((const char *)file->dir_ent.name, MSDOS_DOT,
517 MSDOS_NAME) ? ".." : ".";
518 if (!(file->dir_ent.attr & ATTR_DIR)) {
519 printf("%s\n Is a non-directory.\n", path_name(file));
520 if (interactive)
521 printf("1) Drop it\n2) Auto-rename\n3) Rename\n"
522 "4) Convert to directory\n");
523#ifndef __REACTOS__
524 else
525#else
526 else if (rw)
527#endif
528 printf(" Auto-renaming it.\n");
529#ifdef __REACTOS__
530 if (rw || interactive) {
531#endif
532 switch (interactive ? get_key("1234", "?") : '2') {
533 case '1':
534 drop_file(fs, file);
535 return 1;
536 case '2':
538 printf(" Renamed to %s\n", file_name(file->dir_ent.name));
539 return 0;
540 case '3':
542 return 0;
543 case '4':
544 MODIFY(file, size, htole32(0));
545 MODIFY(file, attr, file->dir_ent.attr | ATTR_DIR);
546 break;
547#ifdef __REACTOS__
548 }
549#endif
550 }
551 }
552 if (!dots) {
553 printf("Root contains directory \"%s\". Dropping it.\n", name);
554 drop_file(fs, file);
555 return 1;
556 }
557 return 0;
558}

Referenced by check_dir().

◆ lfn_remove()

static void lfn_remove ( off_t  from,
off_t  to 
)
static

Definition at line 372 of file check.c.

373{
374 DIR_ENT empty;
375
376 /* New dir entry is zeroed except first byte, which is set to 0xe5.
377 * This is to avoid that some FAT-reading OSes (not Linux! ;) stop reading
378 * a directory at the first zero entry...
379 */
380 memset(&empty, 0, sizeof(empty));
381 empty.name[0] = DELETED_FLAG;
382
383 for (; from < to; from += sizeof(empty)) {
384 fs_write(from, sizeof(DIR_ENT), &empty);
385 }
386}
static const WCHAR empty[]
Definition: main.c:47
CardRegion * from
Definition: spigame.cpp:19

Referenced by drop_file().

◆ new_dir()

static void new_dir ( void  )
static

Definition at line 1099 of file check.c.

1100{
1101 lfn_reset();
1102}
void lfn_reset(void)
Definition: lfn.c:193

Referenced by BookmarkList::import_IE_favorites(), scan_dir(), and scan_root().

◆ path_name()

static char * path_name ( DOS_FILE file)
static

Construct a full path (starting with '/') for the specified dentry, relative to the partition. All components are "long" names where possible.

Parameters
[in]fileInformation about dentry (file or directory) of interest

return Pointer to static string containing file's full path

Definition at line 208 of file check.c.

209{
210 static char path[PATH_NAME_MAX * 2];
211
212 if (!file)
213 *path = 0; /* Reached the root directory */
214 else {
215 if (strlen(path_name(file->parent)) > PATH_NAME_MAX)
216 die("Path name too long.");
217 if (strcmp(path, "/") != 0)
218 strcat(path, "/");
219
220 /* Append the long name to the path,
221 * or the short name if there isn't a long one
222 */
223 strcpy(strrchr(path, 0),
224 file->lfn ? file->lfn : file_name(file->dir_ent.name));
225 }
226 return path;
227}
char * strcat(char *DstString, const char *SrcString)
Definition: utclib.c:568
int strcmp(const char *String1, const char *String2)
Definition: utclib.c:469
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
char * strcpy(char *DstString, const char *SrcString)
Definition: utclib.c:388
#define PATH_NAME_MAX
Definition: check.c:35
_CRT_RESTORE_GCC_WARNINGS _CRT_DISABLE_GCC_WARNINGS _Check_return_ _CRTIMP _CONST_RETURN char *__cdecl strrchr(_In_z_ const char *_Str, _In_ int _Ch)

Referenced by add_file(), check_dir(), check_file(), do_parent(), handle_dot(), ok_path(), path_name(), test_comctl32_classes(), test_file(), and test_GetVolumePathNameA().

◆ rename_file()

static void rename_file ( DOS_FILE file)
static

Definition at line 462 of file check.c.

463{
464#ifndef __REACTOS__
465 unsigned char name[46];
466 unsigned char *walk, *here;
467#endif
468
469 if (!file->offset) {
470#ifndef __REACTOS__
471 printf("Cannot rename FAT32 root dir\n");
472#else
473 VfatPrint( "Cannot rename FAT32 root dir\n" );
474#endif
475 return; /* cannot rename FAT32 root dir */
476 }
477 while (1) {
478#ifndef __REACTOS__
479 printf("New name: ");
480 fflush(stdout);
481 if (fgets((char *)name, 45, stdin)) {
482 if ((here = (unsigned char *)strchr((const char *)name, '\n')))
483 *here = 0;
484 for (walk = (unsigned char *)strrchr((const char *)name, 0);
485 walk >= name && (*walk == ' ' || *walk == '\t'); walk--) ;
486 walk[1] = 0;
487 for (walk = name; *walk == ' ' || *walk == '\t'; walk++) ;
488 if (file_cvt(walk, file->dir_ent.name)) {
489 if (file->dir_ent.lcase & FAT_NO_83NAME) {
490 /* as we only assign a new 8.3 filename, reset flag that 8.3 name is not
491 present */
492 file->dir_ent.lcase &= ~FAT_NO_83NAME;
493 /* reset the attributes, only keep DIR and VOLUME */
494 file->dir_ent.attr &= ~(ATTR_DIR | ATTR_VOLUME);
495 fs_write(file->offset, MSDOS_NAME + 2, &file->dir_ent);
496 } else {
497 fs_write(file->offset, MSDOS_NAME, file->dir_ent.name);
498 }
499 if (file->lfn)
500 lfn_fix_checksum(file->lfn_offset, file->offset,
501 (const char *)file->dir_ent.name);
502 return;
503 }
504 }
505#else
506 return;
507#endif
508 }
509}
#define stdout
Definition: stdio.h:99
_Check_return_opt_ _CRTIMP int __cdecl fflush(_Inout_opt_ FILE *_File)
#define stdin
Definition: stdio.h:98
_Check_return_opt_ _CRTIMP char *__cdecl fgets(_Out_writes_z_(_MaxCount) char *_Buf, _In_ int _MaxCount, _Inout_ FILE *_File)
int file_cvt(unsigned char *name, unsigned char *fixed)
Definition: file.c:84
VOID VfatPrint(PCHAR Format,...)
Definition: vfatlib.c:362

Referenced by check_dir(), and handle_dot().

◆ scan_dir()

static int scan_dir ( DOS_FS fs,
DOS_FILE this,
FDSC **  cp 
)
static

Definition at line 1174 of file check.c.

1175{
1176 DOS_FILE **chain;
1177 int i;
1178 uint32_t clu_num;
1179
1180 chain = &this->first;
1181 i = 0;
1182 clu_num = FSTART(this, fs);
1183 new_dir();
1184 while (clu_num > 0 && clu_num != -1) {
1185 add_file(fs, &chain, this,
1186 cluster_start(fs, clu_num) + (i % fs->cluster_size), cp);
1187 i += sizeof(DIR_ENT);
1188 if (!(i % fs->cluster_size))
1189 if ((clu_num = next_cluster(fs, clu_num)) == 0 || clu_num == -1)
1190 break;
1191 }
1193 if (check_dir(fs, &this->first, this->offset))
1194 return 0;
1195 if (check_files(fs, this->first))
1196 return 1;
1197 return subdirs(fs, this, cp);
1198}
static void add_file(DOS_FS *fs, DOS_FILE ***chain, DOS_FILE *parent, off_t offset, FDSC **cp)
Definition: check.c:1117
static int check_dir(DOS_FS *fs, DOS_FILE **root, int dots)
Definition: check.c:826
static void new_dir(void)
Definition: check.c:1099
static int subdirs(DOS_FS *fs, DOS_FILE *parent, FDSC **cp)
Definition: check.c:1210
static int check_files(DOS_FS *fs, DOS_FILE *start)
Definition: check.c:816

Referenced by subdirs().

◆ scan_root()

int scan_root ( DOS_FS fs)

Scan all directory and file information for errors.

Parameters
[in,out]fsInformation about the filesystem
Returns
0 Success
1 Error

Definition at line 1232 of file check.c.

1233{
1234 DOS_FILE **chain;
1235 int i;
1236
1237 root = NULL;
1238 chain = &root;
1239 new_dir();
1240 if (fs->root_cluster) {
1241 add_file(fs, &chain, NULL, 0, &fp_root);
1242 } else {
1243 for (i = 0; i < fs->root_entries; i++)
1244 add_file(fs, &chain, NULL, fs->root_start + i * sizeof(DIR_ENT),
1245 &fp_root);
1246 }
1248 (void)check_dir(fs, &root, 0);
1249 if (check_files(fs, root))
1250 return 1;
1251 return subdirs(fs, NULL, &fp_root);
1252}
FDSC * fp_root
Definition: file.c:32

Referenced by VfatChkdsk().

◆ subdirs()

static int subdirs ( DOS_FS fs,
DOS_FILE parent,
FDSC **  cp 
)
static

Recursively scan subdirectories of the specified parent directory.

Parameters
[in,out]fsInformation about the filesystem
[in]parentIdentifies the directory to scan
[in]cp
Returns
0 Success
1 Error

Definition at line 1210 of file check.c.

1211{
1212 DOS_FILE *walk;
1213
1214 for (walk = parent ? parent->first : root; walk; walk = walk->next)
1215 if (walk->dir_ent.attr & ATTR_DIR)
1216 if (strncmp((const char *)walk->dir_ent.name, MSDOS_DOT, MSDOS_NAME)
1217 && strncmp((const char *)walk->dir_ent.name, MSDOS_DOTDOT,
1218 MSDOS_NAME))
1219 if (scan_dir(fs, walk, file_cd(cp, (char *)walk->dir_ent.name)))
1220 return 1;
1221 return 0;
1222}
static int scan_dir(DOS_FS *fs, DOS_FILE *this, FDSC **cp)
Definition: check.c:1174
FDSC ** file_cd(FDSC **curr, char *fixed)
Definition: file.c:186

Referenced by scan_dir(), and scan_root().

◆ test_file()

static void test_file ( DOS_FS fs,
DOS_FILE file,
int  read_test 
)
static

Check a dentry's cluster chain for bad clusters. If requested, we verify readability and mark unreadable clusters as bad.

Parameters
[in,out]fsInformation about the filesystem
[in]filedentry to check
[in]read_testNonzero == verify that dentry's clusters can be read

Definition at line 1005 of file check.c.

1006{
1007 DOS_FILE *owner;
1008 uint32_t walk, prev, clusters, next_clu;
1009
1010 prev = clusters = 0;
1011 for (walk = FSTART(file, fs); walk > 1 && walk < fs->data_clusters + 2;
1012 walk = next_clu) {
1013 next_clu = next_cluster(fs, walk);
1014
1015 /* In this stage we are checking only for a loop within our own
1016 * cluster chain.
1017 * Cross-linking of clusters is handled in check_file()
1018 */
1019 if ((owner = get_owner(fs, walk))) {
1020 if (owner == file) {
1021 printf("%s\n Circular cluster chain. Truncating to %lu "
1022 "cluster%s.\n", path_name(file), (unsigned long)clusters,
1023 clusters == 1 ? "" : "s");
1024 if (prev)
1025 set_fat(fs, prev, -1);
1026 else if (!file->offset)
1027 die("Bad FAT32 root directory! (bad start cluster)\n");
1028 else
1029 MODIFY_START(file, 0, fs);
1030 }
1031 break;
1032 }
1033 if (bad_cluster(fs, walk))
1034 break;
1035 if (read_test) {
1036 if (fs_test(cluster_start(fs, walk), fs->cluster_size)) {
1037 prev = walk;
1038 clusters++;
1039 } else {
1040 printf("%s\n Cluster %lu (%lu) is unreadable. Skipping it.\n",
1041 path_name(file), (unsigned long)clusters, (unsigned long)walk);
1042 if (prev)
1043 set_fat(fs, prev, next_cluster(fs, walk));
1044 else
1046 set_fat(fs, walk, -2);
1047 }
1048 } else {
1049 prev = walk;
1050 clusters++;
1051 }
1052 set_owner(fs, walk, file);
1053 }
1054 /* Revert ownership (for now) */
1055 for (walk = FSTART(file, fs); walk > 1 && walk < fs->data_clusters + 2;
1056 walk = next_cluster(fs, walk))
1057 if (bad_cluster(fs, walk))
1058 break;
1059 else if (get_owner(fs, walk) == file)
1060 set_owner(fs, walk, NULL);
1061 else
1062 break;
1063}
static const struct notification read_test[]
Definition: notification.c:903
int fs_test(off_t pos, int size)
Definition: io.c:322

◆ truncate_file()

static void truncate_file ( DOS_FS fs,
DOS_FILE file,
uint32_t  clusters 
)
static

Definition at line 401 of file check.c.

402{
403 int deleting;
404 uint32_t walk, next;
405
406 walk = FSTART(file, fs);
407 if ((deleting = !clusters))
408 MODIFY_START(file, 0, fs);
409 while (walk > 0 && walk != -1) {
410 next = next_cluster(fs, walk);
411 if (deleting)
412 set_fat(fs, walk, 0);
413 else if ((deleting = !--clusters))
414 set_fat(fs, walk, -1);
415 walk = next;
416 }
417}
static unsigned __int64 next
Definition: rand_nt.c:6

Referenced by check_dir(), and check_file().

◆ undelete()

static void undelete ( DOS_FS fs,
DOS_FILE file 
)
static

Definition at line 1065 of file check.c.

1066{
1067 uint32_t clusters, left, prev, walk;
1068
1069 clusters = left = (le32toh(file->dir_ent.size) + fs->cluster_size - 1) /
1070 fs->cluster_size;
1071 prev = 0;
1072
1073 walk = FSTART(file, fs);
1074
1075 while (left && (walk >= 2) && (walk < fs->data_clusters + 2)) {
1076
1077 FAT_ENTRY curEntry;
1078 get_fat(&curEntry, fs->fat, walk, fs);
1079
1080 if (!curEntry.value)
1081 break;
1082
1083 left--;
1084 if (prev)
1085 set_fat(fs, prev, walk);
1086 prev = walk;
1087 walk++;
1088 }
1089 if (prev)
1090 set_fat(fs, prev, -1);
1091 else
1092 MODIFY_START(file, 0, fs);
1093 if (left)
1094 printf("Warning: Did only undelete %lu of %lu cluster%s.\n",
1095 (unsigned long)clusters - left, (unsigned long)clusters, clusters == 1 ? "" : "s");
1096
1097}
GLint left
Definition: glext.h:7726

Referenced by add_file().

Variable Documentation

◆ day_n

const int day_n[]
static
Initial value:
=
{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, 0 }

Definition at line 229 of file check.c.

Referenced by date_dos2unix().

◆ root

DOS_FILE* root
static

Definition at line 37 of file check.c.

Referenced by alloc_rootdir_entry(), auto_rename(), check_dir(), and scan_root().