dos line endings
authorSteven Edwards <winehacker@gmail.com>
Fri, 29 Jul 2005 23:03:42 +0000 (23:03 +0000)
committerSteven Edwards <winehacker@gmail.com>
Fri, 29 Jul 2005 23:03:42 +0000 (23:03 +0000)
svn path=/trunk/; revision=16887

25 files changed:
rosapps/sysutils/dosfsck/boot.c
rosapps/sysutils/dosfsck/boot.h
rosapps/sysutils/dosfsck/byteorder.h
rosapps/sysutils/dosfsck/byteswap.h
rosapps/sysutils/dosfsck/byteswap1.h
rosapps/sysutils/dosfsck/check.c
rosapps/sysutils/dosfsck/check.h
rosapps/sysutils/dosfsck/common.c
rosapps/sysutils/dosfsck/common.h
rosapps/sysutils/dosfsck/compiler.h
rosapps/sysutils/dosfsck/dosfsck.c
rosapps/sysutils/dosfsck/dosfsck.h
rosapps/sysutils/dosfsck/fat.c
rosapps/sysutils/dosfsck/fat.h
rosapps/sysutils/dosfsck/file.c
rosapps/sysutils/dosfsck/file.h
rosapps/sysutils/dosfsck/getopt.c
rosapps/sysutils/dosfsck/io.c
rosapps/sysutils/dosfsck/io.h
rosapps/sysutils/dosfsck/lfn.c
rosapps/sysutils/dosfsck/lfn.h
rosapps/sysutils/dosfsck/msdos_fs.h
rosapps/sysutils/dosfsck/swab.h
rosapps/sysutils/dosfsck/version.h
rosapps/sysutils/dosfsck/vfat.h

index dac2d2c..cddbac3 100644 (file)
-/* boot.c  -  Read and analyze ia PC/MS-DOS boot sector */
-
-/* Written 1993 by Werner Almesberger */
-
-/* FAT32, VFAT, Atari format support, and various fixes additions May 1998
- * by Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> */
-
-#include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-
-#include "common.h"
-#include "dosfsck.h"
-#include "io.h"
-#include "boot.h"
-
-
-#define ROUND_TO_MULTIPLE(n,m) ((n) && (m) ? (n)+(m)-1-((n)-1)%(m) : 0)
-    /* don't divide by zero */
-
-static struct {
-    __u8 media;
-    char *descr;
-} mediabytes[] = {
-    { 0xf0, "5.25\" or 3.5\" HD floppy" },
-    { 0xf8, "hard disk" },
-    { 0xf9, "3,5\" 720k floppy 2s/80tr/9sec or "
-            "5.25\" 1.2M floppy 2s/80tr/15sec" },
-    { 0xfa, "5.25\" 320k floppy 1s/80tr/8sec" },
-    { 0xfb, "3.5\" 640k floppy 2s/80tr/8sec" },
-    { 0xfc, "5.25\" 180k floppy 1s/40tr/9sec" },
-    { 0xfd, "5.25\" 360k floppy 2s/40tr/9sec" },
-    { 0xfe, "5.25\" 160k floppy 1s/40tr/8sec" },
-    { 0xff, "5.25\" 320k floppy 2s/40tr/8sec" },
-};
-
-#if defined __alpha || defined __ia64__ || defined __s390x__ || defined __x86_64__ || defined __ppc64__
-/* Unaligned fields must first be copied byte-wise */
-#define GET_UNALIGNED_W(f)                     \
-    ({                                         \
-       unsigned short __v;                     \
-       memcpy( &__v, &f, sizeof(__v) );        \
-       CF_LE_W( *(unsigned short *)&f );       \
-    })
-#else
-#define GET_UNALIGNED_W(f) CF_LE_W( *(unsigned short *)&f )
-#endif
-
-
-static char *get_media_descr( unsigned char media )
-{
-    int i;
-
-    for( i = 0; i < sizeof(mediabytes)/sizeof(*mediabytes); ++i ) {
-       if (mediabytes[i].media == media)
-           return( mediabytes[i].descr );
-    }
-    return( "undefined" );
-}
-
-static void dump_boot(DOS_FS *fs,struct boot_sector *b,unsigned lss)
-{
-    unsigned short sectors;
-    
-    printf("Boot sector contents:\n");
-    if (!atari_format) {
-       char id[9];
-       strncpy(id,b->system_id,8);
-       id[8] = 0;
-       printf("System ID \"%s\"\n",id);
-    }
-    else {
-       /* On Atari, a 24 bit serial number is stored at offset 8 of the boot
-        * sector */
-       printf("Serial number 0x%x\n",
-              b->system_id[5] | (b->system_id[6]<<8) | (b->system_id[7]<<16));
-    }
-    printf("Media byte 0x%02x (%s)\n",b->media,get_media_descr(b->media));
-    printf("%10d bytes per logical sector\n",GET_UNALIGNED_W(b->sector_size));
-    printf("%10d bytes per cluster\n",fs->cluster_size);
-    printf("%10d reserved sector%s\n",CF_LE_W(b->reserved),
-          CF_LE_W(b->reserved) == 1 ? "" : "s");
-    printf("First FAT starts at byte %llu (sector %llu)\n",
-          (__u64)fs->fat_start,
-          (__u64)fs->fat_start/lss);
-    printf("%10d FATs, %d bit entries\n",b->fats,fs->fat_bits);
-    printf("%10d bytes per FAT (= %u sectors)\n",fs->fat_size,
-          fs->fat_size/lss);
-    if (!fs->root_cluster) {
-       printf("Root directory starts at byte %llu (sector %llu)\n",
-              (__u64)fs->root_start,
-              (__u64)fs->root_start/lss);
-       printf("%10d root directory entries\n",fs->root_entries);
-    }
-    else {
-       printf( "Root directory start at cluster %lu (arbitrary size)\n",
-               fs->root_cluster);
-    }
-    printf("Data area starts at byte %llu (sector %llu)\n",
-          (__u64)fs->data_start,
-          (__u64)fs->data_start/lss);
-    printf("%10lu data clusters (%llu bytes)\n",fs->clusters,
-          (__u64)fs->clusters*fs->cluster_size);
-    printf("%u sectors/track, %u heads\n",CF_LE_W(b->secs_track),
-          CF_LE_W(b->heads));
-    printf("%10u hidden sectors\n",
-          atari_format ?
-          /* On Atari, the hidden field is only 16 bit wide and unused */
-          (((unsigned char *)&b->hidden)[0] |
-           ((unsigned char *)&b->hidden)[1] << 8) :
-          CF_LE_L(b->hidden));
-    sectors = GET_UNALIGNED_W( b->sectors );
-    printf("%10u sectors total\n", sectors ? sectors : CF_LE_L(b->total_sect));
-}
-
-static void check_backup_boot(DOS_FS *fs, struct boot_sector *b, int lss)
-{
-    struct boot_sector b2;
-
-    if (!fs->backupboot_start) {
-       printf( "There is no backup boot sector.\n" );
-       if (CF_LE_W(b->reserved) < 3) {
-           printf( "And there is no space for creating one!\n" );
-           return;
-       }
-       if (interactive)
-           printf( "1) Create one\n2) Do without a backup\n" );
-       else printf( "  Auto-creating backup boot block.\n" );
-       if (!interactive || get_key("12","?") == '1') {
-           int bbs;
-           /* The usual place for the backup boot sector is sector 6. Choose
-            * that or the last reserved sector. */
-           if (CF_LE_W(b->reserved) >= 7 && CF_LE_W(b->info_sector) != 6)
-               bbs = 6;
-           else {
-               bbs = CF_LE_W(b->reserved) - 1;
-               if (bbs == CF_LE_W(b->info_sector))
-                   --bbs; /* this is never 0, as we checked reserved >= 3! */
-           }
-           fs->backupboot_start = bbs*lss;
-           b->backup_boot = CT_LE_W(bbs);
-           fs_write(fs->backupboot_start,sizeof(*b),b);
-           fs_write((off_t)offsetof(struct boot_sector,backup_boot),
-                    sizeof(b->backup_boot),&b->backup_boot);
-           printf( "Created backup of boot sector in sector %d\n", bbs );
-           return;
-       }
-       else return;
-    }
-    
-    fs_read(fs->backupboot_start,sizeof(b2),&b2);
-    if (memcmp(b,&b2,sizeof(b2)) != 0) {
-       /* there are any differences */
-       __u8 *p, *q;
-       int i, pos, first = 1;
-       char buf[20];
-
-       printf( "There are differences between boot sector and its backup.\n" );
-       printf( "Differences: (offset:original/backup)\n  " );
-       pos = 2;
-       for( p = (__u8 *)b, q = (__u8 *)&b2, i = 0; i < sizeof(b2);
-            ++p, ++q, ++i ) {
-           if (*p != *q) {
-               sprintf( buf, "%s%u:%02x/%02x", first ? "" : ", ",
-                        (unsigned)(p-(__u8 *)b), *p, *q );
-               if (pos + strlen(buf) > 78) printf( "\n  " ), pos = 2;
-               printf( "%s", buf );
-               pos += strlen(buf);
-               first = 0;
-           }
-       }
-       printf( "\n" );
-
-       if (interactive)
-           printf( "1) Copy original to backup\n"
-                   "2) Copy backup to original\n"
-                   "3) No action\n" );
-       else printf( "  Not automatically fixing this.\n" );
-       switch (interactive ? get_key("123","?") : '3') {
-         case '1':
-           fs_write(fs->backupboot_start,sizeof(*b),b);
-           break;
-         case '2':
-           fs_write(0,sizeof(b2),&b2);
-           break;
-         default:
-           break;
-       }
-    }
-}
-
-static void init_fsinfo(struct info_sector *i)
-{
-    i->magic = CT_LE_L(0x41615252);
-    i->signature = CT_LE_L(0x61417272);
-    i->free_clusters = CT_LE_L(-1);
-    i->next_cluster = CT_LE_L(2);
-    i->boot_sign = CT_LE_W(0xaa55);
-}
-
-static void read_fsinfo(DOS_FS *fs, struct boot_sector *b,int lss)
-{
-    struct info_sector i;
-
-    if (!b->info_sector) {
-       printf( "No FSINFO sector\n" );
-       if (interactive)
-           printf( "1) Create one\n2) Do without FSINFO\n" );
-       else printf( "  Not automatically creating it.\n" );
-       if (interactive && get_key("12","?") == '1') {
-           /* search for a free reserved sector (not boot sector and not
-            * backup boot sector) */
-           __u32 s;
-           for( s = 1; s < CF_LE_W(b->reserved); ++s )
-               if (s != CF_LE_W(b->backup_boot)) break;
-           if (s > 0 && s < CF_LE_W(b->reserved)) {
-               init_fsinfo(&i);
-               fs_write((off_t)s*lss,sizeof(i),&i);
-               b->info_sector = CT_LE_W(s);
-               fs_write((off_t)offsetof(struct boot_sector,info_sector),
-                        sizeof(b->info_sector),&b->info_sector);
-               if (fs->backupboot_start)
-                   fs_write(fs->backupboot_start+
-                            offsetof(struct boot_sector,info_sector),
-                            sizeof(b->info_sector),&b->info_sector);
-           }
-           else {
-               printf( "No free reserved sector found -- "
-                       "no space for FSINFO sector!\n" );
-               return;
-           }
-       }
-       else return;
-    }
-    
-    fs->fsinfo_start = CF_LE_W(b->info_sector)*lss;
-    fs_read(fs->fsinfo_start,sizeof(i),&i);
-    
-    if (i.magic != CT_LE_L(0x41615252) ||
-       i.signature != CT_LE_L(0x61417272) ||
-       i.boot_sign != CT_LE_W(0xaa55)) {
-       printf( "FSINFO sector has bad magic number(s):\n" );
-       if (i.magic != CT_LE_L(0x41615252))
-           printf( "  Offset %llu: 0x%08x != expected 0x%08x\n",
-                   (__u64)offsetof(struct info_sector,magic),
-                   CF_LE_L(i.magic),0x41615252);
-       if (i.signature != CT_LE_L(0x61417272))
-           printf( "  Offset %llu: 0x%08x != expected 0x%08x\n",
-                   (__u64)offsetof(struct info_sector,signature),
-                   CF_LE_L(i.signature),0x61417272);
-       if (i.boot_sign != CT_LE_W(0xaa55))
-           printf( "  Offset %llu: 0x%04x != expected 0x%04x\n",
-                   (__u64)offsetof(struct info_sector,boot_sign),
-                   CF_LE_W(i.boot_sign),0xaa55);
-       if (interactive)
-           printf( "1) Correct\n2) Don't correct (FSINFO invalid then)\n" );
-       else printf( "  Auto-correcting it.\n" );
-       if (!interactive || get_key("12","?") == '1') {
-           init_fsinfo(&i);
-           fs_write(fs->fsinfo_start,sizeof(i),&i);
-       }
-       else fs->fsinfo_start = 0;
-    }
-
-    if (fs->fsinfo_start)
-       fs->free_clusters = CF_LE_L(i.free_clusters);
-}
-
-void read_boot(DOS_FS *fs)
-{
-    struct boot_sector b;
-    unsigned total_sectors;
-    unsigned short logical_sector_size, sectors;
-    unsigned fat_length;
-    loff_t data_size;
-
-    fs_read(0,sizeof(b),&b);
-    logical_sector_size = GET_UNALIGNED_W(b.sector_size);
-    if (!logical_sector_size) die("Logical sector size is zero.");
-    fs->cluster_size = b.cluster_size*logical_sector_size;
-    if (!fs->cluster_size) die("Cluster size is zero.");
-    if (b.fats != 2 && b.fats != 1)
-       die("Currently, only 1 or 2 FATs are supported, not %d.\n",b.fats);
-    fs->nfats = b.fats;
-    sectors = GET_UNALIGNED_W(b.sectors);
-    total_sectors = sectors ? sectors : CF_LE_L(b.total_sect);
-    if (verbose) printf("Checking we can access the last sector of the filesystem\n");
-    /* Can't access last odd sector anyway, so round down */
-    fs_test((loff_t)((total_sectors & ~1)-1)*(loff_t)logical_sector_size,
-           logical_sector_size);
-    fat_length = CF_LE_W(b.fat_length) ?
-                CF_LE_W(b.fat_length) : CF_LE_L(b.fat32_length);
-    fs->fat_start = (off_t)CF_LE_W(b.reserved)*logical_sector_size;
-    fs->root_start = ((off_t)CF_LE_W(b.reserved)+b.fats*fat_length)*
-      logical_sector_size;
-    fs->root_entries = GET_UNALIGNED_W(b.dir_entries);
-    fs->data_start = fs->root_start+ROUND_TO_MULTIPLE(fs->root_entries <<
-      MSDOS_DIR_BITS,logical_sector_size);
-    data_size = (loff_t)total_sectors*logical_sector_size-fs->data_start;
-    fs->clusters = data_size/fs->cluster_size;
-    fs->root_cluster = 0; /* indicates standard, pre-FAT32 root dir */
-    fs->fsinfo_start = 0; /* no FSINFO structure */
-    fs->free_clusters = -1; /* unknown */
-    if (!b.fat_length && b.fat32_length) {
-       fs->fat_bits = 32;
-       fs->root_cluster = CF_LE_L(b.root_cluster);
-       if (!fs->root_cluster && fs->root_entries)
-           /* M$ hasn't specified this, but it looks reasonable: If
-            * root_cluster is 0 but there is a separate root dir
-            * (root_entries != 0), we handle the root dir the old way. Give a
-            * warning, but convertig to a root dir in a cluster chain seems
-            * to complex for now... */
-           printf( "Warning: FAT32 root dir not in cluster chain! "
-                   "Compability mode...\n" );
-       else if (!fs->root_cluster && !fs->root_entries)
-           die("No root directory!");
-       else if (fs->root_cluster && fs->root_entries)
-           printf( "Warning: FAT32 root dir is in a cluster chain, but "
-                   "a separate root dir\n"
-                   "  area is defined. Cannot fix this easily.\n" );
-
-       fs->backupboot_start = CF_LE_W(b.backup_boot)*logical_sector_size;
-       check_backup_boot(fs,&b,logical_sector_size);
-       
-       read_fsinfo(fs,&b,logical_sector_size);
-    }
-    else if (!atari_format) {
-       /* On real MS-DOS, a 16 bit FAT is used whenever there would be too
-        * much clusers otherwise. */
-       fs->fat_bits = (fs->clusters > MSDOS_FAT12) ? 16 : 12;
-    }
-    else {
-       /* On Atari, things are more difficult: GEMDOS always uses 12bit FATs
-        * on floppies, and always 16 bit on harddisks. */
-       fs->fat_bits = 16; /* assume 16 bit FAT for now */
-       /* If more clusters than fat entries in 16-bit fat, we assume
-        * it's a real MSDOS FS with 12-bit fat. */
-       if (fs->clusters+2 > fat_length*logical_sector_size*8/16 ||
-           /* if it's a floppy disk --> 12bit fat */
-           device_no == 2 ||
-           /* if it's a ramdisk or loopback device and has one of the usual
-            * floppy sizes -> 12bit FAT  */
-           ((device_no == 1 || device_no == 7) &&
-            (total_sectors == 720 || total_sectors == 1440 ||
-             total_sectors == 2880)))
-           fs->fat_bits = 12;
-    }
-    /* On FAT32, the high 4 bits of a FAT entry are reserved */
-    fs->eff_fat_bits = (fs->fat_bits == 32) ? 28 : fs->fat_bits;
-    fs->fat_size = fat_length*logical_sector_size;
-    if (fs->clusters > ((__u64)fs->fat_size*8/fs->fat_bits)-2)
-       die("File system has %d clusters but only space for %d FAT entries.",
-         fs->clusters,((__u64)fs->fat_size*8/fs->fat_bits)-2);
-    if (!fs->root_entries && !fs->root_cluster)
-       die("Root directory has zero size.");
-    if (fs->root_entries & (MSDOS_DPS-1))
-       die("Root directory (%d entries) doesn't span an integral number of "
-         "sectors.",fs->root_entries);
-    if (logical_sector_size & (SECTOR_SIZE-1))
-       die("Logical sector size (%d bytes) is not a multiple of the physical "
-         "sector size.",logical_sector_size);
-    /* ++roman: On Atari, these two fields are often left uninitialized */
-    if (!atari_format && (!b.secs_track || !b.heads))
-       die("Invalid disk format in boot sector.");
-    if (verbose) dump_boot(fs,&b,logical_sector_size);
-}
-
-/* Local Variables: */
-/* tab-width: 8     */
-/* End:             */
+/* boot.c  -  Read and analyze ia PC/MS-DOS boot sector */\r
+\r
+/* Written 1993 by Werner Almesberger */\r
+\r
+/* FAT32, VFAT, Atari format support, and various fixes additions May 1998\r
+ * by Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> */\r
+\r
+#include <stdio.h>\r
+#include <string.h>\r
+#include <sys/types.h>\r
+\r
+#include "common.h"\r
+#include "dosfsck.h"\r
+#include "io.h"\r
+#include "boot.h"\r
+\r
+\r
+#define ROUND_TO_MULTIPLE(n,m) ((n) && (m) ? (n)+(m)-1-((n)-1)%(m) : 0)\r
+    /* don't divide by zero */\r
+\r
+static struct {\r
+    __u8 media;\r
+    char *descr;\r
+} mediabytes[] = {\r
+    { 0xf0, "5.25\" or 3.5\" HD floppy" },\r
+    { 0xf8, "hard disk" },\r
+    { 0xf9, "3,5\" 720k floppy 2s/80tr/9sec or "\r
+            "5.25\" 1.2M floppy 2s/80tr/15sec" },\r
+    { 0xfa, "5.25\" 320k floppy 1s/80tr/8sec" },\r
+    { 0xfb, "3.5\" 640k floppy 2s/80tr/8sec" },\r
+    { 0xfc, "5.25\" 180k floppy 1s/40tr/9sec" },\r
+    { 0xfd, "5.25\" 360k floppy 2s/40tr/9sec" },\r
+    { 0xfe, "5.25\" 160k floppy 1s/40tr/8sec" },\r
+    { 0xff, "5.25\" 320k floppy 2s/40tr/8sec" },\r
+};\r
+\r
+#if defined __alpha || defined __ia64__ || defined __s390x__ || defined __x86_64__ || defined __ppc64__\r
+/* Unaligned fields must first be copied byte-wise */\r
+#define GET_UNALIGNED_W(f)                     \\r
+    ({                                         \\r
+       unsigned short __v;                     \\r
+       memcpy( &__v, &f, sizeof(__v) );        \\r
+       CF_LE_W( *(unsigned short *)&f );       \\r
+    })\r
+#else\r
+#define GET_UNALIGNED_W(f) CF_LE_W( *(unsigned short *)&f )\r
+#endif\r
+\r
+\r
+static char *get_media_descr( unsigned char media )\r
+{\r
+    int i;\r
+\r
+    for( i = 0; i < sizeof(mediabytes)/sizeof(*mediabytes); ++i ) {\r
+       if (mediabytes[i].media == media)\r
+           return( mediabytes[i].descr );\r
+    }\r
+    return( "undefined" );\r
+}\r
+\r
+static void dump_boot(DOS_FS *fs,struct boot_sector *b,unsigned lss)\r
+{\r
+    unsigned short sectors;\r
+    \r
+    printf("Boot sector contents:\n");\r
+    if (!atari_format) {\r
+       char id[9];\r
+       strncpy(id,b->system_id,8);\r
+       id[8] = 0;\r
+       printf("System ID \"%s\"\n",id);\r
+    }\r
+    else {\r
+       /* On Atari, a 24 bit serial number is stored at offset 8 of the boot\r
+        * sector */\r
+       printf("Serial number 0x%x\n",\r
+              b->system_id[5] | (b->system_id[6]<<8) | (b->system_id[7]<<16));\r
+    }\r
+    printf("Media byte 0x%02x (%s)\n",b->media,get_media_descr(b->media));\r
+    printf("%10d bytes per logical sector\n",GET_UNALIGNED_W(b->sector_size));\r
+    printf("%10d bytes per cluster\n",fs->cluster_size);\r
+    printf("%10d reserved sector%s\n",CF_LE_W(b->reserved),\r
+          CF_LE_W(b->reserved) == 1 ? "" : "s");\r
+    printf("First FAT starts at byte %llu (sector %llu)\n",\r
+          (__u64)fs->fat_start,\r
+          (__u64)fs->fat_start/lss);\r
+    printf("%10d FATs, %d bit entries\n",b->fats,fs->fat_bits);\r
+    printf("%10d bytes per FAT (= %u sectors)\n",fs->fat_size,\r
+          fs->fat_size/lss);\r
+    if (!fs->root_cluster) {\r
+       printf("Root directory starts at byte %llu (sector %llu)\n",\r
+              (__u64)fs->root_start,\r
+              (__u64)fs->root_start/lss);\r
+       printf("%10d root directory entries\n",fs->root_entries);\r
+    }\r
+    else {\r
+       printf( "Root directory start at cluster %lu (arbitrary size)\n",\r
+               fs->root_cluster);\r
+    }\r
+    printf("Data area starts at byte %llu (sector %llu)\n",\r
+          (__u64)fs->data_start,\r
+          (__u64)fs->data_start/lss);\r
+    printf("%10lu data clusters (%llu bytes)\n",fs->clusters,\r
+          (__u64)fs->clusters*fs->cluster_size);\r
+    printf("%u sectors/track, %u heads\n",CF_LE_W(b->secs_track),\r
+          CF_LE_W(b->heads));\r
+    printf("%10u hidden sectors\n",\r
+          atari_format ?\r
+          /* On Atari, the hidden field is only 16 bit wide and unused */\r
+          (((unsigned char *)&b->hidden)[0] |\r
+           ((unsigned char *)&b->hidden)[1] << 8) :\r
+          CF_LE_L(b->hidden));\r
+    sectors = GET_UNALIGNED_W( b->sectors );\r
+    printf("%10u sectors total\n", sectors ? sectors : CF_LE_L(b->total_sect));\r
+}\r
+\r
+static void check_backup_boot(DOS_FS *fs, struct boot_sector *b, int lss)\r
+{\r
+    struct boot_sector b2;\r
+\r
+    if (!fs->backupboot_start) {\r
+       printf( "There is no backup boot sector.\n" );\r
+       if (CF_LE_W(b->reserved) < 3) {\r
+           printf( "And there is no space for creating one!\n" );\r
+           return;\r
+       }\r
+       if (interactive)\r
+           printf( "1) Create one\n2) Do without a backup\n" );\r
+       else printf( "  Auto-creating backup boot block.\n" );\r
+       if (!interactive || get_key("12","?") == '1') {\r
+           int bbs;\r
+           /* The usual place for the backup boot sector is sector 6. Choose\r
+            * that or the last reserved sector. */\r
+           if (CF_LE_W(b->reserved) >= 7 && CF_LE_W(b->info_sector) != 6)\r
+               bbs = 6;\r
+           else {\r
+               bbs = CF_LE_W(b->reserved) - 1;\r
+               if (bbs == CF_LE_W(b->info_sector))\r
+                   --bbs; /* this is never 0, as we checked reserved >= 3! */\r
+           }\r
+           fs->backupboot_start = bbs*lss;\r
+           b->backup_boot = CT_LE_W(bbs);\r
+           fs_write(fs->backupboot_start,sizeof(*b),b);\r
+           fs_write((off_t)offsetof(struct boot_sector,backup_boot),\r
+                    sizeof(b->backup_boot),&b->backup_boot);\r
+           printf( "Created backup of boot sector in sector %d\n", bbs );\r
+           return;\r
+       }\r
+       else return;\r
+    }\r
+    \r
+    fs_read(fs->backupboot_start,sizeof(b2),&b2);\r
+    if (memcmp(b,&b2,sizeof(b2)) != 0) {\r
+       /* there are any differences */\r
+       __u8 *p, *q;\r
+       int i, pos, first = 1;\r
+       char buf[20];\r
+\r
+       printf( "There are differences between boot sector and its backup.\n" );\r
+       printf( "Differences: (offset:original/backup)\n  " );\r
+       pos = 2;\r
+       for( p = (__u8 *)b, q = (__u8 *)&b2, i = 0; i < sizeof(b2);\r
+            ++p, ++q, ++i ) {\r
+           if (*p != *q) {\r
+               sprintf( buf, "%s%u:%02x/%02x", first ? "" : ", ",\r
+                        (unsigned)(p-(__u8 *)b), *p, *q );\r
+               if (pos + strlen(buf) > 78) printf( "\n  " ), pos = 2;\r
+               printf( "%s", buf );\r
+               pos += strlen(buf);\r
+               first = 0;\r
+           }\r
+       }\r
+       printf( "\n" );\r
+\r
+       if (interactive)\r
+           printf( "1) Copy original to backup\n"\r
+                   "2) Copy backup to original\n"\r
+                   "3) No action\n" );\r
+       else printf( "  Not automatically fixing this.\n" );\r
+       switch (interactive ? get_key("123","?") : '3') {\r
+         case '1':\r
+           fs_write(fs->backupboot_start,sizeof(*b),b);\r
+           break;\r
+         case '2':\r
+           fs_write(0,sizeof(b2),&b2);\r
+           break;\r
+         default:\r
+           break;\r
+       }\r
+    }\r
+}\r
+\r
+static void init_fsinfo(struct info_sector *i)\r
+{\r
+    i->magic = CT_LE_L(0x41615252);\r
+    i->signature = CT_LE_L(0x61417272);\r
+    i->free_clusters = CT_LE_L(-1);\r
+    i->next_cluster = CT_LE_L(2);\r
+    i->boot_sign = CT_LE_W(0xaa55);\r
+}\r
+\r
+static void read_fsinfo(DOS_FS *fs, struct boot_sector *b,int lss)\r
+{\r
+    struct info_sector i;\r
+\r
+    if (!b->info_sector) {\r
+       printf( "No FSINFO sector\n" );\r
+       if (interactive)\r
+           printf( "1) Create one\n2) Do without FSINFO\n" );\r
+       else printf( "  Not automatically creating it.\n" );\r
+       if (interactive && get_key("12","?") == '1') {\r
+           /* search for a free reserved sector (not boot sector and not\r
+            * backup boot sector) */\r
+           __u32 s;\r
+           for( s = 1; s < CF_LE_W(b->reserved); ++s )\r
+               if (s != CF_LE_W(b->backup_boot)) break;\r
+           if (s > 0 && s < CF_LE_W(b->reserved)) {\r
+               init_fsinfo(&i);\r
+               fs_write((off_t)s*lss,sizeof(i),&i);\r
+               b->info_sector = CT_LE_W(s);\r
+               fs_write((off_t)offsetof(struct boot_sector,info_sector),\r
+                        sizeof(b->info_sector),&b->info_sector);\r
+               if (fs->backupboot_start)\r
+                   fs_write(fs->backupboot_start+\r
+                            offsetof(struct boot_sector,info_sector),\r
+                            sizeof(b->info_sector),&b->info_sector);\r
+           }\r
+           else {\r
+               printf( "No free reserved sector found -- "\r
+                       "no space for FSINFO sector!\n" );\r
+               return;\r
+           }\r
+       }\r
+       else return;\r
+    }\r
+    \r
+    fs->fsinfo_start = CF_LE_W(b->info_sector)*lss;\r
+    fs_read(fs->fsinfo_start,sizeof(i),&i);\r
+    \r
+    if (i.magic != CT_LE_L(0x41615252) ||\r
+       i.signature != CT_LE_L(0x61417272) ||\r
+       i.boot_sign != CT_LE_W(0xaa55)) {\r
+       printf( "FSINFO sector has bad magic number(s):\n" );\r
+       if (i.magic != CT_LE_L(0x41615252))\r
+           printf( "  Offset %llu: 0x%08x != expected 0x%08x\n",\r
+                   (__u64)offsetof(struct info_sector,magic),\r
+                   CF_LE_L(i.magic),0x41615252);\r
+       if (i.signature != CT_LE_L(0x61417272))\r
+           printf( "  Offset %llu: 0x%08x != expected 0x%08x\n",\r
+                   (__u64)offsetof(struct info_sector,signature),\r
+                   CF_LE_L(i.signature),0x61417272);\r
+       if (i.boot_sign != CT_LE_W(0xaa55))\r
+           printf( "  Offset %llu: 0x%04x != expected 0x%04x\n",\r
+                   (__u64)offsetof(struct info_sector,boot_sign),\r
+                   CF_LE_W(i.boot_sign),0xaa55);\r
+       if (interactive)\r
+           printf( "1) Correct\n2) Don't correct (FSINFO invalid then)\n" );\r
+       else printf( "  Auto-correcting it.\n" );\r
+       if (!interactive || get_key("12","?") == '1') {\r
+           init_fsinfo(&i);\r
+           fs_write(fs->fsinfo_start,sizeof(i),&i);\r
+       }\r
+       else fs->fsinfo_start = 0;\r
+    }\r
+\r
+    if (fs->fsinfo_start)\r
+       fs->free_clusters = CF_LE_L(i.free_clusters);\r
+}\r
+\r
+void read_boot(DOS_FS *fs)\r
+{\r
+    struct boot_sector b;\r
+    unsigned total_sectors;\r
+    unsigned short logical_sector_size, sectors;\r
+    unsigned fat_length;\r
+    loff_t data_size;\r
+\r
+    fs_read(0,sizeof(b),&b);\r
+    logical_sector_size = GET_UNALIGNED_W(b.sector_size);\r
+    if (!logical_sector_size) die("Logical sector size is zero.");\r
+    fs->cluster_size = b.cluster_size*logical_sector_size;\r
+    if (!fs->cluster_size) die("Cluster size is zero.");\r
+    if (b.fats != 2 && b.fats != 1)\r
+       die("Currently, only 1 or 2 FATs are supported, not %d.\n",b.fats);\r
+    fs->nfats = b.fats;\r
+    sectors = GET_UNALIGNED_W(b.sectors);\r
+    total_sectors = sectors ? sectors : CF_LE_L(b.total_sect);\r
+    if (verbose) printf("Checking we can access the last sector of the filesystem\n");\r
+    /* Can't access last odd sector anyway, so round down */\r
+    fs_test((loff_t)((total_sectors & ~1)-1)*(loff_t)logical_sector_size,\r
+           logical_sector_size);\r
+    fat_length = CF_LE_W(b.fat_length) ?\r
+                CF_LE_W(b.fat_length) : CF_LE_L(b.fat32_length);\r
+    fs->fat_start = (off_t)CF_LE_W(b.reserved)*logical_sector_size;\r
+    fs->root_start = ((off_t)CF_LE_W(b.reserved)+b.fats*fat_length)*\r
+      logical_sector_size;\r
+    fs->root_entries = GET_UNALIGNED_W(b.dir_entries);\r
+    fs->data_start = fs->root_start+ROUND_TO_MULTIPLE(fs->root_entries <<\r
+      MSDOS_DIR_BITS,logical_sector_size);\r
+    data_size = (loff_t)total_sectors*logical_sector_size-fs->data_start;\r
+    fs->clusters = data_size/fs->cluster_size;\r
+    fs->root_cluster = 0; /* indicates standard, pre-FAT32 root dir */\r
+    fs->fsinfo_start = 0; /* no FSINFO structure */\r
+    fs->free_clusters = -1; /* unknown */\r
+    if (!b.fat_length && b.fat32_length) {\r
+       fs->fat_bits = 32;\r
+       fs->root_cluster = CF_LE_L(b.root_cluster);\r
+       if (!fs->root_cluster && fs->root_entries)\r
+           /* M$ hasn't specified this, but it looks reasonable: If\r
+            * root_cluster is 0 but there is a separate root dir\r
+            * (root_entries != 0), we handle the root dir the old way. Give a\r
+            * warning, but convertig to a root dir in a cluster chain seems\r
+            * to complex for now... */\r
+           printf( "Warning: FAT32 root dir not in cluster chain! "\r
+                   "Compability mode...\n" );\r
+       else if (!fs->root_cluster && !fs->root_entries)\r
+           die("No root directory!");\r
+       else if (fs->root_cluster && fs->root_entries)\r
+           printf( "Warning: FAT32 root dir is in a cluster chain, but "\r
+                   "a separate root dir\n"\r
+                   "  area is defined. Cannot fix this easily.\n" );\r
+\r
+       fs->backupboot_start = CF_LE_W(b.backup_boot)*logical_sector_size;\r
+       check_backup_boot(fs,&b,logical_sector_size);\r
+       \r
+       read_fsinfo(fs,&b,logical_sector_size);\r
+    }\r
+    else if (!atari_format) {\r
+       /* On real MS-DOS, a 16 bit FAT is used whenever there would be too\r
+        * much clusers otherwise. */\r
+       fs->fat_bits = (fs->clusters > MSDOS_FAT12) ? 16 : 12;\r
+    }\r
+    else {\r
+       /* On Atari, things are more difficult: GEMDOS always uses 12bit FATs\r
+        * on floppies, and always 16 bit on harddisks. */\r
+       fs->fat_bits = 16; /* assume 16 bit FAT for now */\r
+       /* If more clusters than fat entries in 16-bit fat, we assume\r
+        * it's a real MSDOS FS with 12-bit fat. */\r
+       if (fs->clusters+2 > fat_length*logical_sector_size*8/16 ||\r
+           /* if it's a floppy disk --> 12bit fat */\r
+           device_no == 2 ||\r
+           /* if it's a ramdisk or loopback device and has one of the usual\r
+            * floppy sizes -> 12bit FAT  */\r
+           ((device_no == 1 || device_no == 7) &&\r
+            (total_sectors == 720 || total_sectors == 1440 ||\r
+             total_sectors == 2880)))\r
+           fs->fat_bits = 12;\r
+    }\r
+    /* On FAT32, the high 4 bits of a FAT entry are reserved */\r
+    fs->eff_fat_bits = (fs->fat_bits == 32) ? 28 : fs->fat_bits;\r
+    fs->fat_size = fat_length*logical_sector_size;\r
+    if (fs->clusters > ((__u64)fs->fat_size*8/fs->fat_bits)-2)\r
+       die("File system has %d clusters but only space for %d FAT entries.",\r
+         fs->clusters,((__u64)fs->fat_size*8/fs->fat_bits)-2);\r
+    if (!fs->root_entries && !fs->root_cluster)\r
+       die("Root directory has zero size.");\r
+    if (fs->root_entries & (MSDOS_DPS-1))\r
+       die("Root directory (%d entries) doesn't span an integral number of "\r
+         "sectors.",fs->root_entries);\r
+    if (logical_sector_size & (SECTOR_SIZE-1))\r
+       die("Logical sector size (%d bytes) is not a multiple of the physical "\r
+         "sector size.",logical_sector_size);\r
+    /* ++roman: On Atari, these two fields are often left uninitialized */\r
+    if (!atari_format && (!b.secs_track || !b.heads))\r
+       die("Invalid disk format in boot sector.");\r
+    if (verbose) dump_boot(fs,&b,logical_sector_size);\r
+}\r
+\r
+/* Local Variables: */\r
+/* tab-width: 8     */\r
+/* End:             */\r
index 0540c70..63cbcf0 100644 (file)
@@ -1,13 +1,13 @@
-/* boot.h  -  Read and analyze ia PC/MS-DOS boot sector */
-
-/* Written 1993 by Werner Almesberger */
-
-
-#ifndef _BOOT_H
-#define _BOOT_H
-
-void read_boot(DOS_FS *fs);
-
-/* Reads the boot sector from the currently open device and initializes *FS */
-
-#endif
+/* boot.h  -  Read and analyze ia PC/MS-DOS boot sector */\r
+\r
+/* Written 1993 by Werner Almesberger */\r
+\r
+\r
+#ifndef _BOOT_H\r
+#define _BOOT_H\r
+\r
+void read_boot(DOS_FS *fs);\r
+\r
+/* Reads the boot sector from the currently open device and initializes *FS */\r
+\r
+#endif\r
index 07ab6eb..15b87c0 100644 (file)
@@ -1,59 +1,59 @@
-#ifndef _I386_BYTEORDER_H
-#define _I386_BYTEORDER_H
-
-//#include "types.h"
-#include "compiler.h"
-
-#ifdef __GNUC__
-
-/* For avoiding bswap on i386 */
-//#ifdef __KERNEL__
-//#include <linux/config.h>
-//#endif
-
-static __inline__ __attribute_const__ __u32 ___arch__swab32(__u32 x)
-{
-#ifdef CONFIG_X86_BSWAP
-       __asm__("bswap %0" : "=r" (x) : "0" (x));
-#else
-       __asm__("xchgb %b0,%h0\n\t"     /* swap lower bytes     */
-               "rorl $16,%0\n\t"       /* swap words           */
-               "xchgb %b0,%h0"         /* swap higher bytes    */
-               :"=q" (x)
-               : "0" (x));
-#endif
-       return x;
-}
-
-static __inline__ __attribute_const__ __u64 ___arch__swab64(__u64 val)
-{ 
-       union { 
-               struct { __u32 a,b; } s;
-               __u64 u;
-       } v;
-       v.u = val;
-#ifdef CONFIG_X86_BSWAP
-       asm("bswapl %0 ; bswapl %1 ; xchgl %0,%1" 
-           : "=r" (v.s.a), "=r" (v.s.b) 
-           : "0" (v.s.a), "1" (v.s.b)); 
-#else
-   v.s.a = ___arch__swab32(v.s.a); 
-       v.s.b = ___arch__swab32(v.s.b); 
-       asm("xchgl %0,%1" : "=r" (v.s.a), "=r" (v.s.b) : "0" (v.s.a), "1" (v.s.b));
-#endif
-       return v.u;     
-} 
-
-/* Do not define swab16.  Gcc is smart enough to recognize "C" version and
-   convert it into rotation or exhange.  */
-
-#define __arch__swab64(x) ___arch__swab64(x)
-#define __arch__swab32(x) ___arch__swab32(x)
-
-#define __BYTEORDER_HAS_U64__
-
-#endif /* __GNUC__ */
-
-//#include "little_endian.h"
-
-#endif /* _I386_BYTEORDER_H */
+#ifndef _I386_BYTEORDER_H\r
+#define _I386_BYTEORDER_H\r
+\r
+//#include "types.h"\r
+#include "compiler.h"\r
+\r
+#ifdef __GNUC__\r
+\r
+/* For avoiding bswap on i386 */\r
+//#ifdef __KERNEL__\r
+//#include <linux/config.h>\r
+//#endif\r
+\r
+static __inline__ __attribute_const__ __u32 ___arch__swab32(__u32 x)\r
+{\r
+#ifdef CONFIG_X86_BSWAP\r
+       __asm__("bswap %0" : "=r" (x) : "0" (x));\r
+#else\r
+       __asm__("xchgb %b0,%h0\n\t"     /* swap lower bytes     */\r
+               "rorl $16,%0\n\t"       /* swap words           */\r
+               "xchgb %b0,%h0"         /* swap higher bytes    */\r
+               :"=q" (x)\r
+               : "0" (x));\r
+#endif\r
+       return x;\r
+}\r
+\r
+static __inline__ __attribute_const__ __u64 ___arch__swab64(__u64 val)\r
+{ \r
+       union { \r
+               struct { __u32 a,b; } s;\r
+               __u64 u;\r
+       } v;\r
+       v.u = val;\r
+#ifdef CONFIG_X86_BSWAP\r
+       asm("bswapl %0 ; bswapl %1 ; xchgl %0,%1" \r
+           : "=r" (v.s.a), "=r" (v.s.b) \r
+           : "0" (v.s.a), "1" (v.s.b)); \r
+#else\r
+   v.s.a = ___arch__swab32(v.s.a); \r
+       v.s.b = ___arch__swab32(v.s.b); \r
+       asm("xchgl %0,%1" : "=r" (v.s.a), "=r" (v.s.b) : "0" (v.s.a), "1" (v.s.b));\r
+#endif\r
+       return v.u;     \r
+} \r
+\r
+/* Do not define swab16.  Gcc is smart enough to recognize "C" version and\r
+   convert it into rotation or exhange.  */\r
+\r
+#define __arch__swab64(x) ___arch__swab64(x)\r
+#define __arch__swab32(x) ___arch__swab32(x)\r
+\r
+#define __BYTEORDER_HAS_U64__\r
+\r
+#endif /* __GNUC__ */\r
+\r
+//#include "little_endian.h"\r
+\r
+#endif /* _I386_BYTEORDER_H */\r
index 0cf37c1..4a09eb6 100644 (file)
@@ -1,40 +1,40 @@
-/* Copyright (C) 1997 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, write to the Free
-   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-   02111-1307 USA.  */
-
-#ifndef _BYTESWAP_H
-#define _BYTESWAP_H    1
-
-/* Get the machine specific, optimized definitions.  */
-#include "byteswap1.h"
-
-
-/* The following definitions must all be macros since otherwise some
-   of the possible optimizations are not possible.  */
-
-/* Return a value with all bytes in the 16 bit argument swapped.  */
-#define bswap_16(x) __bswap_16 (x)
-
-/* Return a value with all bytes in the 32 bit argument swapped.  */
-#define bswap_32(x) __bswap_32 (x)
-
-#if defined __GNUC__ && __GNUC__ >= 2
-/* Return a value with all bytes in the 64 bit argument swapped.  */
-# define bswap_64(x) __bswap_64 (x)
-#endif
-
-#endif /* byteswap.h */
+/* Copyright (C) 1997 Free Software Foundation, Inc.\r
+   This file is part of the GNU C Library.\r
+\r
+   The GNU C Library is free software; you can redistribute it and/or\r
+   modify it under the terms of the GNU Lesser General Public\r
+   License as published by the Free Software Foundation; either\r
+   version 2.1 of the License, or (at your option) any later version.\r
+\r
+   The GNU C Library is distributed in the hope that it will be useful,\r
+   but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+   Lesser General Public License for more details.\r
+\r
+   You should have received a copy of the GNU Lesser General Public\r
+   License along with the GNU C Library; if not, write to the Free\r
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA\r
+   02111-1307 USA.  */\r
+\r
+#ifndef _BYTESWAP_H\r
+#define _BYTESWAP_H    1\r
+\r
+/* Get the machine specific, optimized definitions.  */\r
+#include "byteswap1.h"\r
+\r
+\r
+/* The following definitions must all be macros since otherwise some\r
+   of the possible optimizations are not possible.  */\r
+\r
+/* Return a value with all bytes in the 16 bit argument swapped.  */\r
+#define bswap_16(x) __bswap_16 (x)\r
+\r
+/* Return a value with all bytes in the 32 bit argument swapped.  */\r
+#define bswap_32(x) __bswap_32 (x)\r
+\r
+#if defined __GNUC__ && __GNUC__ >= 2\r
+/* Return a value with all bytes in the 64 bit argument swapped.  */\r
+# define bswap_64(x) __bswap_64 (x)\r
+#endif\r
+\r
+#endif /* byteswap.h */\r
index 33af208..1e5d466 100644 (file)
-/* Macros to swap the order of bytes in integer values.
-   Copyright (C) 1997, 1998, 2000, 2002, 2003 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, write to the Free
-   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-   02111-1307 USA.  */
-
-#if !defined _BYTESWAP_H && !defined _NETINET_IN_H
-# error "Never use <bits/byteswap.h> directly; include <byteswap.h> instead."
-#endif
-
-#ifndef _BITS_BYTESWAP_H
-#define _BITS_BYTESWAP_H 1
-
-/* Swap bytes in 16 bit value.  */
-#define __bswap_constant_16(x) \
-     ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8))
-
-#ifdef __GNUC__
-# if __GNUC__ >= 2
-#  define __bswap_16(x) \
-     (__extension__                                                          \
-      ({ register unsigned short int __v, __x = (x);                         \
-        if (__builtin_constant_p (__x))                                      \
-          __v = __bswap_constant_16 (__x);                                   \
-        else                                                                 \
-          __asm__ ("rorw $8, %w0"                                            \
-                   : "=r" (__v)                                              \
-                   : "0" (__x)                                               \
-                   : "cc");                                                  \
-        __v; }))
-# else
-/* This is better than nothing.  */
-#  define __bswap_16(x) \
-     (__extension__                                                          \
-      ({ register unsigned short int __x = (x); __bswap_constant_16 (__x); }))
-# endif
-#else
-static __inline unsigned short int
-__bswap_16 (unsigned short int __bsx)
-{
-  return __bswap_constant_16 (__bsx);
-}
-#endif
-
-/* Swap bytes in 32 bit value.  */
-#define __bswap_constant_32(x) \
-     ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >>  8) |                      \
-      (((x) & 0x0000ff00) <<  8) | (((x) & 0x000000ff) << 24))
-
-#ifdef __GNUC__
-# if __GNUC__ >= 2
-/* To swap the bytes in a word the i486 processors and up provide the
-   `bswap' opcode.  On i386 we have to use three instructions.  */
-#  if !defined __i486__ && !defined __pentium__ && !defined __pentiumpro__ \
-      && !defined __pentium4__
-#   define __bswap_32(x)                                                     \
-     (__extension__                                                          \
-      ({ register unsigned int __v, __x = (x);                               \
-        if (__builtin_constant_p (__x))                                      \
-          __v = __bswap_constant_32 (__x);                                   \
-        else                                                                 \
-          __asm__ ("rorw $8, %w0;"                                           \
-                   "rorl $16, %0;"                                           \
-                   "rorw $8, %w0"                                            \
-                   : "=r" (__v)                                              \
-                   : "0" (__x)                                               \
-                   : "cc");                                                  \
-        __v; }))
-#  else
-#   define __bswap_32(x) \
-     (__extension__                                                          \
-      ({ register unsigned int __v, __x = (x);                               \
-        if (__builtin_constant_p (__x))                                      \
-          __v = __bswap_constant_32 (__x);                                   \
-        else                                                                 \
-          __asm__ ("bswap %0" : "=r" (__v) : "0" (__x));                     \
-        __v; }))
-#  endif
-# else
-#  define __bswap_32(x) \
-     (__extension__                                                          \
-      ({ register unsigned int __x = (x); __bswap_constant_32 (__x); }))
-# endif
-#else
-static __inline unsigned int
-__bswap_32 (unsigned int __bsx)
-{
-  return __bswap_constant_32 (__bsx);
-}
-#endif
-
-
-#if defined __GNUC__ && __GNUC__ >= 2
-/* Swap bytes in 64 bit value.  */
-#define __bswap_constant_64(x) \
-     ((((x) & 0xff00000000000000ull) >> 56)                                  \
-      | (((x) & 0x00ff000000000000ull) >> 40)                                \
-      | (((x) & 0x0000ff0000000000ull) >> 24)                                \
-      | (((x) & 0x000000ff00000000ull) >> 8)                                 \
-      | (((x) & 0x00000000ff000000ull) << 8)                                 \
-      | (((x) & 0x0000000000ff0000ull) << 24)                                \
-      | (((x) & 0x000000000000ff00ull) << 40)                                \
-      | (((x) & 0x00000000000000ffull) << 56))
-
-# define __bswap_64(x) \
-     (__extension__                                                          \
-      ({ union { __extension__ unsigned long long int __ll;                  \
-                unsigned long int __l[2]; } __w, __r;                        \
-         if (__builtin_constant_p (x))                                       \
-          __r.__ll = __bswap_constant_64 (x);                                \
-        else                                                                 \
-          {                                                                  \
-            __w.__ll = (x);                                                  \
-            __r.__l[0] = __bswap_32 (__w.__l[1]);                            \
-            __r.__l[1] = __bswap_32 (__w.__l[0]);                            \
-          }                                                                  \
-        __r.__ll; }))
-#endif
-
-#endif /* _BITS_BYTESWAP_H */
+/* Macros to swap the order of bytes in integer values.\r
+   Copyright (C) 1997, 1998, 2000, 2002, 2003 Free Software Foundation, Inc.\r
+   This file is part of the GNU C Library.\r
+\r
+   The GNU C Library is free software; you can redistribute it and/or\r
+   modify it under the terms of the GNU Lesser General Public\r
+   License as published by the Free Software Foundation; either\r
+   version 2.1 of the License, or (at your option) any later version.\r
+\r
+   The GNU C Library is distributed in the hope that it will be useful,\r
+   but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+   Lesser General Public License for more details.\r
+\r
+   You should have received a copy of the GNU Lesser General Public\r
+   License along with the GNU C Library; if not, write to the Free\r
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA\r
+   02111-1307 USA.  */\r
+\r
+#if !defined _BYTESWAP_H && !defined _NETINET_IN_H\r
+# error "Never use <bits/byteswap.h> directly; include <byteswap.h> instead."\r
+#endif\r
+\r
+#ifndef _BITS_BYTESWAP_H\r
+#define _BITS_BYTESWAP_H 1\r
+\r
+/* Swap bytes in 16 bit value.  */\r
+#define __bswap_constant_16(x) \\r
+     ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8))\r
+\r
+#ifdef __GNUC__\r
+# if __GNUC__ >= 2\r
+#  define __bswap_16(x) \\r
+     (__extension__                                                          \\r
+      ({ register unsigned short int __v, __x = (x);                         \\r
+        if (__builtin_constant_p (__x))                                      \\r
+          __v = __bswap_constant_16 (__x);                                   \\r
+        else                                                                 \\r
+          __asm__ ("rorw $8, %w0"                                            \\r
+                   : "=r" (__v)                                              \\r
+                   : "0" (__x)                                               \\r
+                   : "cc");                                                  \\r
+        __v; }))\r
+# else\r
+/* This is better than nothing.  */\r
+#  define __bswap_16(x) \\r
+     (__extension__                                                          \\r
+      ({ register unsigned short int __x = (x); __bswap_constant_16 (__x); }))\r
+# endif\r
+#else\r
+static __inline unsigned short int\r
+__bswap_16 (unsigned short int __bsx)\r
+{\r
+  return __bswap_constant_16 (__bsx);\r
+}\r
+#endif\r
+\r
+/* Swap bytes in 32 bit value.  */\r
+#define __bswap_constant_32(x) \\r
+     ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >>  8) |                      \\r
+      (((x) & 0x0000ff00) <<  8) | (((x) & 0x000000ff) << 24))\r
+\r
+#ifdef __GNUC__\r
+# if __GNUC__ >= 2\r
+/* To swap the bytes in a word the i486 processors and up provide the\r
+   `bswap' opcode.  On i386 we have to use three instructions.  */\r
+#  if !defined __i486__ && !defined __pentium__ && !defined __pentiumpro__ \\r
+      && !defined __pentium4__\r
+#   define __bswap_32(x)                                                     \\r
+     (__extension__                                                          \\r
+      ({ register unsigned int __v, __x = (x);                               \\r
+        if (__builtin_constant_p (__x))                                      \\r
+          __v = __bswap_constant_32 (__x);                                   \\r
+        else                                                                 \\r
+          __asm__ ("rorw $8, %w0;"                                           \\r
+                   "rorl $16, %0;"                                           \\r
+                   "rorw $8, %w0"                                            \\r
+                   : "=r" (__v)                                              \\r
+                   : "0" (__x)                                               \\r
+                   : "cc");                                                  \\r
+        __v; }))\r
+#  else\r
+#   define __bswap_32(x) \\r
+     (__extension__                                                          \\r
+      ({ register unsigned int __v, __x = (x);                               \\r
+        if (__builtin_constant_p (__x))                                      \\r
+          __v = __bswap_constant_32 (__x);                                   \\r
+        else                                                                 \\r
+          __asm__ ("bswap %0" : "=r" (__v) : "0" (__x));                     \\r
+        __v; }))\r
+#  endif\r
+# else\r
+#  define __bswap_32(x) \\r
+     (__extension__                                                          \\r
+      ({ register unsigned int __x = (x); __bswap_constant_32 (__x); }))\r
+# endif\r
+#else\r
+static __inline unsigned int\r
+__bswap_32 (unsigned int __bsx)\r
+{\r
+  return __bswap_constant_32 (__bsx);\r
+}\r
+#endif\r
+\r
+\r
+#if defined __GNUC__ && __GNUC__ >= 2\r
+/* Swap bytes in 64 bit value.  */\r
+#define __bswap_constant_64(x) \\r
+     ((((x) & 0xff00000000000000ull) >> 56)                                  \\r
+      | (((x) & 0x00ff000000000000ull) >> 40)                                \\r
+      | (((x) & 0x0000ff0000000000ull) >> 24)                                \\r
+      | (((x) & 0x000000ff00000000ull) >> 8)                                 \\r
+      | (((x) & 0x00000000ff000000ull) << 8)                                 \\r
+      | (((x) & 0x0000000000ff0000ull) << 24)                                \\r
+      | (((x) & 0x000000000000ff00ull) << 40)                                \\r
+      | (((x) & 0x00000000000000ffull) << 56))\r
+\r
+# define __bswap_64(x) \\r
+     (__extension__                                                          \\r
+      ({ union { __extension__ unsigned long long int __ll;                  \\r
+                unsigned long int __l[2]; } __w, __r;                        \\r
+         if (__builtin_constant_p (x))                                       \\r
+          __r.__ll = __bswap_constant_64 (x);                                \\r
+        else                                                                 \\r
+          {                                                                  \\r
+            __w.__ll = (x);                                                  \\r
+            __r.__l[0] = __bswap_32 (__w.__l[1]);                            \\r
+            __r.__l[1] = __bswap_32 (__w.__l[0]);                            \\r
+          }                                                                  \\r
+        __r.__ll; }))\r
+#endif\r
+\r
+#endif /* _BITS_BYTESWAP_H */\r
index a7c384a..425bd20 100644 (file)
-/* check.c  -  Check and repair a PC/MS-DOS file system */
-
-/* Written 1993 by Werner Almesberger */
-
-/* FAT32, VFAT, Atari format support, and various fixes additions May 1998
- * by Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> */
-
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <limits.h>
+/* check.c  -  Check and repair a PC/MS-DOS file system */\r
+\r
+/* Written 1993 by Werner Almesberger */\r
+\r
+/* FAT32, VFAT, Atari format support, and various fixes additions May 1998\r
+ * by Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> */\r
+\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include <limits.h>\r
 #include <time.h>\r
-#include <windows.h>
-
-#include "common.h"
-#include "dosfsck.h"
-#include "io.h"
-#include "fat.h"
-#include "file.h"
-#include "lfn.h"
-#include "check.h"
-
-
-static DOS_FILE *root;
-
-/* get start field of a dir entry */
-#define FSTART(p,fs) \
-  ((unsigned long)CF_LE_W(p->dir_ent.start) | \
-   (fs->fat_bits == 32 ? CF_LE_W(p->dir_ent.starthi) << 16 : 0))
-
-#define MODIFY(p,i,v)                                  \
-  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)
-
-#define MODIFY_START(p,v,fs)                                           \
-  do {                                                                 \
-    unsigned long __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 = CT_LE_W(__v&0xffff);                         \
-       p->dir_ent.starthi = CT_LE_W(__v>>16);                          \
-       __v = CT_LE_L(__v);                                             \
-       fs_write((loff_t)offsetof(struct boot_sector,root_cluster),     \
-                sizeof(((struct boot_sector *)0)->root_cluster),       \
-                &__v);                                                 \
-    }                                                                  \
-    else {                                                             \
-       MODIFY(p,start,CT_LE_W((__v)&0xffff));                          \
-       if (fs->fat_bits == 32)                                         \
-           MODIFY(p,starthi,CT_LE_W((__v)>>16));                       \
-    }                                                                  \
-  } while(0)
-
-
-loff_t alloc_rootdir_entry(DOS_FS *fs, DIR_ENT *de, const char *pattern)
-{
-    static int curr_num = 0;
-    loff_t offset;
-
-    if (fs->root_cluster) {
-       DIR_ENT d2;
-       int i = 0, got = 0;
-       unsigned long clu_num, prev = 0;
-       loff_t offset2;
-       
-       clu_num = fs->root_cluster;
-       offset = cluster_start(fs,clu_num);
-       while (clu_num > 0 && clu_num != -1) {
-           fs_read(offset,sizeof(DIR_ENT),&d2);
-           if (IS_FREE(d2.name) && d2.attr != VFAT_LN_ATTR) {
-               got = 1;
-               break;
-           }
-           i += sizeof(DIR_ENT);
-           offset += sizeof(DIR_ENT);
-           if ((i % fs->cluster_size) == 0) {
-               prev = clu_num;
-               if ((clu_num = next_cluster(fs,clu_num)) == 0 || clu_num == -1)
-                   break;
-               offset = cluster_start(fs,clu_num);
-           }
-       }
-       if (!got) {
-           /* no free slot, need to extend root dir: alloc next free cluster
-            * after previous one */
-           if (!prev)
-               die("Root directory has no cluster allocated!");
-           for (clu_num = prev+1; clu_num != prev; clu_num++) {
-               if (clu_num >= fs->clusters+2) clu_num = 2;
-               if (!fs->fat[clu_num].value)
-                   break;
-           }
-           if (clu_num == prev)
-               die("Root directory full and no free cluster");
-           set_fat(fs,prev,clu_num);
-           set_fat(fs,clu_num,-1);
-           set_owner(fs, clu_num, get_owner(fs, fs->root_cluster));
-           /* clear new cluster */
-           memset( &d2, 0, sizeof(d2) );
-           offset = cluster_start(fs,clu_num);
-           for( i = 0; i < (int)fs->cluster_size; i += sizeof(DIR_ENT) )
-               fs_write( offset+i, sizeof(d2), &d2 );
-       }
-       memset(de,0,sizeof(DIR_ENT));
-       while (1) {
-           sprintf(de->name,pattern,curr_num);
-           clu_num = fs->root_cluster;
-           i = 0;
-           offset2 = cluster_start(fs,clu_num);
-           while (clu_num > 0 && clu_num != -1) {
-               fs_read(offset2,sizeof(DIR_ENT),&d2);
-               if (offset2 != offset &&
-                   !strncmp(d2.name,de->name,MSDOS_NAME))
-                   break;
-               i += sizeof(DIR_ENT);
-               offset2 += sizeof(DIR_ENT);
-               if ((i % fs->cluster_size) == 0) {
-                   if ((clu_num = next_cluster(fs,clu_num)) == 0 ||
-                       clu_num == -1)
-                       break;
-                   offset2 = cluster_start(fs,clu_num);
-               }
-           }
-           if (clu_num == 0 || clu_num == -1)
-               break;
-           if (++curr_num >= 10000) die("Unable to create unique name");
-       }
-    }
-    else {
-       DIR_ENT *root;
-       int next_free = 0, scan;
-
-       root = alloc(fs->root_entries*sizeof(DIR_ENT));
-       fs_read(fs->root_start,fs->root_entries*sizeof(DIR_ENT),root);
-
-       while (next_free < (int)fs->root_entries)
-           if (IS_FREE(root[next_free].name) &&
-               root[next_free].attr != VFAT_LN_ATTR)
-               break;
-           else next_free++;
-       if (next_free == (int)fs->root_entries)
-           die("Root directory is full.");
-       offset = fs->root_start+next_free*sizeof(DIR_ENT);
-       memset(de,0,sizeof(DIR_ENT));
-       while (1) {
-           sprintf(de->name,pattern,curr_num);
-           for (scan = 0; scan < (int)fs->root_entries; scan++)
-               if (scan != next_free &&
-                   !strncmp(root[scan].name,de->name,MSDOS_NAME))
-                   break;
-           if (scan == (int)fs->root_entries) break;
-           if (++curr_num >= 10000) die("Unable to create unique name");
-       }
-       free(root);
-    }
-    ++n_files;
-    return offset;
-}
-
-
-static char *path_name(DOS_FILE *file)
-{
+#include <windows.h>\r
+\r
+#include "common.h"\r
+#include "dosfsck.h"\r
+#include "io.h"\r
+#include "fat.h"\r
+#include "file.h"\r
+#include "lfn.h"\r
+#include "check.h"\r
+\r
+\r
+static DOS_FILE *root;\r
+\r
+/* get start field of a dir entry */\r
+#define FSTART(p,fs) \\r
+  ((unsigned long)CF_LE_W(p->dir_ent.start) | \\r
+   (fs->fat_bits == 32 ? CF_LE_W(p->dir_ent.starthi) << 16 : 0))\r
+\r
+#define MODIFY(p,i,v)                                  \\r
+  do {                                                 \\r
+    if (p->offset) {                                   \\r
+       p->dir_ent.i = v;                               \\r
+       fs_write(p->offset+offsetof(DIR_ENT,i),         \\r
+                sizeof(p->dir_ent.i),&p->dir_ent.i);   \\r
+    }                                                  \\r
+  } while(0)\r
+\r
+#define MODIFY_START(p,v,fs)                                           \\r
+  do {                                                                 \\r
+    unsigned long __v = (v);                                           \\r
+    if (!p->offset) {                                                  \\r
+       /* writing to fake entry for FAT32 root dir */                  \\r
+       if (!__v) die("Oops, deleting FAT32 root dir!");                \\r
+       fs->root_cluster = __v;                                         \\r
+       p->dir_ent.start = CT_LE_W(__v&0xffff);                         \\r
+       p->dir_ent.starthi = CT_LE_W(__v>>16);                          \\r
+       __v = CT_LE_L(__v);                                             \\r
+       fs_write((loff_t)offsetof(struct boot_sector,root_cluster),     \\r
+                sizeof(((struct boot_sector *)0)->root_cluster),       \\r
+                &__v);                                                 \\r
+    }                                                                  \\r
+    else {                                                             \\r
+       MODIFY(p,start,CT_LE_W((__v)&0xffff));                          \\r
+       if (fs->fat_bits == 32)                                         \\r
+           MODIFY(p,starthi,CT_LE_W((__v)>>16));                       \\r
+    }                                                                  \\r
+  } while(0)\r
+\r
+\r
+loff_t alloc_rootdir_entry(DOS_FS *fs, DIR_ENT *de, const char *pattern)\r
+{\r
+    static int curr_num = 0;\r
+    loff_t offset;\r
+\r
+    if (fs->root_cluster) {\r
+       DIR_ENT d2;\r
+       int i = 0, got = 0;\r
+       unsigned long clu_num, prev = 0;\r
+       loff_t offset2;\r
+       \r
+       clu_num = fs->root_cluster;\r
+       offset = cluster_start(fs,clu_num);\r
+       while (clu_num > 0 && clu_num != -1) {\r
+           fs_read(offset,sizeof(DIR_ENT),&d2);\r
+           if (IS_FREE(d2.name) && d2.attr != VFAT_LN_ATTR) {\r
+               got = 1;\r
+               break;\r
+           }\r
+           i += sizeof(DIR_ENT);\r
+           offset += sizeof(DIR_ENT);\r
+           if ((i % fs->cluster_size) == 0) {\r
+               prev = clu_num;\r
+               if ((clu_num = next_cluster(fs,clu_num)) == 0 || clu_num == -1)\r
+                   break;\r
+               offset = cluster_start(fs,clu_num);\r
+           }\r
+       }\r
+       if (!got) {\r
+           /* no free slot, need to extend root dir: alloc next free cluster\r
+            * after previous one */\r
+           if (!prev)\r
+               die("Root directory has no cluster allocated!");\r
+           for (clu_num = prev+1; clu_num != prev; clu_num++) {\r
+               if (clu_num >= fs->clusters+2) clu_num = 2;\r
+               if (!fs->fat[clu_num].value)\r
+                   break;\r
+           }\r
+           if (clu_num == prev)\r
+               die("Root directory full and no free cluster");\r
+           set_fat(fs,prev,clu_num);\r
+           set_fat(fs,clu_num,-1);\r
+           set_owner(fs, clu_num, get_owner(fs, fs->root_cluster));\r
+           /* clear new cluster */\r
+           memset( &d2, 0, sizeof(d2) );\r
+           offset = cluster_start(fs,clu_num);\r
+           for( i = 0; i < (int)fs->cluster_size; i += sizeof(DIR_ENT) )\r
+               fs_write( offset+i, sizeof(d2), &d2 );\r
+       }\r
+       memset(de,0,sizeof(DIR_ENT));\r
+       while (1) {\r
+           sprintf(de->name,pattern,curr_num);\r
+           clu_num = fs->root_cluster;\r
+           i = 0;\r
+           offset2 = cluster_start(fs,clu_num);\r
+           while (clu_num > 0 && clu_num != -1) {\r
+               fs_read(offset2,sizeof(DIR_ENT),&d2);\r
+               if (offset2 != offset &&\r
+                   !strncmp(d2.name,de->name,MSDOS_NAME))\r
+                   break;\r
+               i += sizeof(DIR_ENT);\r
+               offset2 += sizeof(DIR_ENT);\r
+               if ((i % fs->cluster_size) == 0) {\r
+                   if ((clu_num = next_cluster(fs,clu_num)) == 0 ||\r
+                       clu_num == -1)\r
+                       break;\r
+                   offset2 = cluster_start(fs,clu_num);\r
+               }\r
+           }\r
+           if (clu_num == 0 || clu_num == -1)\r
+               break;\r
+           if (++curr_num >= 10000) die("Unable to create unique name");\r
+       }\r
+    }\r
+    else {\r
+       DIR_ENT *root;\r
+       int next_free = 0, scan;\r
+\r
+       root = alloc(fs->root_entries*sizeof(DIR_ENT));\r
+       fs_read(fs->root_start,fs->root_entries*sizeof(DIR_ENT),root);\r
+\r
+       while (next_free < (int)fs->root_entries)\r
+           if (IS_FREE(root[next_free].name) &&\r
+               root[next_free].attr != VFAT_LN_ATTR)\r
+               break;\r
+           else next_free++;\r
+       if (next_free == (int)fs->root_entries)\r
+           die("Root directory is full.");\r
+       offset = fs->root_start+next_free*sizeof(DIR_ENT);\r
+       memset(de,0,sizeof(DIR_ENT));\r
+       while (1) {\r
+           sprintf(de->name,pattern,curr_num);\r
+           for (scan = 0; scan < (int)fs->root_entries; scan++)\r
+               if (scan != next_free &&\r
+                   !strncmp(root[scan].name,de->name,MSDOS_NAME))\r
+                   break;\r
+           if (scan == (int)fs->root_entries) break;\r
+           if (++curr_num >= 10000) die("Unable to create unique name");\r
+       }\r
+       free(root);\r
+    }\r
+    ++n_files;\r
+    return offset;\r
+}\r
+\r
+\r
+static char *path_name(DOS_FILE *file)\r
+{\r
 //    static char path[PATH_MAX*2];\r
-    static char path[MAX_PATH*2];
-
-    if (!file) *path = 0;
-    else {
-       if (strlen(path_name(file->parent)) > MAX_PATH)
-           die("Path name too long.");
-       if (strcmp(path,"/") != 0) strcat(path,"/");
-       strcpy(strrchr(path,0),file->lfn?file->lfn:file_name(file->dir_ent.name));
-    }
-    return path;
-}
-
-
-static int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 };
-                 /* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */
-
-
-/* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
-
-time_t date_dos2unix(unsigned short time,unsigned short date)
-{
-    int month,year;
-    time_t secs;
-
-    month = ((date >> 5) & 15)-1;
-    year = date >> 9;
-    secs = (time & 31)*2+60*((time >> 5) & 63)+(time >> 11)*3600+86400*
-      ((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 &&
-      month < 2 ? 1 : 0)+3653);
-                       /* days since 1.1.70 plus 80's leap day */
-    return secs;
-}
-
-
-static char *file_stat(DOS_FILE *file)
-{
-    static char temp[100];
-    struct tm *tm;
-    char tmp[100];
-    time_t date;
-
-    date = date_dos2unix(CF_LE_W(file->dir_ent.time),CF_LE_W(file->
-      dir_ent.date));
-    tm = localtime(&date);
-    strftime(tmp,99,"%H:%M:%S %b %d %Y",tm);
-    sprintf(temp,"  Size %u bytes, date %s",CF_LE_L(file->dir_ent.size),tmp);
-    return temp;
-}
-
-
-static int bad_name(unsigned char *name)
-{
-    int i, spc, suspicious = 0;
-    char *bad_chars = atari_format ? "*?\\/:" : "*?<>|\"\\/:";
-
-    /* Do not complain about (and auto-correct) the extended attribute files
-     * of OS/2. */
-    if (strncmp(name,"EA DATA  SF",11) == 0 ||
-        strncmp(name,"WP ROOT  SF",11) == 0) return 0;
-    
-    for (i = 0; i < 8; i++) {
-       if (name[i] < ' ' || name[i] == 0x7f) return 1;
-       if (name[i] > 0x7f) ++suspicious;
-       if (strchr(bad_chars,name[i])) return 1;
-    }
-
-    for (i = 8; i < 11; i++) {
-       if (name[i] < ' ' || name[i] == 0x7f) return 1;
-       if (name[i] > 0x7f) ++suspicious;
-       if (strchr(bad_chars,name[i])) return 1;
-    }
-
-    spc = 0;
-    for (i = 0; i < 8; i++) {
-       if (name[i] == ' ')
-           spc = 1;
-       else if (spc)
-           /* non-space after a space not allowed, space terminates the name
-            * part */
-           return 1;
-    }
-
-    spc = 0;
-    for (i = 8; i < 11; i++) {
-       if (name[i] == ' ')
-           spc = 1;
-       else if (spc)
-           /* non-space after a space not allowed, space terminates the name
-            * part */
-           return 1;
-    }
-
-    /* Under GEMDOS, chars >= 128 are never allowed. */
-    if (atari_format && suspicious)
-       return 1;
-    
-    /* Only complain about too much suspicious chars in interactive mode,
-     * never correct them automatically. The chars are all basically ok, so we
-     * shouldn't auto-correct such names. */
-    if (interactive && suspicious > 6)
-       return 1;
-    return 0;
-}
-
-
-static void drop_file(DOS_FS *fs,DOS_FILE *file)
-{
-    unsigned long cluster;
-
-    MODIFY(file,name[0],DELETED_FLAG);
-    for (cluster = FSTART(file,fs); cluster > 0 && cluster <
-      fs->clusters+2; cluster = next_cluster(fs,cluster))
-       set_owner(fs,cluster,NULL);
-    --n_files;
-}
-
-
-static void truncate_file(DOS_FS *fs,DOS_FILE *file,unsigned long clusters)
-{
-    int deleting;
-    unsigned long walk,next,prev;
-    
-    walk = FSTART(file,fs);
-    prev = 0;
-    if ((deleting = !clusters)) MODIFY_START(file,0,fs);
-    while (walk > 0 && walk != -1) {
-       next = next_cluster(fs,walk);
-       if (deleting) set_fat(fs,walk,0);
-       else if ((deleting = !--clusters)) set_fat(fs,walk,-1);
-       prev = walk;
-       walk = next;
-    }
-}
-
-
-static void auto_rename(DOS_FILE *file)
-{
-    DOS_FILE *first,*walk;
-    int number;
-
-    if (!file->offset) return; /* cannot rename FAT32 root dir */
-    first = file->parent ? file->parent->first : root;
-    number = 0;
-    while (1) {
-       sprintf(file->dir_ent.name,"FSCK%04d",number);
-       strncpy(file->dir_ent.ext,"REN",3);
-       for (walk = first; walk; walk = walk->next)
-           if (walk != file && !strncmp(walk->dir_ent.name,file->dir_ent.
-             name,MSDOS_NAME)) break;
-       if (!walk) {
-           fs_write(file->offset,MSDOS_NAME,file->dir_ent.name);
-           return;
-       }
-       number++;
-    }
-    die("Can't generate a unique name.");
-}
-
-
-static void rename_file(DOS_FILE *file)
-{
-    unsigned char name[46];
-    unsigned char *walk,*here;
-
-    if (!file->offset) {
-       printf( "Cannot rename FAT32 root dir\n" );
-       return; /* cannot rename FAT32 root dir */
-    }
-    while (1) {
-       printf("New name: ");
-       fflush(stdout);
-       if (fgets(name,45,stdin)) {
-           if ((here = strchr(name,'\n'))) *here = 0;
-           for (walk = strrchr(name,0); walk >= name && (*walk == ' ' ||
-             *walk == '\t'); walk--);
-           walk[1] = 0;
-           for (walk = name; *walk == ' ' || *walk == '\t'; walk++);
-           if (file_cvt(walk,file->dir_ent.name)) {
-               fs_write(file->offset,MSDOS_NAME,file->dir_ent.name);
-               return;
-           }
-       }
-    }
-}
-
-
-static int handle_dot(DOS_FS *fs,DOS_FILE *file,int dots)
-{
-    char *name;
-
-    name = strncmp(file->dir_ent.name,MSDOS_DOT,MSDOS_NAME) ? ".." : ".";
-    if (!(file->dir_ent.attr & ATTR_DIR)) {
-       printf("%s\n  Is a non-directory.\n",path_name(file));
-       if (interactive)
-           printf("1) Drop it\n2) Auto-rename\n3) Rename\n"
-             "4) Convert to directory\n");
-       else printf("  Auto-renaming it.\n");
-       switch (interactive ? get_key("1234","?") : '2') {
-           case '1':
-               drop_file(fs,file);
-               return 1;
-           case '2':
-               auto_rename(file);
-               printf("  Renamed to %s\n",file_name(file->dir_ent.name));
-               return 0;
-           case '3':
-               rename_file(file);
-               return 0;
-           case '4':
-               MODIFY(file,size,CT_LE_L(0));
-               MODIFY(file,attr,file->dir_ent.attr | ATTR_DIR);
-               break;
-       }
-    }
-    if (!dots) {
-       printf("Root contains directory \"%s\". Dropping it.\n",name);
-       drop_file(fs,file);
-       return 1;
-    }
-    return 0;
-}
-
-
-static int check_file(DOS_FS *fs,DOS_FILE *file)
-{
-    DOS_FILE *owner;
-    int restart;
-    unsigned long expect,curr,this,clusters,prev,walk,clusters2;
-
-    if (file->dir_ent.attr & ATTR_DIR) {
-       if (CF_LE_L(file->dir_ent.size)) {
-           printf("%s\n  Directory has non-zero size. Fixing it.\n",
-             path_name(file));
-           MODIFY(file,size,CT_LE_L(0));
-       }
-       if (file->parent && !strncmp(file->dir_ent.name,MSDOS_DOT,MSDOS_NAME)) {
-           expect = FSTART(file->parent,fs);
-           if (FSTART(file,fs) != expect) {
-               printf("%s\n  Start (%ld) does not point to parent (%ld)\n",
-                 path_name(file),FSTART(file,fs),expect);
-               MODIFY_START(file,expect,fs);
-           }
-           return 0;
-       }
-       if (file->parent && !strncmp(file->dir_ent.name,MSDOS_DOTDOT,
-         MSDOS_NAME)) {
-           expect = file->parent->parent ? FSTART(file->parent->parent,fs):0;
-           if (fs->root_cluster && expect == fs->root_cluster)
-               expect = 0;
-           if (FSTART(file,fs) != expect) {
-               printf("%s\n  Start (%lu) does not point to .. (%lu)\n",
-                 path_name(file),FSTART(file,fs),expect);
-               MODIFY_START(file,expect,fs);
-           }
-           return 0;
-       }
-       if (FSTART(file,fs)==0){
-               printf ("%s\n Start does point to root directory. Deleting dir. \n",
-                               path_name(file));
-               MODIFY(file,name[0],DELETED_FLAG);
-               return 0;
-       }
-    }
-    if (FSTART(file,fs) >= fs->clusters+2) {
-       printf("%s\n  Start cluster beyond limit (%lu > %lu). Truncating file.\n",
-         path_name(file),FSTART(file,fs),fs->clusters+1);
-       if (!file->offset)
-           die( "Bad FAT32 root directory! (bad start cluster)\n" );
-       MODIFY_START(file,0,fs);
-    }
-    clusters = prev = 0;
-    for (curr = FSTART(file,fs) ? FSTART(file,fs) :
-      -1; curr != -1; curr = next_cluster(fs,curr)) {
-       if (!fs->fat[curr].value || bad_cluster(fs,curr)) {
-           printf("%s\n  Contains a %s cluster (%lu). Assuming EOF.\n",
-             path_name(file),fs->fat[curr].value ? "bad" : "free",curr);
-           if (prev) set_fat(fs,prev,-1);
-           else if (!file->offset)
-               die( "FAT32 root dir starts with a bad cluster!" );
-           else MODIFY_START(file,0,fs);
-           break;
-       }
-       if (!(file->dir_ent.attr & ATTR_DIR) && CF_LE_L(file->dir_ent.size) <=
-         clusters*fs->cluster_size) {
-           printf("%s\n  File size is %u bytes, cluster chain length is > %lu "
-             "bytes.\n  Truncating file to %u bytes.\n",path_name(file),
-             CF_LE_L(file->dir_ent.size),clusters*fs->cluster_size,
-             CF_LE_L(file->dir_ent.size));
-           truncate_file(fs,file,clusters);
-           break;
-       }
-       if ((owner = get_owner(fs,curr))) {
-           int do_trunc = 0;
-           printf("%s  and\n",path_name(owner));
-           printf("%s\n  share clusters.\n",path_name(file));
-           clusters2 = 0;
-           for (walk = FSTART(owner,fs); walk > 0 && walk != -1; walk =
-             next_cluster(fs,walk))
-               if (walk == curr) break;
-               else clusters2++;
-           restart = file->dir_ent.attr & ATTR_DIR;
-           if (!owner->offset) {
-               printf( "  Truncating second to %lu bytes because first "
-                       "is FAT32 root dir.\n", clusters2*fs->cluster_size );
-               do_trunc = 2;
-           }
-           else if (!file->offset) {
-               printf( "  Truncating first to %lu bytes because second "
-                       "is FAT32 root dir.\n", clusters*fs->cluster_size );
-               do_trunc = 1;
-           }
-           else if (interactive)
-               printf("1) Truncate first to %lu bytes%s\n"
-                 "2) Truncate second to %lu bytes\n",clusters*fs->cluster_size,
-                 restart ? " and restart" : "",clusters2*fs->cluster_size);
-           else printf("  Truncating second to %lu bytes.\n",clusters2*
-                 fs->cluster_size);
-           if (do_trunc != 2 &&
-               (do_trunc == 1 ||
-                (interactive && get_key("12","?") == '1'))) {
-               prev = 0;
-               clusters = 0;
-               for (this = FSTART(owner,fs); this > 0 && this != -1; this =
-                 next_cluster(fs,this)) {
-                   if (this == curr) {
-                       if (prev) set_fat(fs,prev,-1);
-                       else MODIFY_START(owner,0,fs);
-                       MODIFY(owner,size,CT_LE_L(clusters*fs->cluster_size));
-                       if (restart) return 1;
-                       while (this > 0 && this != -1) {
-                           set_owner(fs,this,NULL);
-                           this = next_cluster(fs,this);
-                       }
-                       break;
-                   }
-                   clusters++;
-                   prev = this;
-               }
-               if (this != curr)
-                   die("Internal error: didn't find cluster %d in chain"
-                     " starting at %d",curr,FSTART(owner,fs));
-           }
-           else {
-               if (prev) set_fat(fs,prev,-1);
-               else MODIFY_START(file,0,fs);
-               break;
-           }
-       }
-       set_owner(fs,curr,file);
-       clusters++;
-       prev = curr;
-    }
-    if (!(file->dir_ent.attr & ATTR_DIR) && CF_LE_L(file->dir_ent.size) >
-      clusters*fs->cluster_size) {
-       printf("%s\n  File size is %u bytes, cluster chain length is %lu bytes."
-         "\n  Truncating file to %lu bytes.\n",path_name(file),CF_LE_L(file->
-         dir_ent.size),clusters*fs->cluster_size,clusters*fs->cluster_size);
-       MODIFY(file,size,CT_LE_L(clusters*fs->cluster_size));
-    }
-    return 0;
-}
-
-
-static int check_files(DOS_FS *fs,DOS_FILE *start)
-{
-    while (start) {
-       if (check_file(fs,start)) return 1;
-       start = start->next;
-    }
-    return 0;
-}
-
-
-static int check_dir(DOS_FS *fs,DOS_FILE **root,int dots)
-{
-    DOS_FILE *parent,**walk,**scan;
-    int dot,dotdot,skip,redo;
-    int good,bad;
-
-    if (!*root) return 0;
-    parent = (*root)->parent;
-    good = bad = 0;
-    for (walk = root; *walk; walk = &(*walk)->next)
-       if (bad_name((*walk)->dir_ent.name)) bad++;
-       else good++;
-    if (*root && parent && good+bad > 4 && bad > good/2) {
-       printf("%s\n  Has a large number of bad entries. (%d/%d)\n",
-         path_name(parent),bad,good+bad);
-       if (!dots) printf( "  Not dropping root directory.\n" );
-       else if (!interactive) printf("  Not dropping it in auto-mode.\n");
-       else if (get_key("yn","Drop directory ? (y/n)") == 'y') {
-           truncate_file(fs,parent,0);
-           MODIFY(parent,name[0],DELETED_FLAG);
-           /* buglet: deleted directory stays in the list. */
-           return 1;
-       }
-    }
-    dot = dotdot = redo = 0;
-    walk = root;
-    while (*walk) {
-       if (!strncmp((*walk)->dir_ent.name,MSDOS_DOT,MSDOS_NAME) ||
-         !strncmp((*walk)->dir_ent.name,MSDOS_DOTDOT,MSDOS_NAME)) {
-           if (handle_dot(fs,*walk,dots)) {
-               *walk = (*walk)->next;
-               continue;
-           }
-           if (!strncmp((*walk)->dir_ent.name,MSDOS_DOT,MSDOS_NAME)) dot++;
-           else dotdot++;
-       }
-       if (!((*walk)->dir_ent.attr & ATTR_VOLUME) &&
-           bad_name((*walk)->dir_ent.name)) {
-           printf("%s\n  Bad file name.\n",path_name(*walk));
-           if (interactive)
-               printf("1) Drop file\n2) Rename file\n3) Auto-rename\n"
-                 "4) Keep it\n");
-           else printf("  Auto-renaming it.\n");
-           switch (interactive ? get_key("1234","?") : '3') {
-               case '1':
-                   drop_file(fs,*walk);
-                   walk = &(*walk)->next;
-                   continue;
-               case '2':
-                   rename_file(*walk);
-                   redo = 1;
-                   break;
-               case '3':
-                   auto_rename(*walk);
-                   printf("  Renamed to %s\n",file_name((*walk)->dir_ent.
-                     name));
-                   break;
-               case '4':
-                   break;
-           }
-       }
-       /* don't check for duplicates of the volume label */
-       if (!((*walk)->dir_ent.attr & ATTR_VOLUME)) {
-           scan = &(*walk)->next;
-           skip = 0;
-           while (*scan && !skip) {
-               if (!((*scan)->dir_ent.attr & ATTR_VOLUME) &&
-                   !strncmp((*walk)->dir_ent.name,(*scan)->dir_ent.name,MSDOS_NAME)) {
-                   printf("%s\n  Duplicate directory entry.\n  First  %s\n",
-                          path_name(*walk),file_stat(*walk));
-                   printf("  Second %s\n",file_stat(*scan));
-                   if (interactive)
-                       printf("1) Drop first\n2) Drop second\n3) Rename first\n"
-                              "4) Rename second\n5) Auto-rename first\n"
-                              "6) Auto-rename second\n");
-                   else printf("  Auto-renaming second.\n");
-                   switch (interactive ? get_key("123456","?") : '6') {
-                     case '1':
-                       drop_file(fs,*walk);
-                       *walk = (*walk)->next;
-                       skip = 1;
-                       break;
-                     case '2':
-                       drop_file(fs,*scan);
-                       *scan = (*scan)->next;
-                       continue;
-                     case '3':
-                       rename_file(*walk);
-                       printf("  Renamed to %s\n",path_name(*walk));
-                       redo = 1;
-                       break;
-                     case '4':
-                       rename_file(*scan);
-                       printf("  Renamed to %s\n",path_name(*walk));
-                       redo = 1;
-                       break;
-                     case '5':
-                       auto_rename(*walk);
-                       printf("  Renamed to %s\n",file_name((*walk)->dir_ent.
-                         name));
-                       break;
-                     case '6':
-                       auto_rename(*scan);
-                       printf("  Renamed to %s\n",file_name((*scan)->dir_ent.
-                         name));
-                       break;
-                   }
-               }
-               scan = &(*scan)->next;
-           }
-           if (skip) continue;
-       }
-       if (!redo) walk = &(*walk)->next;
-       else {
-           walk = root;
-           dot = dotdot = redo = 0;
-       }
-    }
-    if (dots && !dot)
-       printf("%s\n  \".\" is missing. Can't fix this yet.\n",
-         path_name(parent));
-    if (dots && !dotdot)
-       printf("%s\n  \"..\" is missing. Can't fix this yet.\n",
-         path_name(parent));
-    return 0;
-}
-
-
-static void test_file(DOS_FS *fs,DOS_FILE *file,int read_test)
-{
-    DOS_FILE *owner;
-    unsigned long walk,prev,clusters,next_clu;
-
-    prev = clusters = 0;
-    for (walk = FSTART(file,fs); walk > 0 && walk < fs->clusters+2;
-      walk = next_clu) {
-       next_clu = next_cluster(fs,walk);
-       if ((owner = get_owner(fs,walk))) {
-           if (owner == file) {
-               printf("%s\n  Circular cluster chain. Truncating to %lu "
-                 "cluster%s.\n",path_name(file),clusters,clusters == 1 ? "" :
-                 "s");
-               if (prev) set_fat(fs,prev,-1);
-               else if (!file->offset)
-                   die( "Bad FAT32 root directory! (bad start cluster)\n" );
-               else MODIFY_START(file,0,fs);
-           }
-           break;
-       }
-       if (bad_cluster(fs,walk)) break;
-       if (read_test) {
-           if (fs_test(cluster_start(fs,walk),fs->cluster_size)) {
-               prev = walk;
-               clusters++;
-           }
-           else {
-               printf("%s\n  Cluster %lu (%lu) is unreadable. Skipping it.\n",
-                 path_name(file),clusters,walk);
-               if (prev) set_fat(fs,prev,next_cluster(fs,walk));
-               else MODIFY_START(file,next_cluster(fs,walk),fs);
-               set_fat(fs,walk,-2);
-           }
-       }
-       set_owner(fs,walk,file);
-    }
-    for (walk = FSTART(file,fs); walk > 0 && walk < fs->clusters+2;
-      walk = next_cluster(fs,walk))
-       if (bad_cluster(fs,walk)) break;
-       else if (get_owner(fs,walk) == file) set_owner(fs,walk,NULL);
-           else break;
-}
-
-
-static void undelete(DOS_FS *fs,DOS_FILE *file)
-{
-    unsigned long clusters,left,prev,walk;
-
-    clusters = left = (CF_LE_L(file->dir_ent.size)+fs->cluster_size-1)/
-      fs->cluster_size;
-    prev = 0;
-    for (walk = FSTART(file,fs); left && walk >= 2 && walk <
-       fs->clusters+2 && !fs->fat[walk].value; walk++) {
-       left--;
-       if (prev) set_fat(fs,prev,walk);
-       prev = walk;
-    }
-    if (prev) set_fat(fs,prev,-1);
-    else MODIFY_START(file,0,fs);
-    if (left)
-       printf("Warning: Did only undelete %lu of %lu cluster%s.\n",clusters-left,
-         clusters,clusters == 1 ? "" : "s");
-   
-}
-
-
-static void new_dir( void )
-{
-    lfn_reset();
-}
-
-
-static void add_file(DOS_FS *fs,DOS_FILE ***chain,DOS_FILE *parent,
-                                        loff_t offset,FDSC **cp)
-{
-    DOS_FILE *new;
-    DIR_ENT de;
-    FD_TYPE type;
+    static char path[MAX_PATH*2];\r
+\r
+    if (!file) *path = 0;\r
+    else {\r
+       if (strlen(path_name(file->parent)) > MAX_PATH)\r
+           die("Path name too long.");\r
+       if (strcmp(path,"/") != 0) strcat(path,"/");\r
+       strcpy(strrchr(path,0),file->lfn?file->lfn:file_name(file->dir_ent.name));\r
+    }\r
+    return path;\r
+}\r
+\r
+\r
+static int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 };\r
+                 /* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */\r
+\r
+\r
+/* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */\r
+\r
+time_t date_dos2unix(unsigned short time,unsigned short date)\r
+{\r
+    int month,year;\r
+    time_t secs;\r
+\r
+    month = ((date >> 5) & 15)-1;\r
+    year = date >> 9;\r
+    secs = (time & 31)*2+60*((time >> 5) & 63)+(time >> 11)*3600+86400*\r
+      ((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 &&\r
+      month < 2 ? 1 : 0)+3653);\r
+                       /* days since 1.1.70 plus 80's leap day */\r
+    return secs;\r
+}\r
+\r
+\r
+static char *file_stat(DOS_FILE *file)\r
+{\r
+    static char temp[100];\r
+    struct tm *tm;\r
+    char tmp[100];\r
+    time_t date;\r
+\r
+    date = date_dos2unix(CF_LE_W(file->dir_ent.time),CF_LE_W(file->\r
+      dir_ent.date));\r
+    tm = localtime(&date);\r
+    strftime(tmp,99,"%H:%M:%S %b %d %Y",tm);\r
+    sprintf(temp,"  Size %u bytes, date %s",CF_LE_L(file->dir_ent.size),tmp);\r
+    return temp;\r
+}\r
+\r
+\r
+static int bad_name(unsigned char *name)\r
+{\r
+    int i, spc, suspicious = 0;\r
+    char *bad_chars = atari_format ? "*?\\/:" : "*?<>|\"\\/:";\r
+\r
+    /* Do not complain about (and auto-correct) the extended attribute files\r
+     * of OS/2. */\r
+    if (strncmp(name,"EA DATA  SF",11) == 0 ||\r
+        strncmp(name,"WP ROOT  SF",11) == 0) return 0;\r
+    \r
+    for (i = 0; i < 8; i++) {\r
+       if (name[i] < ' ' || name[i] == 0x7f) return 1;\r
+       if (name[i] > 0x7f) ++suspicious;\r
+       if (strchr(bad_chars,name[i])) return 1;\r
+    }\r
+\r
+    for (i = 8; i < 11; i++) {\r
+       if (name[i] < ' ' || name[i] == 0x7f) return 1;\r
+       if (name[i] > 0x7f) ++suspicious;\r
+       if (strchr(bad_chars,name[i])) return 1;\r
+    }\r
+\r
+    spc = 0;\r
+    for (i = 0; i < 8; i++) {\r
+       if (name[i] == ' ')\r
+           spc = 1;\r
+       else if (spc)\r
+           /* non-space after a space not allowed, space terminates the name\r
+            * part */\r
+           return 1;\r
+    }\r
+\r
+    spc = 0;\r
+    for (i = 8; i < 11; i++) {\r
+       if (name[i] == ' ')\r
+           spc = 1;\r
+       else if (spc)\r
+           /* non-space after a space not allowed, space terminates the name\r
+            * part */\r
+           return 1;\r
+    }\r
+\r
+    /* Under GEMDOS, chars >= 128 are never allowed. */\r
+    if (atari_format && suspicious)\r
+       return 1;\r
+    \r
+    /* Only complain about too much suspicious chars in interactive mode,\r
+     * never correct them automatically. The chars are all basically ok, so we\r
+     * shouldn't auto-correct such names. */\r
+    if (interactive && suspicious > 6)\r
+       return 1;\r
+    return 0;\r
+}\r
+\r
+\r
+static void drop_file(DOS_FS *fs,DOS_FILE *file)\r
+{\r
+    unsigned long cluster;\r
+\r
+    MODIFY(file,name[0],DELETED_FLAG);\r
+    for (cluster = FSTART(file,fs); cluster > 0 && cluster <\r
+      fs->clusters+2; cluster = next_cluster(fs,cluster))\r
+       set_owner(fs,cluster,NULL);\r
+    --n_files;\r
+}\r
+\r
+\r
+static void truncate_file(DOS_FS *fs,DOS_FILE *file,unsigned long clusters)\r
+{\r
+    int deleting;\r
+    unsigned long walk,next,prev;\r
+    \r
+    walk = FSTART(file,fs);\r
+    prev = 0;\r
+    if ((deleting = !clusters)) MODIFY_START(file,0,fs);\r
+    while (walk > 0 && walk != -1) {\r
+       next = next_cluster(fs,walk);\r
+       if (deleting) set_fat(fs,walk,0);\r
+       else if ((deleting = !--clusters)) set_fat(fs,walk,-1);\r
+       prev = walk;\r
+       walk = next;\r
+    }\r
+}\r
+\r
+\r
+static void auto_rename(DOS_FILE *file)\r
+{\r
+    DOS_FILE *first,*walk;\r
+    int number;\r
+\r
+    if (!file->offset) return; /* cannot rename FAT32 root dir */\r
+    first = file->parent ? file->parent->first : root;\r
+    number = 0;\r
+    while (1) {\r
+       sprintf(file->dir_ent.name,"FSCK%04d",number);\r
+       strncpy(file->dir_ent.ext,"REN",3);\r
+       for (walk = first; walk; walk = walk->next)\r
+           if (walk != file && !strncmp(walk->dir_ent.name,file->dir_ent.\r
+             name,MSDOS_NAME)) break;\r
+       if (!walk) {\r
+           fs_write(file->offset,MSDOS_NAME,file->dir_ent.name);\r
+           return;\r
+       }\r
+       number++;\r
+    }\r
+    die("Can't generate a unique name.");\r
+}\r
+\r
+\r
+static void rename_file(DOS_FILE *file)\r
+{\r
+    unsigned char name[46];\r
+    unsigned char *walk,*here;\r
+\r
+    if (!file->offset) {\r
+       printf( "Cannot rename FAT32 root dir\n" );\r
+       return; /* cannot rename FAT32 root dir */\r
+    }\r
+    while (1) {\r
+       printf("New name: ");\r
+       fflush(stdout);\r
+       if (fgets(name,45,stdin)) {\r
+           if ((here = strchr(name,'\n'))) *here = 0;\r
+           for (walk = strrchr(name,0); walk >= name && (*walk == ' ' ||\r
+             *walk == '\t'); walk--);\r
+           walk[1] = 0;\r
+           for (walk = name; *walk == ' ' || *walk == '\t'; walk++);\r
+           if (file_cvt(walk,file->dir_ent.name)) {\r
+               fs_write(file->offset,MSDOS_NAME,file->dir_ent.name);\r
+               return;\r
+           }\r
+       }\r
+    }\r
+}\r
+\r
+\r
+static int handle_dot(DOS_FS *fs,DOS_FILE *file,int dots)\r
+{\r
+    char *name;\r
+\r
+    name = strncmp(file->dir_ent.name,MSDOS_DOT,MSDOS_NAME) ? ".." : ".";\r
+    if (!(file->dir_ent.attr & ATTR_DIR)) {\r
+       printf("%s\n  Is a non-directory.\n",path_name(file));\r
+       if (interactive)\r
+           printf("1) Drop it\n2) Auto-rename\n3) Rename\n"\r
+             "4) Convert to directory\n");\r
+       else printf("  Auto-renaming it.\n");\r
+       switch (interactive ? get_key("1234","?") : '2') {\r
+           case '1':\r
+               drop_file(fs,file);\r
+               return 1;\r
+           case '2':\r
+               auto_rename(file);\r
+               printf("  Renamed to %s\n",file_name(file->dir_ent.name));\r
+               return 0;\r
+           case '3':\r
+               rename_file(file);\r
+               return 0;\r
+           case '4':\r
+               MODIFY(file,size,CT_LE_L(0));\r
+               MODIFY(file,attr,file->dir_ent.attr | ATTR_DIR);\r
+               break;\r
+       }\r
+    }\r
+    if (!dots) {\r
+       printf("Root contains directory \"%s\". Dropping it.\n",name);\r
+       drop_file(fs,file);\r
+       return 1;\r
+    }\r
+    return 0;\r
+}\r
+\r
+\r
+static int check_file(DOS_FS *fs,DOS_FILE *file)\r
+{\r
+    DOS_FILE *owner;\r
+    int restart;\r
+    unsigned long expect,curr,this,clusters,prev,walk,clusters2;\r
+\r
+    if (file->dir_ent.attr & ATTR_DIR) {\r
+       if (CF_LE_L(file->dir_ent.size)) {\r
+           printf("%s\n  Directory has non-zero size. Fixing it.\n",\r
+             path_name(file));\r
+           MODIFY(file,size,CT_LE_L(0));\r
+       }\r
+       if (file->parent && !strncmp(file->dir_ent.name,MSDOS_DOT,MSDOS_NAME)) {\r
+           expect = FSTART(file->parent,fs);\r
+           if (FSTART(file,fs) != expect) {\r
+               printf("%s\n  Start (%ld) does not point to parent (%ld)\n",\r
+                 path_name(file),FSTART(file,fs),expect);\r
+               MODIFY_START(file,expect,fs);\r
+           }\r
+           return 0;\r
+       }\r
+       if (file->parent && !strncmp(file->dir_ent.name,MSDOS_DOTDOT,\r
+         MSDOS_NAME)) {\r
+           expect = file->parent->parent ? FSTART(file->parent->parent,fs):0;\r
+           if (fs->root_cluster && expect == fs->root_cluster)\r
+               expect = 0;\r
+           if (FSTART(file,fs) != expect) {\r
+               printf("%s\n  Start (%lu) does not point to .. (%lu)\n",\r
+                 path_name(file),FSTART(file,fs),expect);\r
+               MODIFY_START(file,expect,fs);\r
+           }\r
+           return 0;\r
+       }\r
+       if (FSTART(file,fs)==0){\r
+               printf ("%s\n Start does point to root directory. Deleting dir. \n",\r
+                               path_name(file));\r
+               MODIFY(file,name[0],DELETED_FLAG);\r
+               return 0;\r
+       }\r
+    }\r
+    if (FSTART(file,fs) >= fs->clusters+2) {\r
+       printf("%s\n  Start cluster beyond limit (%lu > %lu). Truncating file.\n",\r
+         path_name(file),FSTART(file,fs),fs->clusters+1);\r
+       if (!file->offset)\r
+           die( "Bad FAT32 root directory! (bad start cluster)\n" );\r
+       MODIFY_START(file,0,fs);\r
+    }\r
+    clusters = prev = 0;\r
+    for (curr = FSTART(file,fs) ? FSTART(file,fs) :\r
+      -1; curr != -1; curr = next_cluster(fs,curr)) {\r
+       if (!fs->fat[curr].value || bad_cluster(fs,curr)) {\r
+           printf("%s\n  Contains a %s cluster (%lu). Assuming EOF.\n",\r
+             path_name(file),fs->fat[curr].value ? "bad" : "free",curr);\r
+           if (prev) set_fat(fs,prev,-1);\r
+           else if (!file->offset)\r
+               die( "FAT32 root dir starts with a bad cluster!" );\r
+           else MODIFY_START(file,0,fs);\r
+           break;\r
+       }\r
+       if (!(file->dir_ent.attr & ATTR_DIR) && CF_LE_L(file->dir_ent.size) <=\r
+         clusters*fs->cluster_size) {\r
+           printf("%s\n  File size is %u bytes, cluster chain length is > %lu "\r
+             "bytes.\n  Truncating file to %u bytes.\n",path_name(file),\r
+             CF_LE_L(file->dir_ent.size),clusters*fs->cluster_size,\r
+             CF_LE_L(file->dir_ent.size));\r
+           truncate_file(fs,file,clusters);\r
+           break;\r
+       }\r
+       if ((owner = get_owner(fs,curr))) {\r
+           int do_trunc = 0;\r
+           printf("%s  and\n",path_name(owner));\r
+           printf("%s\n  share clusters.\n",path_name(file));\r
+           clusters2 = 0;\r
+           for (walk = FSTART(owner,fs); walk > 0 && walk != -1; walk =\r
+             next_cluster(fs,walk))\r
+               if (walk == curr) break;\r
+               else clusters2++;\r
+           restart = file->dir_ent.attr & ATTR_DIR;\r
+           if (!owner->offset) {\r
+               printf( "  Truncating second to %lu bytes because first "\r
+                       "is FAT32 root dir.\n", clusters2*fs->cluster_size );\r
+               do_trunc = 2;\r
+           }\r
+           else if (!file->offset) {\r
+               printf( "  Truncating first to %lu bytes because second "\r
+                       "is FAT32 root dir.\n", clusters*fs->cluster_size );\r
+               do_trunc = 1;\r
+           }\r
+           else if (interactive)\r
+               printf("1) Truncate first to %lu bytes%s\n"\r
+                 "2) Truncate second to %lu bytes\n",clusters*fs->cluster_size,\r
+                 restart ? " and restart" : "",clusters2*fs->cluster_size);\r
+           else printf("  Truncating second to %lu bytes.\n",clusters2*\r
+                 fs->cluster_size);\r
+           if (do_trunc != 2 &&\r
+               (do_trunc == 1 ||\r
+                (interactive && get_key("12","?") == '1'))) {\r
+               prev = 0;\r
+               clusters = 0;\r
+               for (this = FSTART(owner,fs); this > 0 && this != -1; this =\r
+                 next_cluster(fs,this)) {\r
+                   if (this == curr) {\r
+                       if (prev) set_fat(fs,prev,-1);\r
+                       else MODIFY_START(owner,0,fs);\r
+                       MODIFY(owner,size,CT_LE_L(clusters*fs->cluster_size));\r
+                       if (restart) return 1;\r
+                       while (this > 0 && this != -1) {\r
+                           set_owner(fs,this,NULL);\r
+                           this = next_cluster(fs,this);\r
+                       }\r
+                       break;\r
+                   }\r
+                   clusters++;\r
+                   prev = this;\r
+               }\r
+               if (this != curr)\r
+                   die("Internal error: didn't find cluster %d in chain"\r
+                     " starting at %d",curr,FSTART(owner,fs));\r
+           }\r
+           else {\r
+               if (prev) set_fat(fs,prev,-1);\r
+               else MODIFY_START(file,0,fs);\r
+               break;\r
+           }\r
+       }\r
+       set_owner(fs,curr,file);\r
+       clusters++;\r
+       prev = curr;\r
+    }\r
+    if (!(file->dir_ent.attr & ATTR_DIR) && CF_LE_L(file->dir_ent.size) >\r
+      clusters*fs->cluster_size) {\r
+       printf("%s\n  File size is %u bytes, cluster chain length is %lu bytes."\r
+         "\n  Truncating file to %lu bytes.\n",path_name(file),CF_LE_L(file->\r
+         dir_ent.size),clusters*fs->cluster_size,clusters*fs->cluster_size);\r
+       MODIFY(file,size,CT_LE_L(clusters*fs->cluster_size));\r
+    }\r
+    return 0;\r
+}\r
+\r
+\r
+static int check_files(DOS_FS *fs,DOS_FILE *start)\r
+{\r
+    while (start) {\r
+       if (check_file(fs,start)) return 1;\r
+       start = start->next;\r
+    }\r
+    return 0;\r
+}\r
+\r
+\r
+static int check_dir(DOS_FS *fs,DOS_FILE **root,int dots)\r
+{\r
+    DOS_FILE *parent,**walk,**scan;\r
+    int dot,dotdot,skip,redo;\r
+    int good,bad;\r
+\r
+    if (!*root) return 0;\r
+    parent = (*root)->parent;\r
+    good = bad = 0;\r
+    for (walk = root; *walk; walk = &(*walk)->next)\r
+       if (bad_name((*walk)->dir_ent.name)) bad++;\r
+       else good++;\r
+    if (*root && parent && good+bad > 4 && bad > good/2) {\r
+       printf("%s\n  Has a large number of bad entries. (%d/%d)\n",\r
+         path_name(parent),bad,good+bad);\r
+       if (!dots) printf( "  Not dropping root directory.\n" );\r
+       else if (!interactive) printf("  Not dropping it in auto-mode.\n");\r
+       else if (get_key("yn","Drop directory ? (y/n)") == 'y') {\r
+           truncate_file(fs,parent,0);\r
+           MODIFY(parent,name[0],DELETED_FLAG);\r
+           /* buglet: deleted directory stays in the list. */\r
+           return 1;\r
+       }\r
+    }\r
+    dot = dotdot = redo = 0;\r
+    walk = root;\r
+    while (*walk) {\r
+       if (!strncmp((*walk)->dir_ent.name,MSDOS_DOT,MSDOS_NAME) ||\r
+         !strncmp((*walk)->dir_ent.name,MSDOS_DOTDOT,MSDOS_NAME)) {\r
+           if (handle_dot(fs,*walk,dots)) {\r
+               *walk = (*walk)->next;\r
+               continue;\r
+           }\r
+           if (!strncmp((*walk)->dir_ent.name,MSDOS_DOT,MSDOS_NAME)) dot++;\r
+           else dotdot++;\r
+       }\r
+       if (!((*walk)->dir_ent.attr & ATTR_VOLUME) &&\r
+           bad_name((*walk)->dir_ent.name)) {\r
+           printf("%s\n  Bad file name.\n",path_name(*walk));\r
+           if (interactive)\r
+               printf("1) Drop file\n2) Rename file\n3) Auto-rename\n"\r
+                 "4) Keep it\n");\r
+           else printf("  Auto-renaming it.\n");\r
+           switch (interactive ? get_key("1234","?") : '3') {\r
+               case '1':\r
+                   drop_file(fs,*walk);\r
+                   walk = &(*walk)->next;\r
+                   continue;\r
+               case '2':\r
+                   rename_file(*walk);\r
+                   redo = 1;\r
+                   break;\r
+               case '3':\r
+                   auto_rename(*walk);\r
+                   printf("  Renamed to %s\n",file_name((*walk)->dir_ent.\r
+                     name));\r
+                   break;\r
+               case '4':\r
+                   break;\r
+           }\r
+       }\r
+       /* don't check for duplicates of the volume label */\r
+       if (!((*walk)->dir_ent.attr & ATTR_VOLUME)) {\r
+           scan = &(*walk)->next;\r
+           skip = 0;\r
+           while (*scan && !skip) {\r
+               if (!((*scan)->dir_ent.attr & ATTR_VOLUME) &&\r
+                   !strncmp((*walk)->dir_ent.name,(*scan)->dir_ent.name,MSDOS_NAME)) {\r
+                   printf("%s\n  Duplicate directory entry.\n  First  %s\n",\r
+                          path_name(*walk),file_stat(*walk));\r
+                   printf("  Second %s\n",file_stat(*scan));\r
+                   if (interactive)\r
+                       printf("1) Drop first\n2) Drop second\n3) Rename first\n"\r
+                              "4) Rename second\n5) Auto-rename first\n"\r
+                              "6) Auto-rename second\n");\r
+                   else printf("  Auto-renaming second.\n");\r
+                   switch (interactive ? get_key("123456","?") : '6') {\r
+                     case '1':\r
+                       drop_file(fs,*walk);\r
+                       *walk = (*walk)->next;\r
+                       skip = 1;\r
+                       break;\r
+                     case '2':\r
+                       drop_file(fs,*scan);\r
+                       *scan = (*scan)->next;\r
+                       continue;\r
+                     case '3':\r
+                       rename_file(*walk);\r
+                       printf("  Renamed to %s\n",path_name(*walk));\r
+                       redo = 1;\r
+                       break;\r
+                     case '4':\r
+                       rename_file(*scan);\r
+                       printf("  Renamed to %s\n",path_name(*walk));\r
+                       redo = 1;\r
+                       break;\r
+                     case '5':\r
+                       auto_rename(*walk);\r
+                       printf("  Renamed to %s\n",file_name((*walk)->dir_ent.\r
+                         name));\r
+                       break;\r
+                     case '6':\r
+                       auto_rename(*scan);\r
+                       printf("  Renamed to %s\n",file_name((*scan)->dir_ent.\r
+                         name));\r
+                       break;\r
+                   }\r
+               }\r
+               scan = &(*scan)->next;\r
+           }\r
+           if (skip) continue;\r
+       }\r
+       if (!redo) walk = &(*walk)->next;\r
+       else {\r
+           walk = root;\r
+           dot = dotdot = redo = 0;\r
+       }\r
+    }\r
+    if (dots && !dot)\r
+       printf("%s\n  \".\" is missing. Can't fix this yet.\n",\r
+         path_name(parent));\r
+    if (dots && !dotdot)\r
+       printf("%s\n  \"..\" is missing. Can't fix this yet.\n",\r
+         path_name(parent));\r
+    return 0;\r
+}\r
+\r
+\r
+static void test_file(DOS_FS *fs,DOS_FILE *file,int read_test)\r
+{\r
+    DOS_FILE *owner;\r
+    unsigned long walk,prev,clusters,next_clu;\r
+\r
+    prev = clusters = 0;\r
+    for (walk = FSTART(file,fs); walk > 0 && walk < fs->clusters+2;\r
+      walk = next_clu) {\r
+       next_clu = next_cluster(fs,walk);\r
+       if ((owner = get_owner(fs,walk))) {\r
+           if (owner == file) {\r
+               printf("%s\n  Circular cluster chain. Truncating to %lu "\r
+                 "cluster%s.\n",path_name(file),clusters,clusters == 1 ? "" :\r
+                 "s");\r
+               if (prev) set_fat(fs,prev,-1);\r
+               else if (!file->offset)\r
+                   die( "Bad FAT32 root directory! (bad start cluster)\n" );\r
+               else MODIFY_START(file,0,fs);\r
+           }\r
+           break;\r
+       }\r
+       if (bad_cluster(fs,walk)) break;\r
+       if (read_test) {\r
+           if (fs_test(cluster_start(fs,walk),fs->cluster_size)) {\r
+               prev = walk;\r
+               clusters++;\r
+           }\r
+           else {\r
+               printf("%s\n  Cluster %lu (%lu) is unreadable. Skipping it.\n",\r
+                 path_name(file),clusters,walk);\r
+               if (prev) set_fat(fs,prev,next_cluster(fs,walk));\r
+               else MODIFY_START(file,next_cluster(fs,walk),fs);\r
+               set_fat(fs,walk,-2);\r
+           }\r
+       }\r
+       set_owner(fs,walk,file);\r
+    }\r
+    for (walk = FSTART(file,fs); walk > 0 && walk < fs->clusters+2;\r
+      walk = next_cluster(fs,walk))\r
+       if (bad_cluster(fs,walk)) break;\r
+       else if (get_owner(fs,walk) == file) set_owner(fs,walk,NULL);\r
+           else break;\r
+}\r
+\r
+\r
+static void undelete(DOS_FS *fs,DOS_FILE *file)\r
+{\r
+    unsigned long clusters,left,prev,walk;\r
+\r
+    clusters = left = (CF_LE_L(file->dir_ent.size)+fs->cluster_size-1)/\r
+      fs->cluster_size;\r
+    prev = 0;\r
+    for (walk = FSTART(file,fs); left && walk >= 2 && walk <\r
+       fs->clusters+2 && !fs->fat[walk].value; walk++) {\r
+       left--;\r
+       if (prev) set_fat(fs,prev,walk);\r
+       prev = walk;\r
+    }\r
+    if (prev) set_fat(fs,prev,-1);\r
+    else MODIFY_START(file,0,fs);\r
+    if (left)\r
+       printf("Warning: Did only undelete %lu of %lu cluster%s.\n",clusters-left,\r
+         clusters,clusters == 1 ? "" : "s");\r
+   \r
+}\r
+\r
+\r
+static void new_dir( void )\r
+{\r
+    lfn_reset();\r
+}\r
+\r
+\r
+static void add_file(DOS_FS *fs,DOS_FILE ***chain,DOS_FILE *parent,\r
+                                        loff_t offset,FDSC **cp)\r
+{\r
+    DOS_FILE *new;\r
+    DIR_ENT de;\r
+    FD_TYPE type;\r
 \r
        char tmpBuffer[512]; // TMN:\r
-
-    if (offset) {
+\r
+    if (offset) {\r
 //     fs_read(offset,sizeof(DIR_ENT),&de);\r
        fs_read(offset,sizeof(tmpBuffer),&tmpBuffer); // TMN:\r
-       memcpy(&de, tmpBuffer, sizeof(DIR_ENT));      // TMN:
-    } else {
-       memcpy(de.name,"           ",MSDOS_NAME);
-       de.attr = ATTR_DIR;
-       de.size = de.time = de.date = 0;
-       de.start = CT_LE_W(fs->root_cluster & 0xffff);
-       de.starthi = CT_LE_W((fs->root_cluster >> 16) & 0xffff);
-    }
-    if ((type = file_type(cp,de.name)) != fdt_none) {
-       if (type == fdt_undelete && (de.attr & ATTR_DIR))
-           die("Can't undelete directories.");
-       file_modify(cp,de.name);
-       fs_write(offset,1,&de);
-    }
-    if (IS_FREE(de.name)) {
-       lfn_check_orphaned();
-       return;
-    }
-    if (de.attr == VFAT_LN_ATTR) {
-       lfn_add_slot(&de,offset);
-       return;
-    }
-    new = qalloc(&mem_queue,sizeof(DOS_FILE));
-    new->lfn = lfn_get(&de);
-    new->offset = offset;
-    memcpy(&new->dir_ent,&de,sizeof(de));
-    new->next = new->first = NULL;
-    new->parent = parent;
-    if (type == fdt_undelete) undelete(fs,new);
-    **chain = new;
-    *chain = &new->next;
-    if (list) {
-       printf("Checking file %s",path_name(new));
-       if (new->lfn)
-           printf(" (%s)", file_name(new->dir_ent.name) );
-       printf("\n");
-    }
-    if (offset &&
-       strncmp(de.name,MSDOS_DOT,MSDOS_NAME) != 0 &&
-       strncmp(de.name,MSDOS_DOTDOT,MSDOS_NAME) != 0)
-       ++n_files;
-    test_file(fs,new,test);
-}
-
-
-static int subdirs(DOS_FS *fs,DOS_FILE *parent,FDSC **cp);
-
-
-static int scan_dir(DOS_FS *fs,DOS_FILE *this,FDSC **cp)
-{
-    DOS_FILE **chain;
-    int i;
-    unsigned long clu_num;
-
-    chain = &this->first;
-    i = 0;
-    clu_num = FSTART(this,fs);
-    new_dir();
-    while (clu_num > 0 && clu_num != -1) {
-       add_file(fs,&chain,this,cluster_start(fs,clu_num)+(i % fs->
-         cluster_size),cp);
-       i += sizeof(DIR_ENT);
-       if (!(i % fs->cluster_size))
-           if ((clu_num = next_cluster(fs,clu_num)) == 0 || clu_num == -1)
-               break;
-    }
-    lfn_check_orphaned();
-    if (check_dir(fs,&this->first,this->offset)) return 0;
-    if (check_files(fs,this->first)) return 1;
-    return subdirs(fs,this,cp);
-}
-
-
-static int subdirs(DOS_FS *fs,DOS_FILE *parent,FDSC **cp)
-{
-    DOS_FILE *walk;
-
-    for (walk = parent ? parent->first : root; walk; walk = walk->next)
-       if (walk->dir_ent.attr & ATTR_DIR)
-           if (strncmp(walk->dir_ent.name,MSDOS_DOT,MSDOS_NAME) &&
-             strncmp(walk->dir_ent.name,MSDOS_DOTDOT,MSDOS_NAME))
-               if (scan_dir(fs,walk,file_cd(cp,walk->dir_ent.name))) return 1;
-    return 0;
-}
-
-
-int scan_root(DOS_FS *fs)
-{
-    DOS_FILE **chain;
-    int i;
-
-    root = NULL;
-    chain = &root;
-    new_dir();
-    if (fs->root_cluster) {
-       add_file(fs,&chain,NULL,0,&fp_root);
-    }
-    else {
-       for (i = 0; i < fs->root_entries; i++)
-           add_file(fs,&chain,NULL,fs->root_start+i*sizeof(DIR_ENT),&fp_root);
-    }
-    lfn_check_orphaned();
-    (void) check_dir(fs,&root,0);
-    if (check_files(fs,root)) return 1;
-    return subdirs(fs,NULL,&fp_root);
-}
-
-/* Local Variables: */
-/* tab-width: 8     */
-/* End:             */
+       memcpy(&de, tmpBuffer, sizeof(DIR_ENT));      // TMN:\r
+    } else {\r
+       memcpy(de.name,"           ",MSDOS_NAME);\r
+       de.attr = ATTR_DIR;\r
+       de.size = de.time = de.date = 0;\r
+       de.start = CT_LE_W(fs->root_cluster & 0xffff);\r
+       de.starthi = CT_LE_W((fs->root_cluster >> 16) & 0xffff);\r
+    }\r
+    if ((type = file_type(cp,de.name)) != fdt_none) {\r
+       if (type == fdt_undelete && (de.attr & ATTR_DIR))\r
+           die("Can't undelete directories.");\r
+       file_modify(cp,de.name);\r
+       fs_write(offset,1,&de);\r
+    }\r
+    if (IS_FREE(de.name)) {\r
+       lfn_check_orphaned();\r
+       return;\r
+    }\r
+    if (de.attr == VFAT_LN_ATTR) {\r
+       lfn_add_slot(&de,offset);\r
+       return;\r
+    }\r
+    new = qalloc(&mem_queue,sizeof(DOS_FILE));\r
+    new->lfn = lfn_get(&de);\r
+    new->offset = offset;\r
+    memcpy(&new->dir_ent,&de,sizeof(de));\r
+    new->next = new->first = NULL;\r
+    new->parent = parent;\r
+    if (type == fdt_undelete) undelete(fs,new);\r
+    **chain = new;\r
+    *chain = &new->next;\r
+    if (list) {\r
+       printf("Checking file %s",path_name(new));\r
+       if (new->lfn)\r
+           printf(" (%s)", file_name(new->dir_ent.name) );\r
+       printf("\n");\r
+    }\r
+    if (offset &&\r
+       strncmp(de.name,MSDOS_DOT,MSDOS_NAME) != 0 &&\r
+       strncmp(de.name,MSDOS_DOTDOT,MSDOS_NAME) != 0)\r
+       ++n_files;\r
+    test_file(fs,new,test);\r
+}\r
+\r
+\r
+static int subdirs(DOS_FS *fs,DOS_FILE *parent,FDSC **cp);\r
+\r
+\r
+static int scan_dir(DOS_FS *fs,DOS_FILE *this,FDSC **cp)\r
+{\r
+    DOS_FILE **chain;\r
+    int i;\r
+    unsigned long clu_num;\r
+\r
+    chain = &this->first;\r
+    i = 0;\r
+    clu_num = FSTART(this,fs);\r
+    new_dir();\r
+    while (clu_num > 0 && clu_num != -1) {\r
+       add_file(fs,&chain,this,cluster_start(fs,clu_num)+(i % fs->\r
+         cluster_size),cp);\r
+       i += sizeof(DIR_ENT);\r
+       if (!(i % fs->cluster_size))\r
+           if ((clu_num = next_cluster(fs,clu_num)) == 0 || clu_num == -1)\r
+               break;\r
+    }\r
+    lfn_check_orphaned();\r
+    if (check_dir(fs,&this->first,this->offset)) return 0;\r
+    if (check_files(fs,this->first)) return 1;\r
+    return subdirs(fs,this,cp);\r
+}\r
+\r
+\r
+static int subdirs(DOS_FS *fs,DOS_FILE *parent,FDSC **cp)\r
+{\r
+    DOS_FILE *walk;\r
+\r
+    for (walk = parent ? parent->first : root; walk; walk = walk->next)\r
+       if (walk->dir_ent.attr & ATTR_DIR)\r
+           if (strncmp(walk->dir_ent.name,MSDOS_DOT,MSDOS_NAME) &&\r
+             strncmp(walk->dir_ent.name,MSDOS_DOTDOT,MSDOS_NAME))\r
+               if (scan_dir(fs,walk,file_cd(cp,walk->dir_ent.name))) return 1;\r
+    return 0;\r
+}\r
+\r
+\r
+int scan_root(DOS_FS *fs)\r
+{\r
+    DOS_FILE **chain;\r
+    int i;\r
+\r
+    root = NULL;\r
+    chain = &root;\r
+    new_dir();\r
+    if (fs->root_cluster) {\r
+       add_file(fs,&chain,NULL,0,&fp_root);\r
+    }\r
+    else {\r
+       for (i = 0; i < fs->root_entries; i++)\r
+           add_file(fs,&chain,NULL,fs->root_start+i*sizeof(DIR_ENT),&fp_root);\r
+    }\r
+    lfn_check_orphaned();\r
+    (void) check_dir(fs,&root,0);\r
+    if (check_files(fs,root)) return 1;\r
+    return subdirs(fs,NULL,&fp_root);\r
+}\r
+\r
+/* Local Variables: */\r
+/* tab-width: 8     */\r
+/* End:             */\r
index 38f1c68..4498b7f 100644 (file)
@@ -1,23 +1,23 @@
-/* check.h  -  Check and repair a PC/MS-DOS file system */
-
-/* Written 1993 by Werner Almesberger */
-
-
-#ifndef _CHECK_H
-#define _CHECK_H
-
-loff_t alloc_rootdir_entry(DOS_FS *fs, DIR_ENT *de, const char *pattern);
-
-/* Allocate a free slot in the root directory for a new file. The file name is
-   constructed after 'pattern', which must include a %d type format for printf
-   and expand to exactly 11 characters. The name actually used is written into
-   the 'de' structure, the rest of *de is cleared. The offset returned is to
-   where in the filesystem the entry belongs. */
-
-int scan_root(DOS_FS *fs);
-
-/* Scans the root directory and recurses into all subdirectories. See check.c
-   for all the details. Returns a non-zero integer if the file system has to
-   be checked again. */
-
-#endif
+/* check.h  -  Check and repair a PC/MS-DOS file system */\r
+\r
+/* Written 1993 by Werner Almesberger */\r
+\r
+\r
+#ifndef _CHECK_H\r
+#define _CHECK_H\r
+\r
+loff_t alloc_rootdir_entry(DOS_FS *fs, DIR_ENT *de, const char *pattern);\r
+\r
+/* Allocate a free slot in the root directory for a new file. The file name is\r
+   constructed after 'pattern', which must include a %d type format for printf\r
+   and expand to exactly 11 characters. The name actually used is written into\r
+   the 'de' structure, the rest of *de is cleared. The offset returned is to\r
+   where in the filesystem the entry belongs. */\r
+\r
+int scan_root(DOS_FS *fs);\r
+\r
+/* Scans the root directory and recurses into all subdirectories. See check.c\r
+   for all the details. Returns a non-zero integer if the file system has to\r
+   be checked again. */\r
+\r
+#endif\r
index 48a5f33..cc002ea 100644 (file)
-/* common.c  -  Common functions */
-
-/* Written 1993 by Werner Almesberger */
-
-/* FAT32, VFAT, Atari format support, and various fixes additions May 1998
- * by Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> */
-
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdarg.h>
-#include <errno.h>
-
-#include "common.h"
-
-
-typedef struct _link {
-    void *data;
-    struct _link *next;
-} LINK;
-
-
-void die(char *msg,...)
-{
-    va_list args;
-
-    va_start(args,msg);
-    vfprintf(stderr,msg,args);
-    va_end(args);
-    fprintf(stderr,"\n");
-    exit(1);
-}
-
-
-void pdie(char *msg,...)
-{
-    va_list args;
-
-    va_start(args,msg);
-    vfprintf(stderr,msg,args);
-    va_end(args);
-    fprintf(stderr,":%s\n",strerror(errno));
-    exit(1);
-}
-
-
-void *alloc(int size)
-{
-    void *this;
-
-    if ((this = malloc(size))) return this;
-    pdie("malloc");
-    return NULL; /* for GCC */
-}
-
-
-void *qalloc(void **root,int size)
-{
-    LINK *link;
-
-    link = alloc(sizeof(LINK));
-    link->next = *root;
-    *root = link;
-    return link->data = alloc(size);
-}
-
-
-void qfree(void **root)
-{
-    LINK *this;
-
-    while (*root) {
-       this = (LINK *) *root;
-       *root = this->next;
-       free(this->data);
-       free(this);
-    }
-}
-
+/* common.c  -  Common functions */\r
+\r
+/* Written 1993 by Werner Almesberger */\r
+\r
+/* FAT32, VFAT, Atari format support, and various fixes additions May 1998\r
+ * by Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> */\r
+\r
+\r
+#include <stdlib.h>\r
+#include <stdio.h>\r
+#include <string.h>\r
+#include <stdarg.h>\r
+#include <errno.h>\r
+\r
+#include "common.h"\r
+\r
+\r
+typedef struct _link {\r
+    void *data;\r
+    struct _link *next;\r
+} LINK;\r
+\r
+\r
+void die(char *msg,...)\r
+{\r
+    va_list args;\r
+\r
+    va_start(args,msg);\r
+    vfprintf(stderr,msg,args);\r
+    va_end(args);\r
+    fprintf(stderr,"\n");\r
+    exit(1);\r
+}\r
+\r
+\r
+void pdie(char *msg,...)\r
+{\r
+    va_list args;\r
+\r
+    va_start(args,msg);\r
+    vfprintf(stderr,msg,args);\r
+    va_end(args);\r
+    fprintf(stderr,":%s\n",strerror(errno));\r
+    exit(1);\r
+}\r
+\r
+\r
+void *alloc(int size)\r
+{\r
+    void *this;\r
+\r
+    if ((this = malloc(size))) return this;\r
+    pdie("malloc");\r
+    return NULL; /* for GCC */\r
+}\r
+\r
+\r
+void *qalloc(void **root,int size)\r
+{\r
+    LINK *link;\r
+\r
+    link = alloc(sizeof(LINK));\r
+    link->next = *root;\r
+    *root = link;\r
+    return link->data = alloc(size);\r
+}\r
+\r
+\r
+void qfree(void **root)\r
+{\r
+    LINK *this;\r
+\r
+    while (*root) {\r
+       this = (LINK *) *root;\r
+       *root = this->next;\r
+       free(this->data);\r
+       free(this);\r
+    }\r
+}\r
+\r
 \r
 #ifdef min\r
 #undef min\r
-#endif
-int min(int a,int b)
-{
-    return a < b ? a : b;
-}
-
-
-char get_key(char *valid,char *prompt)
-{
-    int ch,okay;
-
-    while (1) {
-       if (prompt) printf("%s ",prompt);
-       fflush(stdout);
-       while (ch = getchar(), ch == ' ' || ch == '\t');
-       if (ch == EOF) exit(1);
-       if (!strchr(valid,okay = ch)) okay = 0;
-       while (ch = getchar(), ch != '\n' && ch != EOF);
-       if (ch == EOF) exit(1);
-       if (okay) return okay;
-       printf("Invalid input.\n");
-    }
-}
-
-/* Local Variables: */
-/* tab-width: 8     */
-/* End:             */
+#endif\r
+int min(int a,int b)\r
+{\r
+    return a < b ? a : b;\r
+}\r
+\r
+\r
+char get_key(char *valid,char *prompt)\r
+{\r
+    int ch,okay;\r
+\r
+    while (1) {\r
+       if (prompt) printf("%s ",prompt);\r
+       fflush(stdout);\r
+       while (ch = getchar(), ch == ' ' || ch == '\t');\r
+       if (ch == EOF) exit(1);\r
+       if (!strchr(valid,okay = ch)) okay = 0;\r
+       while (ch = getchar(), ch != '\n' && ch != EOF);\r
+       if (ch == EOF) exit(1);\r
+       if (okay) return okay;\r
+       printf("Invalid input.\n");\r
+    }\r
+}\r
+\r
+/* Local Variables: */\r
+/* tab-width: 8     */\r
+/* End:             */\r
index 98a4685..6e9bdce 100644 (file)
@@ -1,42 +1,42 @@
-/* common.h  -  Common functions */
-
-# define MSDOS_FAT12 4084 /* maximum number of clusters in a 12 bit FAT */
-
-#include "version.h"
-
-#ifndef _COMMON_H
-#define _COMMON_H
-\r
-//void die(char *msg,...) __attribute((noreturn));
+/* common.h  -  Common functions */\r
+\r
+# define MSDOS_FAT12 4084 /* maximum number of clusters in a 12 bit FAT */\r
+\r
+#include "version.h"\r
+\r
+#ifndef _COMMON_H\r
+#define _COMMON_H\r
+\r
+//void die(char *msg,...) __attribute((noreturn));\r
 __declspec(noreturn) void die(char *msg,...);\r
-
-/* Displays a prinf-style message and terminates the program. */
-
-//void pdie(char *msg,...) __attribute((noreturn));
+\r
+/* Displays a prinf-style message and terminates the program. */\r
+\r
+//void pdie(char *msg,...) __attribute((noreturn));\r
 __declspec(noreturn) void pdie(char *msg,...);\r
-
-/* Like die, but appends an error message according to the state of errno. */
-
-void *alloc(int size);
-
-/* mallocs SIZE bytes and returns a pointer to the data. Terminates the program
-   if malloc fails. */
-
-void *qalloc(void **root,int size);
-
-/* Like alloc, but registers the data area in a list described by ROOT. */
-
-void qfree(void **root);
-
-/* Deallocates all qalloc'ed data areas described by ROOT. */
-
-//int min(int a,int b);
-
-/* Returns the smaller integer value of a and b. */
-
-char get_key(char *valid,char *prompt);
-
-/* Displays PROMPT and waits for user input. Only characters in VALID are
-   accepted. Terminates the program on EOF. Returns the character. */
-
-#endif
+\r
+/* Like die, but appends an error message according to the state of errno. */\r
+\r
+void *alloc(int size);\r
+\r
+/* mallocs SIZE bytes and returns a pointer to the data. Terminates the program\r
+   if malloc fails. */\r
+\r
+void *qalloc(void **root,int size);\r
+\r
+/* Like alloc, but registers the data area in a list described by ROOT. */\r
+\r
+void qfree(void **root);\r
+\r
+/* Deallocates all qalloc'ed data areas described by ROOT. */\r
+\r
+//int min(int a,int b);\r
+\r
+/* Returns the smaller integer value of a and b. */\r
+\r
+char get_key(char *valid,char *prompt);\r
+\r
+/* Displays PROMPT and waits for user input. Only characters in VALID are\r
+   accepted. Terminates the program on EOF. Returns the character. */\r
+\r
+#endif\r
index 2d3edfe..f685e93 100644 (file)
-#ifndef __LINUX_COMPILER_H
-#define __LINUX_COMPILER_H
-
-#ifndef __ASSEMBLY__
-
-#ifdef __CHECKER__
-# define __user                __attribute__((noderef, address_space(1)))
-# define __kernel      /* default address space */
-# define __safe                __attribute__((safe))
-# define __force       __attribute__((force))
-# define __nocast      __attribute__((nocast))
-# define __iomem       __attribute__((noderef, address_space(2)))
-# define __acquires(x) __attribute__((context(0,1)))
-# define __releases(x) __attribute__((context(1,0)))
-# define __acquire(x)  __context__(1)
-# define __release(x)  __context__(-1)
-# define __cond_lock(x)        ((x) ? ({ __context__(1); 1; }) : 0)
-extern void __chk_user_ptr(void __user *);
-extern void __chk_io_ptr(void __iomem *);
-#else
-# define __user
-# define __kernel
-# define __safe
-# define __force
-# define __nocast
-# define __iomem
-# define __chk_user_ptr(x) (void)0
-# define __chk_io_ptr(x) (void)0
-//# define __builtin_warning(x, y...) (1)
-# define __acquires(x)
-# define __releases(x)
-# define __acquire(x) (void)0
-# define __release(x) (void)0
-# define __cond_lock(x) (x)
-#endif
-
-#ifdef __KERNEL__
-
-#if __GNUC__ > 4
-#error no compiler-gcc.h file for this gcc version
-#elif __GNUC__ == 4
-# include <linux/compiler-gcc4.h>
-#elif __GNUC__ == 3
-# include <linux/compiler-gcc3.h>
-#elif __GNUC__ == 2
-# include <linux/compiler-gcc2.h>
-#else
-# error Sorry, your compiler is too old/not recognized.
-#endif
-
-/* Intel compiler defines __GNUC__. So we will overwrite implementations
- * coming from above header files here
- */
-#ifdef __INTEL_COMPILER
-# include <linux/compiler-intel.h>
-#endif
-
-/*
- * Generic compiler-dependent macros required for kernel
- * build go below this comment. Actual compiler/compiler version
- * specific implementations come from the above header files
- */
-
-#define likely(x)      __builtin_expect(!!(x), 1)
-#define unlikely(x)    __builtin_expect(!!(x), 0)
-
-/* Optimization barrier */
-#ifndef barrier
-# define barrier() __memory_barrier()
-#endif
-
-#ifndef RELOC_HIDE
-# define RELOC_HIDE(ptr, off)                                  \
-  ({ unsigned long __ptr;                                      \
-     __ptr = (unsigned long) (ptr);                            \
-    (typeof(ptr)) (__ptr + (off)); })
-#endif
-
-#endif /* __KERNEL__ */
-
-#endif /* __ASSEMBLY__ */
-
-/*
- * Allow us to mark functions as 'deprecated' and have gcc emit a nice
- * warning for each use, in hopes of speeding the functions removal.
- * Usage is:
- *             int __deprecated foo(void)
- */
-#ifndef __deprecated
-# define __deprecated          /* unimplemented */
-#endif
-
-#ifdef MODULE
-#define __deprecated_for_modules __deprecated
-#else
-#define __deprecated_for_modules
-#endif
-
-#ifndef __must_check
-#define __must_check
-#endif
-
-/*
- * Allow us to avoid 'defined but not used' warnings on functions and data,
- * as well as force them to be emitted to the assembly file.
- *
- * As of gcc 3.3, static functions that are not marked with attribute((used))
- * may be elided from the assembly file.  As of gcc 3.3, static data not so
- * marked will not be elided, but this may change in a future gcc version.
- *
- * In prior versions of gcc, such functions and data would be emitted, but
- * would be warned about except with attribute((unused)).
- */
-#ifndef __attribute_used__
-# define __attribute_used__    /* unimplemented */
-#endif
-
-/*
- * From the GCC manual:
- *
- * Many functions have no effects except the return value and their
- * return value depends only on the parameters and/or global
- * variables.  Such a function can be subject to common subexpression
- * elimination and loop optimization just as an arithmetic operator
- * would be.
- * [...]
- */
-#ifndef __attribute_pure__
-# define __attribute_pure__    /* unimplemented */
-#endif
-
-/*
- * From the GCC manual:
- *
- * Many functions do not examine any values except their arguments,
- * and have no effects except the return value.  Basically this is
- * just slightly more strict class than the `pure' attribute above,
- * since function is not allowed to read global memory.
- *
- * Note that a function that has pointer arguments and examines the
- * data pointed to must _not_ be declared `const'.  Likewise, a
- * function that calls a non-`const' function usually must not be
- * `const'.  It does not make sense for a `const' function to return
- * `void'.
- */
-#ifndef __attribute_const__
-# define __attribute_const__   /* unimplemented */
-#endif
-
-#ifndef noinline
-#define noinline
-#endif
-
-#ifndef __always_inline
-#define __always_inline inline
-#endif
-
-#endif /* __LINUX_COMPILER_H */
+#ifndef __LINUX_COMPILER_H\r
+#define __LINUX_COMPILER_H\r
+\r
+#ifndef __ASSEMBLY__\r
+\r
+#ifdef __CHECKER__\r
+# define __user                __attribute__((noderef, address_space(1)))\r
+# define __kernel      /* default address space */\r
+# define __safe                __attribute__((safe))\r
+# define __force       __attribute__((force))\r
+# define __nocast      __attribute__((nocast))\r
+# define __iomem       __attribute__((noderef, address_space(2)))\r
+# define __acquires(x) __attribute__((context(0,1)))\r
+# define __releases(x) __attribute__((context(1,0)))\r
+# define __acquire(x)  __context__(1)\r
+# define __release(x)  __context__(-1)\r
+# define __cond_lock(x)        ((x) ? ({ __context__(1); 1; }) : 0)\r
+extern void __chk_user_ptr(void __user *);\r
+extern void __chk_io_ptr(void __iomem *);\r
+#else\r
+# define __user\r
+# define __kernel\r
+# define __safe\r
+# define __force\r
+# define __nocast\r
+# define __iomem\r
+# define __chk_user_ptr(x) (void)0\r
+# define __chk_io_ptr(x) (void)0\r
+//# define __builtin_warning(x, y...) (1)\r
+# define __acquires(x)\r
+# define __releases(x)\r
+# define __acquire(x) (void)0\r
+# define __release(x) (void)0\r
+# define __cond_lock(x) (x)\r
+#endif\r
+\r
+#ifdef __KERNEL__\r
+\r
+#if __GNUC__ > 4\r
+#error no compiler-gcc.h file for this gcc version\r
+#elif __GNUC__ == 4\r
+# include <linux/compiler-gcc4.h>\r
+#elif __GNUC__ == 3\r
+# include <linux/compiler-gcc3.h>\r
+#elif __GNUC__ == 2\r
+# include <linux/compiler-gcc2.h>\r
+#else\r
+# error Sorry, your compiler is too old/not recognized.\r
+#endif\r
+\r
+/* Intel compiler defines __GNUC__. So we will overwrite implementations\r
+ * coming from above header files here\r
+ */\r
+#ifdef __INTEL_COMPILER\r
+# include <linux/compiler-intel.h>\r
+#endif\r
+\r
+/*\r
+ * Generic compiler-dependent macros required for kernel\r
+ * build go below this comment. Actual compiler/compiler version\r
+ * specific implementations come from the above header files\r
+ */\r
+\r
+#define likely(x)      __builtin_expect(!!(x), 1)\r
+#define unlikely(x)    __builtin_expect(!!(x), 0)\r
+\r
+/* Optimization barrier */\r
+#ifndef barrier\r
+# define barrier() __memory_barrier()\r
+#endif\r
+\r
+#ifndef RELOC_HIDE\r
+# define RELOC_HIDE(ptr, off)                                  \\r
+  ({ unsigned long __ptr;                                      \\r
+     __ptr = (unsigned long) (ptr);                            \\r
+    (typeof(ptr)) (__ptr + (off)); })\r
+#endif\r
+\r
+#endif /* __KERNEL__ */\r
+\r
+#endif /* __ASSEMBLY__ */\r
+\r
+/*\r
+ * Allow us to mark functions as 'deprecated' and have gcc emit a nice\r
+ * warning for each use, in hopes of speeding the functions removal.\r
+ * Usage is:\r
+ *             int __deprecated foo(void)\r
+ */\r
+#ifndef __deprecated\r
+# define __deprecated          /* unimplemented */\r
+#endif\r
+\r
+#ifdef MODULE\r
+#define __deprecated_for_modules __deprecated\r
+#else\r
+#define __deprecated_for_modules\r
+#endif\r
+\r
+#ifndef __must_check\r
+#define __must_check\r
+#endif\r
+\r
+/*\r
+ * Allow us to avoid 'defined but not used' warnings on functions and data,\r
+ * as well as force them to be emitted to the assembly file.\r
+ *\r
+ * As of gcc 3.3, static functions that are not marked with attribute((used))\r
+ * may be elided from the assembly file.  As of gcc 3.3, static data not so\r
+ * marked will not be elided, but this may change in a future gcc version.\r
+ *\r
+ * In prior versions of gcc, such functions and data would be emitted, but\r
+ * would be warned about except with attribute((unused)).\r
+ */\r
+#ifndef __attribute_used__\r
+# define __attribute_used__    /* unimplemented */\r
+#endif\r
+\r
+/*\r
+ * From the GCC manual:\r
+ *\r
+ * Many functions have no effects except the return value and their\r
+ * return value depends only on the parameters and/or global\r
+ * variables.  Such a function can be subject to common subexpression\r
+ * elimination and loop optimization just as an arithmetic operator\r
+ * would be.\r
+ * [...]\r
+ */\r
+#ifndef __attribute_pure__\r
+# define __attribute_pure__    /* unimplemented */\r
+#endif\r
+\r
+/*\r
+ * From the GCC manual:\r
+ *\r
+ * Many functions do not examine any values except their arguments,\r
+ * and have no effects except the return value.  Basically this is\r
+ * just slightly more strict class than the `pure' attribute above,\r
+ * since function is not allowed to read global memory.\r
+ *\r
+ * Note that a function that has pointer arguments and examines the\r
+ * data pointed to must _not_ be declared `const'.  Likewise, a\r
+ * function that calls a non-`const' function usually must not be\r
+ * `const'.  It does not make sense for a `const' function to return\r
+ * `void'.\r
+ */\r
+#ifndef __attribute_const__\r
+# define __attribute_const__   /* unimplemented */\r
+#endif\r
+\r
+#ifndef noinline\r
+#define noinline\r
+#endif\r
+\r
+#ifndef __always_inline\r
+#define __always_inline inline\r
+#endif\r
+\r
+#endif /* __LINUX_COMPILER_H */\r
index 9efc571..40461bb 100644 (file)
-/* dosfsck.c  -  User interface */
-
-/* Written 1993 by Werner Almesberger */
-
-/* FAT32, VFAT, Atari format support, and various fixes additions May 1998
- * by Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> */
-
-
-#include "version.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <getopt.h>
-
-#include "common.h"
-#include "dosfsck.h"
-#include "io.h"
-#include "boot.h"
-#include "fat.h"
-#include "file.h"
-#include "check.h"
-
-
-int interactive = 0,list = 0,test = 0,verbose = 0,write_immed = 0;
-int atari_format = 0;
-unsigned n_files = 0;
-void *mem_queue = NULL;
-
-
-static void usage(char *name)
-{
-    fprintf(stderr,"usage: %s [-aAflrtvVwy] [-d path -d ...] "
-      "[-u path -u ...]\n%15sdevice\n",name,"");
-    fprintf(stderr,"  -a       automatically repair the file system\n");
-    fprintf(stderr,"  -A       toggle Atari file system format\n");
-    fprintf(stderr,"  -d path  drop that file\n");
-    fprintf(stderr,"  -f       salvage unused chains to files\n");
-    fprintf(stderr,"  -l       list path names\n");
-    fprintf(stderr,"  -n       no-op, check non-interactively without changing\n");
-    fprintf(stderr,"  -r       interactively repair the file system\n");
-    fprintf(stderr,"  -t       test for bad clusters\n");
-    fprintf(stderr,"  -u path  try to undelete that (non-directory) file\n");
-    fprintf(stderr,"  -v       verbose mode\n");
-    fprintf(stderr,"  -V       perform a verification pass\n");
-    fprintf(stderr,"  -w       write changes to disk immediately\n");
-    fprintf(stderr,"  -y       same as -a, for compat with other *fsck\n");
-    exit(2);
-}
-
-
-/*
- * ++roman: On m68k, check if this is an Atari; if yes, turn on Atari variant
- * of MS-DOS filesystem by default.
- */
-static void check_atari( void )
-{
-#ifdef __mc68000__
-    FILE *f;
-    char line[128], *p;
-
-    if (!(f = fopen( "/proc/hardware", "r" ))) {
-       perror( "/proc/hardware" );
-       return;
-    }
-
-    while( fgets( line, sizeof(line), f ) ) {
-       if (strncmp( line, "Model:", 6 ) == 0) {
-           p = line + 6;
-           p += strspn( p, " \t" );
-           if (strncmp( p, "Atari ", 6 ) == 0)
-               atari_format = 1;
-           break;
-       }
-    }
-    fclose( f );
-#endif
-}
-
-
-int main(int argc,char **argv)
-{
-    DOS_FS fs;
-    int rw,salvage_files,verify,c;
-    unsigned long free_clusters;
-    
-    rw = salvage_files = verify = 0;
-    interactive = 1;
-    check_atari();
-
-    while ((c = getopt(argc,argv,"Aad:flnrtu:vVwy")) != EOF)
-       switch (c) {
-           case 'A': /* toggle Atari format */
-               atari_format = !atari_format;
-               break;
-           case 'a':
-           case 'y':
-               rw = 1;
-               interactive = 0;
-               salvage_files = 1;
-               break;
-           case 'd':
-               file_add(optarg,fdt_drop);
-               break;
-           case 'f':
-               salvage_files = 1;
-               break;
-           case 'l':
-               list = 1;
-               break;
-           case 'n':
-               rw = 0;
-               interactive = 0;
-               break;
-           case 'r':
-               rw = 1;
-               interactive = 1;
-               break;
-           case 't':
-               test = 1;
-               break;
-           case 'u':
-               file_add(optarg,fdt_undelete);
-               break;
-           case 'v':
-               verbose = 1;
-               printf("dosfsck " VERSION " (" VERSION_DATE ")\n");
-               break;
-           case 'V':
-               verify = 1;
-               break;
-           case 'w':
-               write_immed = 1;
-               break;
-           default:
-               usage(argv[0]);
+/* dosfsck.c  -  User interface */\r
+\r
+/* Written 1993 by Werner Almesberger */\r
+\r
+/* FAT32, VFAT, Atari format support, and various fixes additions May 1998\r
+ * by Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> */\r
+\r
+\r
+#include "version.h"\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include <stdlib.h>\r
+#include <unistd.h>\r
+#include <getopt.h>\r
+\r
+#include "common.h"\r
+#include "dosfsck.h"\r
+#include "io.h"\r
+#include "boot.h"\r
+#include "fat.h"\r
+#include "file.h"\r
+#include "check.h"\r
+\r
+\r
+int interactive = 0,list = 0,test = 0,verbose = 0,write_immed = 0;\r
+int atari_format = 0;\r
+unsigned n_files = 0;\r
+void *mem_queue = NULL;\r
+\r
+\r
+static void usage(char *name)\r
+{\r
+    fprintf(stderr,"usage: %s [-aAflrtvVwy] [-d path -d ...] "\r
+      "[-u path -u ...]\n%15sdevice\n",name,"");\r
+    fprintf(stderr,"  -a       automatically repair the file system\n");\r
+    fprintf(stderr,"  -A       toggle Atari file system format\n");\r
+    fprintf(stderr,"  -d path  drop that file\n");\r
+    fprintf(stderr,"  -f       salvage unused chains to files\n");\r
+    fprintf(stderr,"  -l       list path names\n");\r
+    fprintf(stderr,"  -n       no-op, check non-interactively without changing\n");\r
+    fprintf(stderr,"  -r       interactively repair the file system\n");\r
+    fprintf(stderr,"  -t       test for bad clusters\n");\r
+    fprintf(stderr,"  -u path  try to undelete that (non-directory) file\n");\r
+    fprintf(stderr,"  -v       verbose mode\n");\r
+    fprintf(stderr,"  -V       perform a verification pass\n");\r
+    fprintf(stderr,"  -w       write changes to disk immediately\n");\r
+    fprintf(stderr,"  -y       same as -a, for compat with other *fsck\n");\r
+    exit(2);\r
+}\r
+\r
+\r
+/*\r
+ * ++roman: On m68k, check if this is an Atari; if yes, turn on Atari variant\r
+ * of MS-DOS filesystem by default.\r
+ */\r
+static void check_atari( void )\r
+{\r
+#ifdef __mc68000__\r
+    FILE *f;\r
+    char line[128], *p;\r
+\r
+    if (!(f = fopen( "/proc/hardware", "r" ))) {\r
+       perror( "/proc/hardware" );\r
+       return;\r
+    }\r
+\r
+    while( fgets( line, sizeof(line), f ) ) {\r
+       if (strncmp( line, "Model:", 6 ) == 0) {\r
+           p = line + 6;\r
+           p += strspn( p, " \t" );\r
+           if (strncmp( p, "Atari ", 6 ) == 0)\r
+               atari_format = 1;\r
+           break;\r
        }\r
-
-    if ((test || write_immed) && !rw) {
-       fprintf(stderr,"-t and -w require -a or -r\n");
-       exit(2);
-    }
-    if (optind != argc-1) usage(argv[0]);
-
-    printf( "dosfsck " VERSION ", " VERSION_DATE ", FAT32, LFN\n" );
-    fs_open(argv[optind],rw);
-    read_boot(&fs);
-    if (verify) printf("Starting check/repair pass.\n");
-    while (read_fat(&fs), scan_root(&fs)) qfree(&mem_queue);
-    if (test) fix_bad(&fs);
-    if (salvage_files) reclaim_file(&fs);
-    else reclaim_free(&fs);
-    free_clusters = update_free(&fs);
-    file_unused();
-    qfree(&mem_queue);
-    if (verify) {
-       printf("Starting verification pass.\n");
-       read_fat(&fs);
-       scan_root(&fs);
-       reclaim_free(&fs);
-       qfree(&mem_queue);
-    }
-
-    if (fs_changed()) {
-       if (rw) {
-           if (interactive)
-               rw = get_key("yn","Perform changes ? (y/n)") == 'y';
-           else printf("Performing changes.\n");
-       }
-       else
-           printf("Leaving file system unchanged.\n");
-    }
-
-    printf( "%s: %u files, %lu/%lu clusters\n", argv[optind],
-           n_files, fs.clusters - free_clusters, fs.clusters );
-
-    return fs_close(rw) ? 1 : 0;
-}
-
-/* Local Variables: */
-/* tab-width: 8     */
-/* End:             */
+    }\r
+    fclose( f );\r
+#endif\r
+}\r
+\r
+\r
+int main(int argc,char **argv)\r
+{\r
+    DOS_FS fs;\r
+    int rw,salvage_files,verify,c;\r
+    unsigned long free_clusters;\r
+    \r
+    rw = salvage_files = verify = 0;\r
+    interactive = 1;\r
+    check_atari();\r
+\r
+    while ((c = getopt(argc,argv,"Aad:flnrtu:vVwy")) != EOF)\r
+       switch (c) {\r
+           case 'A': /* toggle Atari format */\r
+               atari_format = !atari_format;\r
+               break;\r
+           case 'a':\r
+           case 'y':\r
+               rw = 1;\r
+               interactive = 0;\r
+               salvage_files = 1;\r
+               break;\r
+           case 'd':\r
+               file_add(optarg,fdt_drop);\r
+               break;\r
+           case 'f':\r
+               salvage_files = 1;\r
+               break;\r
+           case 'l':\r
+               list = 1;\r
+               break;\r
+           case 'n':\r
+               rw = 0;\r
+               interactive = 0;\r
+               break;\r
+           case 'r':\r
+               rw = 1;\r
+               interactive = 1;\r
+               break;\r
+           case 't':\r
+               test = 1;\r
+               break;\r
+           case 'u':\r
+               file_add(optarg,fdt_undelete);\r
+               break;\r
+           case 'v':\r
+               verbose = 1;\r
+               printf("dosfsck " VERSION " (" VERSION_DATE ")\n");\r
+               break;\r
+           case 'V':\r
+               verify = 1;\r
+               break;\r
+           case 'w':\r
+               write_immed = 1;\r
+               break;\r
+           default:\r
+               usage(argv[0]);\r
+       }\r
+\r
+    if ((test || write_immed) && !rw) {\r
+       fprintf(stderr,"-t and -w require -a or -r\n");\r
+       exit(2);\r
+    }\r
+    if (optind != argc-1) usage(argv[0]);\r
+\r
+    printf( "dosfsck " VERSION ", " VERSION_DATE ", FAT32, LFN\n" );\r
+    fs_open(argv[optind],rw);\r
+    read_boot(&fs);\r
+    if (verify) printf("Starting check/repair pass.\n");\r
+    while (read_fat(&fs), scan_root(&fs)) qfree(&mem_queue);\r
+    if (test) fix_bad(&fs);\r
+    if (salvage_files) reclaim_file(&fs);\r
+    else reclaim_free(&fs);\r
+    free_clusters = update_free(&fs);\r
+    file_unused();\r
+    qfree(&mem_queue);\r
+    if (verify) {\r
+       printf("Starting verification pass.\n");\r
+       read_fat(&fs);\r
+       scan_root(&fs);\r
+       reclaim_free(&fs);\r
+       qfree(&mem_queue);\r
+    }\r
+\r
+    if (fs_changed()) {\r
+       if (rw) {\r
+           if (interactive)\r
+               rw = get_key("yn","Perform changes ? (y/n)") == 'y';\r
+           else printf("Performing changes.\n");\r
+       }\r
+       else\r
+           printf("Leaving file system unchanged.\n");\r
+    }\r
+\r
+    printf( "%s: %u files, %lu/%lu clusters\n", argv[optind],\r
+           n_files, fs.clusters - free_clusters, fs.clusters );\r
+\r
+    return fs_close(rw) ? 1 : 0;\r
+}\r
+\r
+/* Local Variables: */\r
+/* tab-width: 8     */\r
+/* End:             */\r
index f3ab006..6fcc5b5 100644 (file)
-/* dosfsck.h  -  Common data structures and global variables */
-
-/* Written 1993 by Werner Almesberger */
-
-/* FAT32, VFAT, Atari format support, and various fixes additions May 1998
- * by Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> */
-
-
-#ifndef _DOSFSCK_H
-#define _DOSFSCK_H
-
-//#include "types.h"
-
+/* dosfsck.h  -  Common data structures and global variables */\r
+\r
+/* Written 1993 by Werner Almesberger */\r
+\r
+/* FAT32, VFAT, Atari format support, and various fixes additions May 1998\r
+ * by Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> */\r
+\r
+\r
+#ifndef _DOSFSCK_H\r
+#define _DOSFSCK_H\r
+\r
+//#include "types.h"\r
+\r
 #ifdef _WIN32\r
 \r
 typedef unsigned char __u8;\r
 typedef unsigned short __u16;\r
 typedef unsigned int __u32;\r
-typedef unsigned __int64 __u64;
-typedef unsigned short __le16;
+typedef unsigned __int64 __u64;\r
+typedef unsigned short __le16;\r
 typedef unsigned int  __le32;\r
 typedef __int64 loff_t;\r
 typedef __int64 ll_t;\r
-
-#define CF_LE_W(v) (v)
-#define CF_LE_L(v) (v)
-#define CT_LE_W(v) (v)
-#define CT_LE_L(v) (v)
-
-#endif
-
-#define _LINUX_STAT_H          /* hack to avoid inclusion of <linux/stat.h> */
-#define _LINUX_STRING_H_       /* hack to avoid inclusion of <linux/string.h>*/
-#define _LINUX_FS_H             /* hack to avoid inclusion of <linux/fs.h> */
-
-//#include <linux/version.h>
-//# include "types.h"
-# include "byteorder.h"
-
-#include "msdos_fs.h"
-
-#if 0
-#undef CF_LE_W
-#undef CF_LE_L
-#undef CT_LE_W
-#undef CT_LE_L
-#endif
-
-#if __BYTE_ORDER == __BIG_ENDIAN
-#include "byteswap.h"
-#if 0
-#define CF_LE_W(v) bswap_16(v)
-#define CF_LE_L(v) bswap_32(v)
-#define CT_LE_W(v) CF_LE_W(v)
-#define CT_LE_L(v) CF_LE_L(v)
-#endif
-#else
-#define CF_LE_W(v) (v)
-#define CF_LE_L(v) (v)
-#define CT_LE_W(v) (v)
-#define CT_LE_L(v) (v)
-#endif /* __BIG_ENDIAN */
-
-#define VFAT_LN_ATTR (ATTR_RO | ATTR_HIDDEN | ATTR_SYS | ATTR_VOLUME)
-
+\r
+#define CF_LE_W(v) (v)\r
+#define CF_LE_L(v) (v)\r
+#define CT_LE_W(v) (v)\r
+#define CT_LE_L(v) (v)\r
+\r
+#endif\r
+\r
+#define _LINUX_STAT_H          /* hack to avoid inclusion of <linux/stat.h> */\r
+#define _LINUX_STRING_H_       /* hack to avoid inclusion of <linux/string.h>*/\r
+#define _LINUX_FS_H             /* hack to avoid inclusion of <linux/fs.h> */\r
+\r
+//#include <linux/version.h>\r
+//# include "types.h"\r
+# include "byteorder.h"\r
+\r
+#include "msdos_fs.h"\r
+\r
+#if 0\r
+#undef CF_LE_W\r
+#undef CF_LE_L\r
+#undef CT_LE_W\r
+#undef CT_LE_L\r
+#endif\r
+\r
+#if __BYTE_ORDER == __BIG_ENDIAN\r
+#include "byteswap.h"\r
+#if 0\r
+#define CF_LE_W(v) bswap_16(v)\r
+#define CF_LE_L(v) bswap_32(v)\r
+#define CT_LE_W(v) CF_LE_W(v)\r
+#define CT_LE_L(v) CF_LE_L(v)\r
+#endif\r
+#else\r
+#define CF_LE_W(v) (v)\r
+#define CF_LE_L(v) (v)\r
+#define CT_LE_W(v) (v)\r
+#define CT_LE_L(v) (v)\r
+#endif /* __BIG_ENDIAN */\r
+\r
+#define VFAT_LN_ATTR (ATTR_RO | ATTR_HIDDEN | ATTR_SYS | ATTR_VOLUME)\r
+\r
 #include <pshpack1.h>\r
 \r
-/* ++roman: Use own definition of boot sector structure -- the kernel headers'
- * name for it is msdos_boot_sector in 2.0 and fat_boot_sector in 2.1 ... */
-struct boot_sector {
-    __u8       ignored[3];     /* Boot strap short or near jump */
-    __u8       system_id[8];   /* Name - can be used to special case
-                                  partition manager volumes */
-    __u8       sector_size[2]; /* bytes per logical sector */
-    __u8       cluster_size;   /* sectors/cluster */
-    __u16      reserved;       /* reserved sectors */
-    __u8       fats;           /* number of FATs */
-    __u8       dir_entries[2]; /* root directory entries */
-    __u8       sectors[2];     /* number of sectors */
-    __u8       media;          /* media code (unused) */
-    __u16      fat_length;     /* sectors/FAT */
-    __u16      secs_track;     /* sectors per track */
-    __u16      heads;          /* number of heads */
-    __u32      hidden;         /* hidden sectors (unused) */
-    __u32      total_sect;     /* number of sectors (if sectors == 0) */
-    
-    /* The following fields are only used by FAT32 */
-    __u32      fat32_length;   /* sectors/FAT */
-    __u16      flags;          /* bit 8: fat mirroring, low 4: active fat */
-    __u8       version[2];     /* major, minor filesystem version */
-    __u32      root_cluster;   /* first cluster in root directory */
-    __u16      info_sector;    /* filesystem info sector */
-    __u16      backup_boot;    /* backup boot sector */
-    __u16      reserved2[6];   /* Unused */
-
-    /* fill up to 512 bytes */
-    __u8       junk[448];
-};
+/* ++roman: Use own definition of boot sector structure -- the kernel headers'\r
+ * name for it is msdos_boot_sector in 2.0 and fat_boot_sector in 2.1 ... */\r
+struct boot_sector {\r
+    __u8       ignored[3];     /* Boot strap short or near jump */\r
+    __u8       system_id[8];   /* Name - can be used to special case\r
+                                  partition manager volumes */\r
+    __u8       sector_size[2]; /* bytes per logical sector */\r
+    __u8       cluster_size;   /* sectors/cluster */\r
+    __u16      reserved;       /* reserved sectors */\r
+    __u8       fats;           /* number of FATs */\r
+    __u8       dir_entries[2]; /* root directory entries */\r
+    __u8       sectors[2];     /* number of sectors */\r
+    __u8       media;          /* media code (unused) */\r
+    __u16      fat_length;     /* sectors/FAT */\r
+    __u16      secs_track;     /* sectors per track */\r
+    __u16      heads;          /* number of heads */\r
+    __u32      hidden;         /* hidden sectors (unused) */\r
+    __u32      total_sect;     /* number of sectors (if sectors == 0) */\r
+    \r
+    /* The following fields are only used by FAT32 */\r
+    __u32      fat32_length;   /* sectors/FAT */\r
+    __u16      flags;          /* bit 8: fat mirroring, low 4: active fat */\r
+    __u8       version[2];     /* major, minor filesystem version */\r
+    __u32      root_cluster;   /* first cluster in root directory */\r
+    __u16      info_sector;    /* filesystem info sector */\r
+    __u16      backup_boot;    /* backup boot sector */\r
+    __u16      reserved2[6];   /* Unused */\r
+\r
+    /* fill up to 512 bytes */\r
+    __u8       junk[448];\r
+};\r
 \r
 #include <poppack.h>\r
-
-struct info_sector {
-    __u32      magic;          /* Magic for info sector ('RRaA') */
-    __u8       junk[0x1dc];
-    __u32      reserved1;      /* Nothing as far as I can tell */
-    __u32      signature;      /* 0x61417272 ('rrAa') */
-    __u32      free_clusters;  /* Free cluster count.  -1 if unknown */
-    __u32      next_cluster;   /* Most recently allocated cluster. */
-    __u32      reserved2[3];
-    __u16      reserved3;
-    __u16      boot_sign;
-};
-
-typedef struct {
-    __u8       name[8],ext[3]; /* name and extension */
-    __u8       attr;           /* attribute bits */
-    __u8       lcase;          /* Case for base and extension */
-    __u8       ctime_ms;       /* Creation time, milliseconds */
-    __u16      ctime;          /* Creation time */
-    __u16      cdate;          /* Creation date */
-    __u16      adate;          /* Last access date */
-    __u16      starthi;        /* High 16 bits of cluster in FAT32 */
-    __u16      time,date,start;/* time, date and first cluster */
-    __u32      size;           /* file size (in bytes) */
-} DIR_ENT;
-
-typedef struct _dos_file {
-    DIR_ENT dir_ent;
-    char *lfn;
-    loff_t offset;
-    struct _dos_file *parent; /* parent directory */
-    struct _dos_file *next; /* next entry */
-    struct _dos_file *first; /* first entry (directory only) */
-} DOS_FILE;
-
-typedef struct {
-    unsigned long value;
-    unsigned long reserved;
-    DOS_FILE *owner;
-    int prev; /* number of previous clusters */
-} FAT_ENTRY;
-
-typedef struct {
-    int nfats;
-    loff_t fat_start;
-    unsigned int fat_size; /* unit is bytes */
-    unsigned int fat_bits; /* size of a FAT entry */
-    unsigned int eff_fat_bits; /* # of used bits in a FAT entry */
-    unsigned long root_cluster; /* 0 for old-style root dir */
-    loff_t root_start;
-    unsigned int root_entries;
-    loff_t data_start;
-    unsigned int cluster_size;
-    unsigned long clusters;
-    loff_t fsinfo_start; /* 0 if not present */
-    long free_clusters;
-    loff_t backupboot_start; /* 0 if not present */
-    FAT_ENTRY *fat;
-} DOS_FS;
-
-#ifndef offsetof
-#define offsetof(t,e)  ((int)&(((t *)0)->e))
-#endif
-
-extern int interactive,list,verbose,test,write_immed;
-extern int atari_format;
-extern unsigned n_files;
-extern void *mem_queue;
-
-/* value to use as end-of-file marker */
-#define FAT_EOF(fs)    ((atari_format ? 0xfff : 0xff8) | FAT_EXTD(fs))
-#define FAT_IS_EOF(fs,v) ((unsigned long)(v) >= (0xff8|FAT_EXTD(fs)))
-/* value to mark bad clusters */
-#define FAT_BAD(fs)    (0xff7 | FAT_EXTD(fs))
-/* range of values used for bad clusters */
-#define FAT_MIN_BAD(fs)        ((atari_format ? 0xff0 : 0xff7) | FAT_EXTD(fs))
-#define FAT_MAX_BAD(fs)        ((atari_format ? 0xff7 : 0xff7) | FAT_EXTD(fs))
-#define FAT_IS_BAD(fs,v) ((v) >= FAT_MIN_BAD(fs) && (v) <= FAT_MAX_BAD(fs))
-
-/* return -16 as a number with fs->fat_bits bits */
-#define FAT_EXTD(fs)   (((1 << fs->eff_fat_bits)-1) & ~0xf)
-
-#endif
-
-/* Local Variables: */
-/* tab-width: 8     */
-/* End:             */
+\r
+struct info_sector {\r
+    __u32      magic;          /* Magic for info sector ('RRaA') */\r
+    __u8       junk[0x1dc];\r
+    __u32      reserved1;      /* Nothing as far as I can tell */\r
+    __u32      signature;      /* 0x61417272 ('rrAa') */\r
+    __u32      free_clusters;  /* Free cluster count.  -1 if unknown */\r
+    __u32      next_cluster;   /* Most recently allocated cluster. */\r
+    __u32      reserved2[3];\r
+    __u16      reserved3;\r
+    __u16      boot_sign;\r
+};\r
+\r
+typedef struct {\r
+    __u8       name[8],ext[3]; /* name and extension */\r
+    __u8       attr;           /* attribute bits */\r
+    __u8       lcase;          /* Case for base and extension */\r
+    __u8       ctime_ms;       /* Creation time, milliseconds */\r
+    __u16      ctime;          /* Creation time */\r
+    __u16      cdate;          /* Creation date */\r
+    __u16      adate;          /* Last access date */\r
+    __u16      starthi;        /* High 16 bits of cluster in FAT32 */\r
+    __u16      time,date,start;/* time, date and first cluster */\r
+    __u32      size;           /* file size (in bytes) */\r
+} DIR_ENT;\r
+\r
+typedef struct _dos_file {\r
+    DIR_ENT dir_ent;\r
+    char *lfn;\r
+    loff_t offset;\r
+    struct _dos_file *parent; /* parent directory */\r
+    struct _dos_file *next; /* next entry */\r
+    struct _dos_file *first; /* first entry (directory only) */\r
+} DOS_FILE;\r
+\r
+typedef struct {\r
+    unsigned long value;\r
+    unsigned long reserved;\r
+    DOS_FILE *owner;\r
+    int prev; /* number of previous clusters */\r
+} FAT_ENTRY;\r
+\r
+typedef struct {\r
+    int nfats;\r
+    loff_t fat_start;\r
+    unsigned int fat_size; /* unit is bytes */\r
+    unsigned int fat_bits; /* size of a FAT entry */\r
+    unsigned int eff_fat_bits; /* # of used bits in a FAT entry */\r
+    unsigned long root_cluster; /* 0 for old-style root dir */\r
+    loff_t root_start;\r
+    unsigned int root_entries;\r
+    loff_t data_start;\r
+    unsigned int cluster_size;\r
+    unsigned long clusters;\r
+    loff_t fsinfo_start; /* 0 if not present */\r
+    long free_clusters;\r
+    loff_t backupboot_start; /* 0 if not present */\r
+    FAT_ENTRY *fat;\r
+} DOS_FS;\r
+\r
+#ifndef offsetof\r
+#define offsetof(t,e)  ((int)&(((t *)0)->e))\r
+#endif\r
+\r
+extern int interactive,list,verbose,test,write_immed;\r
+extern int atari_format;\r
+extern unsigned n_files;\r
+extern void *mem_queue;\r
+\r
+/* value to use as end-of-file marker */\r
+#define FAT_EOF(fs)    ((atari_format ? 0xfff : 0xff8) | FAT_EXTD(fs))\r
+#define FAT_IS_EOF(fs,v) ((unsigned long)(v) >= (0xff8|FAT_EXTD(fs)))\r
+/* value to mark bad clusters */\r
+#define FAT_BAD(fs)    (0xff7 | FAT_EXTD(fs))\r
+/* range of values used for bad clusters */\r
+#define FAT_MIN_BAD(fs)        ((atari_format ? 0xff0 : 0xff7) | FAT_EXTD(fs))\r
+#define FAT_MAX_BAD(fs)        ((atari_format ? 0xff7 : 0xff7) | FAT_EXTD(fs))\r
+#define FAT_IS_BAD(fs,v) ((v) >= FAT_MIN_BAD(fs) && (v) <= FAT_MAX_BAD(fs))\r
+\r
+/* return -16 as a number with fs->fat_bits bits */\r
+#define FAT_EXTD(fs)   (((1 << fs->eff_fat_bits)-1) & ~0xf)\r
+\r
+#endif\r
+\r
+/* Local Variables: */\r
+/* tab-width: 8     */\r
+/* End:             */\r
index 921d9f7..5f29d5f 100644 (file)
-/* fat.c  -  Read/write access to the FAT */
-
-/* Written 1993 by Werner Almesberger */
-
-/* FAT32, VFAT, Atari format support, and various fixes additions May 1998
- * by Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> */
-
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-//#include <unistd.h>
-
-#include "common.h"
-#include "dosfsck.h"
-#include "io.h"
-#include "check.h"
-#include "fat.h"
-\r
-#pragma warning(disable: 4018)
-
-static void get_fat(FAT_ENTRY *entry,void *fat,unsigned long cluster,DOS_FS *fs)
-{
-    unsigned char *ptr;
-
-    switch(fs->fat_bits) {
-      case 12:
-       ptr = &((unsigned char *) fat)[cluster*3/2];
-       entry->value = 0xfff & (cluster & 1 ? (ptr[0] >> 4) | (ptr[1] << 4) :
-         (ptr[0] | ptr[1] << 8));
-       break;
-      case 16:
-       entry->value = CF_LE_W(((unsigned short *) fat)[cluster]);
-       break;
-      case 32:
-       /* According to M$, the high 4 bits of a FAT32 entry are reserved and
-        * are not part of the cluster number. So we cut them off. */
-       {
-           unsigned long e = CF_LE_L(((unsigned int *) fat)[cluster]);
-           entry->value = e & 0xfffffff;
-           entry->reserved = e >> 28;
-       }
-       break;
-      default:
-       die("Bad FAT entry size: %d bits.",fs->fat_bits);
-    }
-    entry->owner = NULL;
-}
-
-
-void read_fat(DOS_FS *fs)
-{
-    int eff_size;
-    unsigned long i;
-    void *first,*second,*use;
-    int first_ok,second_ok;
-
+/* fat.c  -  Read/write access to the FAT */\r
+\r
+/* Written 1993 by Werner Almesberger */\r
+\r
+/* FAT32, VFAT, Atari format support, and various fixes additions May 1998\r
+ * by Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> */\r
+\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+//#include <unistd.h>\r
+\r
+#include "common.h"\r
+#include "dosfsck.h"\r
+#include "io.h"\r
+#include "check.h"\r
+#include "fat.h"\r
+\r
+#pragma warning(disable: 4018)\r
+\r
+static void get_fat(FAT_ENTRY *entry,void *fat,unsigned long cluster,DOS_FS *fs)\r
+{\r
+    unsigned char *ptr;\r
+\r
+    switch(fs->fat_bits) {\r
+      case 12:\r
+       ptr = &((unsigned char *) fat)[cluster*3/2];\r
+       entry->value = 0xfff & (cluster & 1 ? (ptr[0] >> 4) | (ptr[1] << 4) :\r
+         (ptr[0] | ptr[1] << 8));\r
+       break;\r
+      case 16:\r
+       entry->value = CF_LE_W(((unsigned short *) fat)[cluster]);\r
+       break;\r
+      case 32:\r
+       /* According to M$, the high 4 bits of a FAT32 entry are reserved and\r
+        * are not part of the cluster number. So we cut them off. */\r
+       {\r
+           unsigned long e = CF_LE_L(((unsigned int *) fat)[cluster]);\r
+           entry->value = e & 0xfffffff;\r
+           entry->reserved = e >> 28;\r
+       }\r
+       break;\r
+      default:\r
+       die("Bad FAT entry size: %d bits.",fs->fat_bits);\r
+    }\r
+    entry->owner = NULL;\r
+}\r
+\r
+\r
+void read_fat(DOS_FS *fs)\r
+{\r
+    int eff_size;\r
+    unsigned long i;\r
+    void *first,*second,*use;\r
+    int first_ok,second_ok;\r
+\r
     eff_size = ((fs->clusters+2)*fs->fat_bits+7)/8;\r
        // TMN: Must round up to disk-sector boundary. For now, assume 512-byte disk.\r
        if (eff_size % 512) {\r
                eff_size += 512 - (eff_size % 512);\r
-       }
-    first = alloc(eff_size);
-    fs_read(fs->fat_start,eff_size,first);
-    use = first;
-    if (fs->nfats > 1) {
-       second = alloc(eff_size);
-       fs_read(fs->fat_start+fs->fat_size,eff_size,second);
-    }
-    else
-       second = NULL;
-    if (second && memcmp(first,second,eff_size) != 0) {
-       FAT_ENTRY first_media, second_media;
-       get_fat(&first_media,first,0,fs);
-       get_fat(&second_media,second,0,fs);
-       first_ok = (first_media.value & FAT_EXTD(fs)) == FAT_EXTD(fs);
-       second_ok = (second_media.value & FAT_EXTD(fs)) == FAT_EXTD(fs);
-       if (first_ok && !second_ok) {
-           printf("FATs differ - using first FAT.\n");
-           fs_write(fs->fat_start+fs->fat_size,eff_size,use = first);
-       }
-       if (!first_ok && second_ok) {
-           printf("FATs differ - using second FAT.\n");
-           fs_write(fs->fat_start,eff_size,use = second);
-       }
-       if (first_ok && second_ok) {
-           if (interactive) {
-               printf("FATs differ but appear to be intact. Use which FAT ?\n"
-                 "1) Use first FAT\n2) Use second FAT\n");
-               if (get_key("12","?") == '1')
-                   fs_write(fs->fat_start+fs->fat_size,eff_size,use = first);
-               else fs_write(fs->fat_start,eff_size,use = second);
-           }
-           else {
-               printf("FATs differ but appear to be intact. Using first "
-                 "FAT.\n");
-               fs_write(fs->fat_start+fs->fat_size,eff_size,use = first);
-           }
-       }
-       if (!first_ok && !second_ok) {
-           printf("Both FATs appear to be corrupt. Giving up.\n");
-           exit(1);
-       }
-    }
-    fs->fat = qalloc(&mem_queue,sizeof(FAT_ENTRY)*(fs->clusters+2));
-    for (i = 2; i < fs->clusters+2; i++) get_fat(&fs->fat[i],use,i,fs);
-    for (i = 2; i < fs->clusters+2; i++)
-       if (fs->fat[i].value >= fs->clusters+2 &&
-           (fs->fat[i].value < FAT_MIN_BAD(fs))) {
-           printf("Cluster %ld out of range (%ld > %ld). Setting to EOF.\n",
-                  i-2,fs->fat[i].value,fs->clusters+2-1);
-           set_fat(fs,i,-1);
-       }
-    free(first);
-    if (second)
-       free(second);
-}
-
-
-void set_fat(DOS_FS *fs,unsigned long cluster,unsigned long new)
-{
-    unsigned char data[4];
-    int size;
-    loff_t offs;
-
-    if ((long)new == -1)
-       new = FAT_EOF(fs);
-    else if ((long)new == -2)
-       new = FAT_BAD(fs);
-    switch( fs->fat_bits ) {
-      case 12:
-       offs = fs->fat_start+cluster*3/2;
-       if (cluster & 1) {
-           data[0] = ((new & 0xf) << 4) | (fs->fat[cluster-1].value >> 8);
-           data[1] = new >> 4;
-       }
-       else {
-           data[0] = new & 0xff;
-           data[1] = (new >> 8) | (cluster == fs->clusters-1 ? 0 :
-             (0xff & fs->fat[cluster+1].value) << 4);
-       }
-       size = 2;
-       break;
-      case 16:
-       offs = fs->fat_start+cluster*2;
-       *(unsigned short *) data = CT_LE_W(new);
-       size = 2;
-       break;
-      case 32:
-       offs = fs->fat_start+cluster*4;
-       /* According to M$, the high 4 bits of a FAT32 entry are reserved and
-        * are not part of the cluster number. So we never touch them. */
-       *(unsigned long *) data = CT_LE_L( (new & 0xfffffff) |
-                                          (fs->fat[cluster].reserved << 28) );
-       size = 4;
-       break;
-      default:
-       die("Bad FAT entry size: %d bits.",fs->fat_bits);
-    }
-    fs->fat[cluster].value = new;
-    fs_write(offs,size,&data);
-    fs_write(offs+fs->fat_size,size,&data);
-}
-
-
-int bad_cluster(DOS_FS *fs,unsigned long cluster)
-{
-    return FAT_IS_BAD(fs,fs->fat[cluster].value);
-}
-
-
-unsigned long next_cluster(DOS_FS *fs,unsigned long cluster)
-{
-    unsigned long value;
-
-    value = fs->fat[cluster].value;
-    if (FAT_IS_BAD(fs,value))
-       die("Internal error: next_cluster on bad cluster");
-    return FAT_IS_EOF(fs,value) ? -1 : value;
-}
-
-
-loff_t cluster_start(DOS_FS *fs,unsigned long cluster)
-{
-    return fs->data_start+((loff_t)cluster-2)*fs->cluster_size;
-}
-
-
-void set_owner(DOS_FS *fs,unsigned long cluster,DOS_FILE *owner)
-{
-    if (owner && fs->fat[cluster].owner)
-       die("Internal error: attempt to change file owner");
-    fs->fat[cluster].owner = owner;
-}
-
-
-DOS_FILE *get_owner(DOS_FS *fs,unsigned long cluster)
-{
-    return fs->fat[cluster].owner;
-}
-
-
-void fix_bad(DOS_FS *fs)
-{
-    unsigned long i;
-
-    if (verbose)
-       printf("Checking for bad clusters.\n");
-    for (i = 2; i < fs->clusters+2; i++)
-       if (!get_owner(fs,i) && !FAT_IS_BAD(fs,fs->fat[i].value))
-           if (!fs_test(cluster_start(fs,i),fs->cluster_size)) {
-               printf("Cluster %lu is unreadable.\n",i);
-               set_fat(fs,i,-2);
-           }
-}
-
-
-void reclaim_free(DOS_FS *fs)
-{
-    int reclaimed;
-    unsigned long i;
-
-    if (verbose)
-       printf("Checking for unused clusters.\n");
-    reclaimed = 0;
-    for (i = 2; i < fs->clusters+2; i++)
-       if (!get_owner(fs,i) && fs->fat[i].value &&
-           !FAT_IS_BAD(fs,fs->fat[i].value)) {
-           set_fat(fs,i,0);
-           reclaimed++;
-       }
-    if (reclaimed)
-       printf("Reclaimed %d unused cluster%s (%d bytes).\n",reclaimed,
-         reclaimed == 1 ?  "" : "s",reclaimed*fs->cluster_size);
-}
-
-
-static void tag_free(DOS_FS *fs,DOS_FILE *ptr)
-{
-    DOS_FILE *owner;
-    int prev;
-    unsigned long i,walk;
-
-    for (i = 2; i < fs->clusters+2; i++)
-       if (fs->fat[i].value && !FAT_IS_BAD(fs,fs->fat[i].value) &&
-           !get_owner(fs,i) && !fs->fat[i].prev) {
-           prev = 0;
-           for (walk = i; walk > 0 && walk != -1;
-                walk = next_cluster(fs,walk)) {
-               if (!(owner = get_owner(fs,walk))) set_owner(fs,walk,ptr);
-               else if (owner != ptr)
-                       die("Internal error: free chain collides with file");
-                   else {
-                       set_fat(fs,prev,-1);
-                       break;
-                   }
-               prev = walk;
-           }
-       }
-}
-
-
-void reclaim_file(DOS_FS *fs)
-{
-    DOS_FILE dummy;
-    int reclaimed,files,changed;
-    unsigned long i,next,walk;
-
-    if (verbose)
-       printf("Reclaiming unconnected clusters.\n");
-    for (i = 2; i < fs->clusters+2; i++) fs->fat[i].prev = 0;
-    for (i = 2; i < fs->clusters+2; i++) {
-       next = fs->fat[i].value;
-       if (!get_owner(fs,i) && next && next < fs->clusters+2) {
-           if (get_owner(fs,next) || !fs->fat[next].value ||
-               FAT_IS_BAD(fs,fs->fat[next].value)) set_fat(fs,i,-1);
-           else fs->fat[next].prev++;
-       }
-    }
-    do {
-       tag_free(fs,&dummy);
-       changed = 0;
-       for (i = 2; i < fs->clusters+2; i++)
-           if (fs->fat[i].value && !FAT_IS_BAD(fs,fs->fat[i].value) &&
-               !get_owner(fs, i)) {
-               if (!fs->fat[fs->fat[i].value].prev--)
-                   die("Internal error: prev going below zero");
-               set_fat(fs,i,-1);
-               changed = 1;
-               printf("Broke cycle at cluster %lu in free chain.\n",i);
-               break;
-           }
-    }
-    while (changed);
-    files = reclaimed = 0;
-    for (i = 2; i < fs->clusters+2; i++)
-       if (get_owner(fs,i) == &dummy && !fs->fat[i].prev) {
-           DIR_ENT de;
-           loff_t offset;
-           files++;
-           offset = alloc_rootdir_entry(fs,&de,"FSCK%04dREC");
-           de.start = CT_LE_W(i&0xffff);
-           if (fs->fat_bits == 32)
-               de.starthi = CT_LE_W(i>>16);
-           for (walk = i; walk > 0 && walk != -1;
-                walk = next_cluster(fs,walk)) {
-               de.size = CT_LE_L(CF_LE_L(de.size)+fs->cluster_size);
-               reclaimed++;
-           }
-           fs_write(offset,sizeof(DIR_ENT),&de);
-       }
-    if (reclaimed)
-       printf("Reclaimed %d unused cluster%s (%d bytes) in %d chain%s.\n",
-         reclaimed,reclaimed == 1 ? "" : "s",reclaimed*fs->cluster_size,files,
-         files == 1 ? "" : "s");
-}
-
-
-unsigned long update_free(DOS_FS *fs)
-{
-    unsigned long i;
-    unsigned long free = 0;
-    int do_set = 0;
-
-    for (i = 2; i < fs->clusters+2; i++)
-       if (!get_owner(fs,i) && !FAT_IS_BAD(fs,fs->fat[i].value))
-           ++free;
-
-    if (!fs->fsinfo_start)
-       return free;
-
-    if (verbose)
-       printf("Checking free cluster summary.\n");
-    if (fs->free_clusters >= 0) {
-       if (free != fs->free_clusters) {
-           printf( "Free cluster summary wrong (%ld vs. really %ld)\n",
-                   fs->free_clusters,free);
-           if (interactive)
-               printf( "1) Correct\n2) Don't correct\n" );
-           else printf( "  Auto-correcting.\n" );
-           if (!interactive || get_key("12","?") == '1')
-               do_set = 1;
-       }
-    }
-    else {
-       printf( "Free cluster summary uninitialized (should be %ld)\n", free );
-       if (interactive)
-           printf( "1) Set it\n2) Leave it uninitialized\n" );
-       else printf( "  Auto-setting.\n" );
-       if (!interactive || get_key("12","?") == '1')
-           do_set = 1;
-    }
-
-    if (do_set) {
-       fs->free_clusters = free;
-       free = CT_LE_L(free);
-       fs_write(fs->fsinfo_start+offsetof(struct info_sector,free_clusters),
-                sizeof(free),&free);
-    }
-
-    return free;
-}
-
-/* Local Variables: */
-/* tab-width: 8     */
-/* End:             */
+       }\r
+    first = alloc(eff_size);\r
+    fs_read(fs->fat_start,eff_size,first);\r
+    use = first;\r
+    if (fs->nfats > 1) {\r
+       second = alloc(eff_size);\r
+       fs_read(fs->fat_start+fs->fat_size,eff_size,second);\r
+    }\r
+    else\r
+       second = NULL;\r
+    if (second && memcmp(first,second,eff_size) != 0) {\r
+       FAT_ENTRY first_media, second_media;\r
+       get_fat(&first_media,first,0,fs);\r
+       get_fat(&second_media,second,0,fs);\r
+       first_ok = (first_media.value & FAT_EXTD(fs)) == FAT_EXTD(fs);\r
+       second_ok = (second_media.value & FAT_EXTD(fs)) == FAT_EXTD(fs);\r
+       if (first_ok && !second_ok) {\r
+           printf("FATs differ - using first FAT.\n");\r
+           fs_write(fs->fat_start+fs->fat_size,eff_size,use = first);\r
+       }\r
+       if (!first_ok && second_ok) {\r
+           printf("FATs differ - using second FAT.\n");\r
+           fs_write(fs->fat_start,eff_size,use = second);\r
+       }\r
+       if (first_ok && second_ok) {\r
+           if (interactive) {\r
+               printf("FATs differ but appear to be intact. Use which FAT ?\n"\r
+                 "1) Use first FAT\n2) Use second FAT\n");\r
+               if (get_key("12","?") == '1')\r
+                   fs_write(fs->fat_start+fs->fat_size,eff_size,use = first);\r
+               else fs_write(fs->fat_start,eff_size,use = second);\r
+           }\r
+           else {\r
+               printf("FATs differ but appear to be intact. Using first "\r
+                 "FAT.\n");\r
+               fs_write(fs->fat_start+fs->fat_size,eff_size,use = first);\r
+           }\r
+       }\r
+       if (!first_ok && !second_ok) {\r
+           printf("Both FATs appear to be corrupt. Giving up.\n");\r
+           exit(1);\r
+       }\r
+    }\r
+    fs->fat = qalloc(&mem_queue,sizeof(FAT_ENTRY)*(fs->clusters+2));\r
+    for (i = 2; i < fs->clusters+2; i++) get_fat(&fs->fat[i],use,i,fs);\r
+    for (i = 2; i < fs->clusters+2; i++)\r
+       if (fs->fat[i].value >= fs->clusters+2 &&\r
+           (fs->fat[i].value < FAT_MIN_BAD(fs))) {\r
+           printf("Cluster %ld out of range (%ld > %ld). Setting to EOF.\n",\r
+                  i-2,fs->fat[i].value,fs->clusters+2-1);\r
+           set_fat(fs,i,-1);\r
+       }\r
+    free(first);\r
+    if (second)\r
+       free(second);\r
+}\r
+\r
+\r
+void set_fat(DOS_FS *fs,unsigned long cluster,unsigned long new)\r
+{\r
+    unsigned char data[4];\r
+    int size;\r
+    loff_t offs;\r
+\r
+    if ((long)new == -1)\r
+       new = FAT_EOF(fs);\r
+    else if ((long)new == -2)\r
+       new = FAT_BAD(fs);\r
+    switch( fs->fat_bits ) {\r
+      case 12:\r
+       offs = fs->fat_start+cluster*3/2;\r
+       if (cluster & 1) {\r
+           data[0] = ((new & 0xf) << 4) | (fs->fat[cluster-1].value >> 8);\r
+           data[1] = new >> 4;\r
+       }\r
+       else {\r
+           data[0] = new & 0xff;\r
+           data[1] = (new >> 8) | (cluster == fs->clusters-1 ? 0 :\r
+             (0xff & fs->fat[cluster+1].value) << 4);\r
+       }\r
+       size = 2;\r
+       break;\r
+      case 16:\r
+       offs = fs->fat_start+cluster*2;\r
+       *(unsigned short *) data = CT_LE_W(new);\r
+       size = 2;\r
+       break;\r
+      case 32:\r
+       offs = fs->fat_start+cluster*4;\r
+       /* According to M$, the high 4 bits of a FAT32 entry are reserved and\r
+        * are not part of the cluster number. So we never touch them. */\r
+       *(unsigned long *) data = CT_LE_L( (new & 0xfffffff) |\r
+                                          (fs->fat[cluster].reserved << 28) );\r
+       size = 4;\r
+       break;\r
+      default:\r
+       die("Bad FAT entry size: %d bits.",fs->fat_bits);\r
+    }\r
+    fs->fat[cluster].value = new;\r
+    fs_write(offs,size,&data);\r
+    fs_write(offs+fs->fat_size,size,&data);\r
+}\r
+\r
+\r
+int bad_cluster(DOS_FS *fs,unsigned long cluster)\r
+{\r
+    return FAT_IS_BAD(fs,fs->fat[cluster].value);\r
+}\r
+\r
+\r
+unsigned long next_cluster(DOS_FS *fs,unsigned long cluster)\r
+{\r
+    unsigned long value;\r
+\r
+    value = fs->fat[cluster].value;\r
+    if (FAT_IS_BAD(fs,value))\r
+       die("Internal error: next_cluster on bad cluster");\r
+    return FAT_IS_EOF(fs,value) ? -1 : value;\r
+}\r
+\r
+\r
+loff_t cluster_start(DOS_FS *fs,unsigned long cluster)\r
+{\r
+    return fs->data_start+((loff_t)cluster-2)*fs->cluster_size;\r
+}\r
+\r
+\r
+void set_owner(DOS_FS *fs,unsigned long cluster,DOS_FILE *owner)\r
+{\r
+    if (owner && fs->fat[cluster].owner)\r
+       die("Internal error: attempt to change file owner");\r
+    fs->fat[cluster].owner = owner;\r
+}\r
+\r
+\r
+DOS_FILE *get_owner(DOS_FS *fs,unsigned long cluster)\r
+{\r
+    return fs->fat[cluster].owner;\r
+}\r
+\r
+\r
+void fix_bad(DOS_FS *fs)\r
+{\r
+    unsigned long i;\r
+\r
+    if (verbose)\r
+       printf("Checking for bad clusters.\n");\r
+    for (i = 2; i < fs->clusters+2; i++)\r
+       if (!get_owner(fs,i) && !FAT_IS_BAD(fs,fs->fat[i].value))\r
+           if (!fs_test(cluster_start(fs,i),fs->cluster_size)) {\r
+               printf("Cluster %lu is unreadable.\n",i);\r
+               set_fat(fs,i,-2);\r
+           }\r
+}\r
+\r
+\r
+void reclaim_free(DOS_FS *fs)\r
+{\r
+    int reclaimed;\r
+    unsigned long i;\r
+\r
+    if (verbose)\r
+       printf("Checking for unused clusters.\n");\r
+    reclaimed = 0;\r
+    for (i = 2; i < fs->clusters+2; i++)\r
+       if (!get_owner(fs,i) && fs->fat[i].value &&\r
+           !FAT_IS_BAD(fs,fs->fat[i].value)) {\r
+           set_fat(fs,i,0);\r
+           reclaimed++;\r
+       }\r
+    if (reclaimed)\r
+       printf("Reclaimed %d unused cluster%s (%d bytes).\n",reclaimed,\r
+         reclaimed == 1 ?  "" : "s",reclaimed*fs->cluster_size);\r
+}\r
+\r
+\r
+static void tag_free(DOS_FS *fs,DOS_FILE *ptr)\r
+{\r
+    DOS_FILE *owner;\r
+    int prev;\r
+    unsigned long i,walk;\r
+\r
+    for (i = 2; i < fs->clusters+2; i++)\r
+       if (fs->fat[i].value && !FAT_IS_BAD(fs,fs->fat[i].value) &&\r
+           !get_owner(fs,i) && !fs->fat[i].prev) {\r
+           prev = 0;\r
+           for (walk = i; walk > 0 && walk != -1;\r
+                walk = next_cluster(fs,walk)) {\r
+               if (!(owner = get_owner(fs,walk))) set_owner(fs,walk,ptr);\r
+               else if (owner != ptr)\r
+                       die("Internal error: free chain collides with file");\r
+                   else {\r
+                       set_fat(fs,prev,-1);\r
+                       break;\r
+                   }\r
+               prev = walk;\r
+           }\r
+       }\r
+}\r
+\r
+\r
+void reclaim_file(DOS_FS *fs)\r
+{\r
+    DOS_FILE dummy;\r
+    int reclaimed,files,changed;\r
+    unsigned long i,next,walk;\r
+\r
+    if (verbose)\r
+       printf("Reclaiming unconnected clusters.\n");\r
+    for (i = 2; i < fs->clusters+2; i++) fs->fat[i].prev = 0;\r
+    for (i = 2; i < fs->clusters+2; i++) {\r
+       next = fs->fat[i].value;\r
+       if (!get_owner(fs,i) && next && next < fs->clusters+2) {\r
+           if (get_owner(fs,next) || !fs->fat[next].value ||\r
+               FAT_IS_BAD(fs,fs->fat[next].value)) set_fat(fs,i,-1);\r
+           else fs->fat[next].prev++;\r
+       }\r
+    }\r
+    do {\r
+       tag_free(fs,&dummy);\r
+       changed = 0;\r
+       for (i = 2; i < fs->clusters+2; i++)\r
+           if (fs->fat[i].value && !FAT_IS_BAD(fs,fs->fat[i].value) &&\r
+               !get_owner(fs, i)) {\r
+               if (!fs->fat[fs->fat[i].value].prev--)\r
+                   die("Internal error: prev going below zero");\r
+               set_fat(fs,i,-1);\r
+               changed = 1;\r
+               printf("Broke cycle at cluster %lu in free chain.\n",i);\r
+               break;\r
+           }\r
+    }\r
+    while (changed);\r
+    files = reclaimed = 0;\r
+    for (i = 2; i < fs->clusters+2; i++)\r
+       if (get_owner(fs,i) == &dummy && !fs->fat[i].prev) {\r
+           DIR_ENT de;\r
+           loff_t offset;\r
+           files++;\r
+           offset = alloc_rootdir_entry(fs,&de,"FSCK%04dREC");\r
+           de.start = CT_LE_W(i&0xffff);\r
+           if (fs->fat_bits == 32)\r
+               de.starthi = CT_LE_W(i>>16);\r
+           for (walk = i; walk > 0 && walk != -1;\r
+                walk = next_cluster(fs,walk)) {\r
+               de.size = CT_LE_L(CF_LE_L(de.size)+fs->cluster_size);\r
+               reclaimed++;\r
+           }\r
+           fs_write(offset,sizeof(DIR_ENT),&de);\r
+       }\r
+    if (reclaimed)\r
+       printf("Reclaimed %d unused cluster%s (%d bytes) in %d chain%s.\n",\r
+         reclaimed,reclaimed == 1 ? "" : "s",reclaimed*fs->cluster_size,files,\r
+         files == 1 ? "" : "s");\r
+}\r
+\r
+\r
+unsigned long update_free(DOS_FS *fs)\r
+{\r
+    unsigned long i;\r
+    unsigned long free = 0;\r
+    int do_set = 0;\r
+\r
+    for (i = 2; i < fs->clusters+2; i++)\r
+       if (!get_owner(fs,i) && !FAT_IS_BAD(fs,fs->fat[i].value))\r
+           ++free;\r
+\r
+    if (!fs->fsinfo_start)\r
+       return free;\r
+\r
+    if (verbose)\r
+       printf("Checking free cluster summary.\n");\r
+    if (fs->free_clusters >= 0) {\r
+       if (free != fs->free_clusters) {\r
+           printf( "Free cluster summary wrong (%ld vs. really %ld)\n",\r
+                   fs->free_clusters,free);\r
+           if (interactive)\r
+               printf( "1) Correct\n2) Don't correct\n" );\r
+           else printf( "  Auto-correcting.\n" );\r
+           if (!interactive || get_key("12","?") == '1')\r
+               do_set = 1;\r
+       }\r
+    }\r
+    else {\r
+       printf( "Free cluster summary uninitialized (should be %ld)\n", free );\r
+       if (interactive)\r
+           printf( "1) Set it\n2) Leave it uninitialized\n" );\r
+       else printf( "  Auto-setting.\n" );\r
+       if (!interactive || get_key("12","?") == '1')\r
+           do_set = 1;\r
+    }\r
+\r
+    if (do_set) {\r
+       fs->free_clusters = free;\r
+       free = CT_LE_L(free);\r
+       fs_write(fs->fsinfo_start+offsetof(struct info_sector,free_clusters),\r
+                sizeof(free),&free);\r
+    }\r
+\r
+    return free;\r
+}\r
+\r
+/* Local Variables: */\r
+/* tab-width: 8     */\r
+/* End:             */\r
index 8c2312d..32b23de 100644 (file)
@@ -1,64 +1,64 @@
-/* fat.h  -  Read/write access to the FAT */
-
-/* Written 1993 by Werner Almesberger */
-
-
-#ifndef _FAT_H
-#define _FAT_H
-
-void read_fat(DOS_FS *fs);
-
-/* Loads the FAT of the file system described by FS. Initializes the FAT,
-   replaces broken FATs and rejects invalid cluster entries. */
-
-void set_fat(DOS_FS *fs,unsigned long cluster,unsigned long new);
-
-/* Changes the value of the CLUSTERth cluster of the FAT of FS to NEW. Special
-   values of NEW are -1 (EOF, 0xff8 or 0xfff8) and -2 (bad sector, 0xff7 or
-   0xfff7) */
-
-int bad_cluster(DOS_FS *fs,unsigned long cluster);
-
-/* Returns a non-zero integer if the CLUSTERth cluster is marked as bad or zero
-   otherwise. */
-
-unsigned long next_cluster(DOS_FS *fs,unsigned long cluster);
-
-/* Returns the number of the cluster following CLUSTER, or -1 if this is the
-   last cluster of the respective cluster chain. CLUSTER must not be a bad
-   cluster. */
-
-loff_t cluster_start(DOS_FS *fs,unsigned long cluster);
-
-/* Returns the byte offset of CLUSTER, relative to the respective device. */
-
-void set_owner(DOS_FS *fs,unsigned long cluster,DOS_FILE *owner);
-
-/* Sets the owner pointer of the respective cluster to OWNER. If OWNER was NULL
-   before, it can be set to NULL or any non-NULL value. Otherwise, only NULL is
-   accepted as the new value. */
-
-DOS_FILE *get_owner(DOS_FS *fs,unsigned long cluster);
-
-/* Returns the owner of the repective cluster or NULL if the cluster has no
-   owner. */
-
-void fix_bad(DOS_FS *fs);
-
-/* Scans the disk for currently unused bad clusters and marks them as bad. */
-
-void reclaim_free(DOS_FS *fs);
-
-/* Marks all allocated, but unused clusters as free. */
-
-void reclaim_file(DOS_FS *fs);
-
-/* Scans the FAT for chains of allocated, but unused clusters and creates files
-   for them in the root directory. Also tries to fix all inconsistencies (e.g.
-   loops, shared clusters, etc.) in the process. */
-
-unsigned long update_free(DOS_FS *fs);
-
-/* Updates free cluster count in FSINFO sector. */
-
-#endif
+/* fat.h  -  Read/write access to the FAT */\r
+\r
+/* Written 1993 by Werner Almesberger */\r
+\r
+\r
+#ifndef _FAT_H\r
+#define _FAT_H\r
+\r
+void read_fat(DOS_FS *fs);\r
+\r
+/* Loads the FAT of the file system described by FS. Initializes the FAT,\r
+   replaces broken FATs and rejects invalid cluster entries. */\r
+\r
+void set_fat(DOS_FS *fs,unsigned long cluster,unsigned long new);\r
+\r
+/* Changes the value of the CLUSTERth cluster of the FAT of FS to NEW. Special\r
+   values of NEW are -1 (EOF, 0xff8 or 0xfff8) and -2 (bad sector, 0xff7 or\r
+   0xfff7) */\r
+\r
+int bad_cluster(DOS_FS *fs,unsigned long cluster);\r
+\r
+/* Returns a non-zero integer if the CLUSTERth cluster is marked as bad or zero\r
+   otherwise. */\r
+\r
+unsigned long next_cluster(DOS_FS *fs,unsigned long cluster);\r
+\r
+/* Returns the number of the cluster following CLUSTER, or -1 if this is the\r
+   last cluster of the respective cluster chain. CLUSTER must not be a bad\r
+   cluster. */\r
+\r
+loff_t cluster_start(DOS_FS *fs,unsigned long cluster);\r
+\r
+/* Returns the byte offset of CLUSTER, relative to the respective device. */\r
+\r
+void set_owner(DOS_FS *fs,unsigned long cluster,DOS_FILE *owner);\r
+\r
+/* Sets the owner pointer of the respective cluster to OWNER. If OWNER was NULL\r
+   before, it can be set to NULL or any non-NULL value. Otherwise, only NULL is\r
+   accepted as the new value. */\r
+\r
+DOS_FILE *get_owner(DOS_FS *fs,unsigned long cluster);\r
+\r
+/* Returns the owner of the repective cluster or NULL if the cluster has no\r
+   owner. */\r
+\r
+void fix_bad(DOS_FS *fs);\r
+\r
+/* Scans the disk for currently unused bad clusters and marks them as bad. */\r
+\r
+void reclaim_free(DOS_FS *fs);\r
+\r
+/* Marks all allocated, but unused clusters as free. */\r
+\r
+void reclaim_file(DOS_FS *fs);\r
+\r
+/* Scans the FAT for chains of allocated, but unused clusters and creates files\r
+   for them in the root directory. Also tries to fix all inconsistencies (e.g.\r
+   loops, shared clusters, etc.) in the process. */\r
+\r
+unsigned long update_free(DOS_FS *fs);\r
+\r
+/* Updates free cluster count in FSINFO sector. */\r
+\r
+#endif\r
index 9d6b4ff..ea5079c 100644 (file)
-/* file.c  -  Additional file attributes */
-
-/* Written 1993 by Werner Almesberger */
-
-/* FAT32, VFAT, Atari format support, and various fixes additions May 1998
- * by Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> */
-
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <ctype.h>
-//#include <unistd.h>
-
-#define _LINUX_STAT_H          /* hack to avoid inclusion of <linux/stat.h> */
-#define _LINUX_STRING_H_       /* hack to avoid inclusion of <linux/string.h>*/
-#define _LINUX_FS_H             /* hack to avoid inclusion of <linux/fs.h> */
-
-//#include <linux/version.h>
-//#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
-//# define __KERNEL__
-//# include <asm/types.h>
-//# undef __KERNEL__
-//#endif
-
-#include "dosfsck.h"
-#include "msdos_fs.h"
-
-#include "common.h"
-#include "file.h"
-
-
-FDSC *fp_root = NULL;
-
-
-static void put_char(char **p,unsigned char c)
-{
-    if ((c >= ' ' && c < 0x7f) || c >= 0xa0) *(*p)++ = c;
-    else {
-       *(*p)++ = '\\';
-       *(*p)++ = '0'+(c >> 6);
-       *(*p)++ = '0'+((c >> 3) & 7);
-       *(*p)++ = '0'+(c & 7);
-    }
-}
-
-
-char *file_name(unsigned char *fixed)
-{
-    static char path[MSDOS_NAME*4+2];
-    char *p;
-    int i,j;
-
-    p = path;
-    for (i = j =  0; i < 8; i++)
-       if (fixed[i] != ' ') {
-           while (j++ < i) *p++ = ' ';
-           put_char(&p,fixed[i]);
-       }
-    if (strncmp(fixed+8,"   ",3)) {
-       *p++ = '.';
-       for (i = j =  0; i < 3; i++)
-           if (fixed[i+8] != ' ') {
-               while (j++ < i) *p++ = ' ';
-               put_char(&p,fixed[i+8]);
-           }
-    }
-    *p = 0;
-    return path;
-}
-
-
-int file_cvt(unsigned char *name,unsigned char *fixed)
-{
-    unsigned char c;
-    int size,ext,cnt;
-
-    size = 8;
-    ext = 0;
-    while (*name) {
-       c = *name;
-       if (c < ' ' || c > 0x7e || strchr("*?<>|\"/",c)) {
-           printf("Invalid character in name. Use \\ooo for special "
-             "characters.\n");
-           return 0;
-       }
-       if (c == '.') {
-           if (ext) {
-               printf("Duplicate dots in name.\n");
-               return 0;
-           }
-           while (size--) *fixed++ = ' ';
-           size = 3;
-           ext = 1;
-           name++;
-           continue;
-       }
-       if (c == '\\') {
-           c = 0;
-           for (cnt = 3; cnt; cnt--) {
-               if (*name < '0' || *name > '7') {
-                   printf("Invalid octal character.\n");
-                   return 0;
-               }
-               c = c*8+*name++-'0';
-           }
-           if (cnt < 4) {
-               printf("Expected three octal digits.\n");
-               return 0;
-           }
-           name += 3;
-       }
-       if (islower(c)) c = toupper(c);
-       if (size) {
-           *fixed++ = c;
-           size--;
-       }
-       name++;
-    }
-    if (*name || size == 8) return 0;
-    if (!ext) {
-       while (size--) *fixed++ = ' ';
-       size = 3;
-    }
-    while (size--) *fixed++ = ' ';
-    return 1;
-}
-
-
-void file_add(char *path,FD_TYPE type)
-{
-    FDSC **current,*walk;
-    char name[MSDOS_NAME];
-    char *here;
-
-    current = &fp_root;
-    if (*path != '/') die("%s: Absolute path required.",path);
-    path++;
-    while (1) {
-       if ((here = strchr(path,'/'))) *here = 0;
-       if (!file_cvt(path,name)) exit(2);
-       for (walk = *current; walk; walk = walk->next)
-           if (!here && (!strncmp(name,walk->name,MSDOS_NAME) || (type ==
-             fdt_undelete && !strncmp(name+1,walk->name+1,MSDOS_NAME-1))))
-               die("Ambiguous name: \"%s\"",path);
-           else if (here && !strncmp(name,walk->name,MSDOS_NAME)) break;
-       if (!walk) {
-           walk = alloc(sizeof(FDSC));
-           strncpy(walk->name,name,MSDOS_NAME);
-           walk->type = here ? fdt_none : type;
-           walk->first = NULL;
-           walk->next = *current;
-           *current = walk;
-       }
-       current = &walk->first;
-       if (!here) break;
-       *here = '/';
-       path = here+1;
-    }
-}
-
-
-FDSC **file_cd(FDSC **curr,char *fixed)
-{
-    FDSC **walk;
-
-    if (!curr || !*curr) return NULL;
-    for (walk = curr; *walk; walk = &(*walk)->next)
-       if (!strncmp((*walk)->name,fixed,MSDOS_NAME) && (*walk)->first)
-           return &(*walk)->first;
-    return NULL;
-}
-
-
-static FDSC **file_find(FDSC **dir,char *fixed)
-{
-    if (!dir || !*dir) return NULL;
-    if (*(unsigned char *) fixed == DELETED_FLAG) {
-       while (*dir) {
-           if (!strncmp((*dir)->name+1,fixed+1,MSDOS_NAME-1) && !(*dir)->first)
-               return dir;
-           dir = &(*dir)->next;
-       }
-       return NULL;
-    }
-    while (*dir) {
-       if (!strncmp((*dir)->name,fixed,MSDOS_NAME) && !(*dir)->first)
-           return dir;
-       dir = &(*dir)->next;
-    }
-    return NULL;
-}
-
-
-FD_TYPE file_type(FDSC **curr,char *fixed)
-{
-    FDSC **this;
-
-    if ((this = file_find(curr,fixed))) return (*this)->type;
-    return fdt_none;
-}
-
-
-void file_modify(FDSC **curr,char *fixed)
-{
-    FDSC **this,*next;
-
-    if (!(this = file_find(curr,fixed)))
-       die("Internal error: file_find failed");
-    switch ((*this)->type) {
-       case fdt_drop:
-           printf("Dropping %s\n",file_name(fixed));
-           *(unsigned char *) fixed = DELETED_FLAG;
-           break;
-       case fdt_undelete:
-           *fixed = *(*this)->name;
-           printf("Undeleting %s\n",file_name(fixed));
-           break;
-       default:
-           die("Internal error: file_modify");
-    }
-    next = (*this)->next;
-    free(*this);
-    *this = next;
-}
-
-
-static void report_unused(FDSC *this)
-{
-    FDSC *next;
-
-    while (this) {
-       next = this->next;
-       if (this->first) report_unused(this->first);
-       else if (this->type != fdt_none)
-               printf("Warning: did not %s file %s\n",this->type == fdt_drop ?
-                 "drop" : "undelete",file_name(this->name));
-       free(this);
-       this = next;
-    }
-}
-
-
-void file_unused(void)
-{
-    report_unused(fp_root);
-}
-
-/* Local Variables: */
-/* tab-width: 8     */
-/* End:             */
+/* file.c  -  Additional file attributes */\r
+\r
+/* Written 1993 by Werner Almesberger */\r
+\r
+/* FAT32, VFAT, Atari format support, and various fixes additions May 1998\r
+ * by Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> */\r
+\r
+\r
+#include <stdlib.h>\r
+#include <stdio.h>\r
+#include <string.h>\r
+#include <ctype.h>\r
+//#include <unistd.h>\r
+\r
+#define _LINUX_STAT_H          /* hack to avoid inclusion of <linux/stat.h> */\r
+#define _LINUX_STRING_H_       /* hack to avoid inclusion of <linux/string.h>*/\r
+#define _LINUX_FS_H             /* hack to avoid inclusion of <linux/fs.h> */\r
+\r
+//#include <linux/version.h>\r
+//#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)\r
+//# define __KERNEL__\r
+//# include <asm/types.h>\r
+//# undef __KERNEL__\r
+//#endif\r
+\r
+#include "dosfsck.h"\r
+#include "msdos_fs.h"\r
+\r
+#include "common.h"\r
+#include "file.h"\r
+\r
+\r
+FDSC *fp_root = NULL;\r
+\r
+\r
+static void put_char(char **p,unsigned char c)\r
+{\r
+    if ((c >= ' ' && c < 0x7f) || c >= 0xa0) *(*p)++ = c;\r
+    else {\r
+       *(*p)++ = '\\';\r
+       *(*p)++ = '0'+(c >> 6);\r
+       *(*p)++ = '0'+((c >> 3) & 7);\r
+       *(*p)++ = '0'+(c & 7);\r
+    }\r
+}\r
+\r
+\r
+char *file_name(unsigned char *fixed)\r
+{\r
+    static char path[MSDOS_NAME*4+2];\r
+    char *p;\r
+    int i,j;\r
+\r
+    p = path;\r
+    for (i = j =  0; i < 8; i++)\r
+       if (fixed[i] != ' ') {\r
+           while (j++ < i) *p++ = ' ';\r
+           put_char(&p,fixed[i]);\r
+       }\r
+    if (strncmp(fixed+8,"   ",3)) {\r
+       *p++ = '.';\r
+       for (i = j =  0; i < 3; i++)\r
+           if (fixed[i+8] != ' ') {\r
+               while (j++ < i) *p++ = ' ';\r
+               put_char(&p,fixed[i+8]);\r
+           }\r
+    }\r
+    *p = 0;\r
+    return path;\r
+}\r
+\r
+\r
+int file_cvt(unsigned char *name,unsigned char *fixed)\r
+{\r
+    unsigned char c;\r
+    int size,ext,cnt;\r
+\r
+    size = 8;\r
+    ext = 0;\r
+    while (*name) {\r
+       c = *name;\r
+       if (c < ' ' || c > 0x7e || strchr("*?<>|\"/",c)) {\r
+           printf("Invalid character in name. Use \\ooo for special "\r
+             "characters.\n");\r
+           return 0;\r
+       }\r
+       if (c == '.') {\r
+           if (ext) {\r
+               printf("Duplicate dots in name.\n");\r
+               return 0;\r
+           }\r
+           while (size--) *fixed++ = ' ';\r
+           size = 3;\r
+           ext = 1;\r
+           name++;\r
+           continue;\r
+       }\r
+       if (c == '\\') {\r
+           c = 0;\r
+           for (cnt = 3; cnt; cnt--) {\r
+               if (*name < '0' || *name > '7') {\r
+                   printf("Invalid octal character.\n");\r
+                   return 0;\r
+               }\r
+               c = c*8+*name++-'0';\r
+           }\r
+           if (cnt < 4) {\r
+               printf("Expected three octal digits.\n");\r
+               return 0;\r
+           }\r
+           name += 3;\r
+       }\r
+       if (islower(c)) c = toupper(c);\r
+       if (size) {\r
+           *fixed++ = c;\r
+           size--;\r
+       }\r
+       name++;\r
+    }\r
+    if (*name || size == 8) return 0;\r
+    if (!ext) {\r
+       while (size--) *fixed++ = ' ';\r
+       size = 3;\r
+    }\r
+    while (size--) *fixed++ = ' ';\r
+    return 1;\r
+}\r
+\r
+\r
+void file_add(char *path,FD_TYPE type)\r
+{\r
+    FDSC **current,*walk;\r
+    char name[MSDOS_NAME];\r
+    char *here;\r
+\r
+    current = &fp_root;\r
+    if (*path != '/') die("%s: Absolute path required.",path);\r
+    path++;\r
+    while (1) {\r
+       if ((here = strchr(path,'/'))) *here = 0;\r
+       if (!file_cvt(path,name)) exit(2);\r
+       for (walk = *current; walk; walk = walk->next)\r
+           if (!here && (!strncmp(name,walk->name,MSDOS_NAME) || (type ==\r
+             fdt_undelete && !strncmp(name+1,walk->name+1,MSDOS_NAME-1))))\r
+               die("Ambiguous name: \"%s\"",path);\r
+           else if (here && !strncmp(name,walk->name,MSDOS_NAME)) break;\r
+       if (!walk) {\r
+           walk = alloc(sizeof(FDSC));\r
+           strncpy(walk->name,name,MSDOS_NAME);\r
+           walk->type = here ? fdt_none : type;\r
+           walk->first = NULL;\r
+           walk->next = *current;\r
+           *current = walk;\r
+       }\r
+       current = &walk->first;\r
+       if (!here) break;\r
+       *here = '/';\r
+       path = here+1;\r
+    }\r
+}\r
+\r
+\r
+FDSC **file_cd(FDSC **curr,char *fixed)\r
+{\r
+    FDSC **walk;\r
+\r
+    if (!curr || !*curr) return NULL;\r
+    for (walk = curr; *walk; walk = &(*walk)->next)\r
+       if (!strncmp((*walk)->name,fixed,MSDOS_NAME) && (*walk)->first)\r
+           return &(*walk)->first;\r
+    return NULL;\r
+}\r
+\r
+\r
+static FDSC **file_find(FDSC **dir,char *fixed)\r
+{\r
+    if (!dir || !*dir) return NULL;\r
+    if (*(unsigned char *) fixed == DELETED_FLAG) {\r
+       while (*dir) {\r
+           if (!strncmp((*dir)->name+1,fixed+1,MSDOS_NAME-1) && !(*dir)->first)\r
+               return dir;\r
+           dir = &(*dir)->next;\r
+       }\r
+       return NULL;\r
+    }\r
+    while (*dir) {\r
+       if (!strncmp((*dir)->name,fixed,MSDOS_NAME) && !(*dir)->first)\r
+           return dir;\r
+       dir = &(*dir)->next;\r
+    }\r
+    return NULL;\r
+}\r
+\r
+\r
+FD_TYPE file_type(FDSC **curr,char *fixed)\r
+{\r
+    FDSC **this;\r
+\r
+    if ((this = file_find(curr,fixed))) return (*this)->type;\r
+    return fdt_none;\r
+}\r
+\r
+\r
+void file_modify(FDSC **curr,char *fixed)\r
+{\r
+    FDSC **this,*next;\r
+\r
+    if (!(this = file_find(curr,fixed)))\r
+       die("Internal error: file_find failed");\r
+    switch ((*this)->type) {\r
+       case fdt_drop:\r
+           printf("Dropping %s\n",file_name(fixed));\r
+           *(unsigned char *) fixed = DELETED_FLAG;\r
+           break;\r
+       case fdt_undelete:\r
+           *fixed = *(*this)->name;\r
+           printf("Undeleting %s\n",file_name(fixed));\r
+           break;\r
+       default:\r
+           die("Internal error: file_modify");\r
+    }\r
+    next = (*this)->next;\r
+    free(*this);\r
+    *this = next;\r
+}\r
+\r
+\r
+static void report_unused(FDSC *this)\r
+{\r
+    FDSC *next;\r
+\r
+    while (this) {\r
+       next = this->next;\r
+       if (this->first) report_unused(this->first);\r
+       else if (this->type != fdt_none)\r
+               printf("Warning: did not %s file %s\n",this->type == fdt_drop ?\r
+                 "drop" : "undelete",file_name(this->name));\r
+       free(this);\r
+       this = next;\r
+    }\r
+}\r
+\r
+\r
+void file_unused(void)\r
+{\r
+    report_unused(fp_root);\r
+}\r
+\r
+/* Local Variables: */\r
+/* tab-width: 8     */\r
+/* End:             */\r
index d7f1386..f9c3571 100644 (file)
@@ -1,55 +1,55 @@
-/* file.h  -  Additional file attributes */
-
-/* Written 1993 by Werner Almesberger */
-
-
-#ifndef _FILE_H
-#define _FILE_H
-
-typedef enum { fdt_none,fdt_drop,fdt_undelete } FD_TYPE;
-
-typedef struct _fptr {
-    char name[MSDOS_NAME];
-    FD_TYPE type;
-    struct _fptr *first; /* first entry */
-    struct _fptr *next; /* next file in directory */
-} FDSC;
-
-
-extern FDSC *fp_root;
-
-
-char *file_name(unsigned char *fixed);
-
-/* Returns a pointer to a pretty-printed representation of a fixed MS-DOS file
-   name. */
-
-int file_cvt(unsigned char *name,unsigned char *fixed);
-
-/* Converts a pretty-printed file name to the fixed MS-DOS format. Returns a
-   non-zero integer on success, zero on failure. */
-
-void file_add(char *path,FD_TYPE type);
-
-/* Define special attributes for a path. TYPE can be either FDT_DROP or
-   FDT_UNDELETE. */
-
-FDSC **file_cd(FDSC **curr,char *fixed);
-
-/* Returns a pointer to the directory descriptor of the subdirectory FIXED of
-   CURR, or NULL if no such subdirectory exists. */
-
-FD_TYPE file_type(FDSC **curr,char *fixed);
-
-/* Returns the attribute of the file FIXED in directory CURR or FDT_NONE if no
-   such file exists or if CURR is NULL. */
-
-void file_modify(FDSC **curr,char *fixed);
-
-/* Performs the necessary operation on the entry of CURR that is named FIXED. */
-
-void file_unused(void);
-
-/* Displays warnings for all unused file attributes. */
-
-#endif
+/* file.h  -  Additional file attributes */\r
+\r
+/* Written 1993 by Werner Almesberger */\r
+\r
+\r
+#ifndef _FILE_H\r
+#define _FILE_H\r
+\r
+typedef enum { fdt_none,fdt_drop,fdt_undelete } FD_TYPE;\r
+\r
+typedef struct _fptr {\r
+    char name[MSDOS_NAME];\r
+    FD_TYPE type;\r
+    struct _fptr *first; /* first entry */\r
+    struct _fptr *next; /* next file in directory */\r
+} FDSC;\r
+\r
+\r
+extern FDSC *fp_root;\r
+\r
+\r
+char *file_name(unsigned char *fixed);\r
+\r
+/* Returns a pointer to a pretty-printed representation of a fixed MS-DOS file\r
+   name. */\r
+\r
+int file_cvt(unsigned char *name,unsigned char *fixed);\r
+\r
+/* Converts a pretty-printed file name to the fixed MS-DOS format. Returns a\r
+   non-zero integer on success, zero on failure. */\r
+\r
+void file_add(char *path,FD_TYPE type);\r
+\r
+/* Define special attributes for a path. TYPE can be either FDT_DROP or\r
+   FDT_UNDELETE. */\r
+\r
+FDSC **file_cd(FDSC **curr,char *fixed);\r
+\r
+/* Returns a pointer to the directory descriptor of the subdirectory FIXED of\r
+   CURR, or NULL if no such subdirectory exists. */\r
+\r
+FD_TYPE file_type(FDSC **curr,char *fixed);\r
+\r
+/* Returns the attribute of the file FIXED in directory CURR or FDT_NONE if no\r
+   such file exists or if CURR is NULL. */\r
+\r
+void file_modify(FDSC **curr,char *fixed);\r
+\r
+/* Performs the necessary operation on the entry of CURR that is named FIXED. */\r
+\r
+void file_unused(void);\r
+\r
+/* Displays warnings for all unused file attributes. */\r
+\r
+#endif\r
index 0783623..0a37f95 100644 (file)
@@ -1,63 +1,63 @@
-/*
- * $Id$
- * This is an unpublished work copyright (c) 1998 HELIOS Software GmbH
- * 30827 Garbsen, Germany
- */
-
-
-#include <stdio.h>
-#include <string.h>
-#ifdef HAS_UNISTD
-# include <unistd.h>
-#endif
-
-char *optarg;
-int optind = 1;
-int opterr = 1;
-int optopt;
-static int subopt;
-static int suboptind = 1;
-
-int getopt(int argc, char *const argv[], const char * optstring)
-{
-       char *curopt;
-       char *p;
-       int cursubopt;
-
-       if (suboptind == optind-1 && argv[suboptind][subopt] != '\0') {
-               curopt = (char *)argv[suboptind];
-       } else {
-               curopt = (char *)argv[optind];
-               if (curopt == NULL || curopt[0] != '-' || strcmp(curopt, "-") == 0)
-                       return -1;
-               suboptind = optind;
-               subopt = 1;
-               optind++;
-               if (strcmp(curopt, "--") == 0)
-                       return -1;
-       }
-       cursubopt = subopt++;
-       if ((p = strchr(optstring, curopt[cursubopt])) == NULL) {
-               optopt = curopt[cursubopt];
-               if (opterr)
-                       fprintf(stderr, "%s: illegal option -- %c\n", argv[0], optopt);
-               return '?';
-       }
-       if (p[1] == ':') {
-               if (curopt[cursubopt+1] != '\0') {
-                       optarg = curopt+cursubopt+1;
-                       suboptind++;
-                       return p[0];
-               }
-               if (argv[optind] == NULL) {
-                       optopt = p[0];
-                       if (opterr)
-                               fprintf(stderr, "%s: option requires an argument -- %c\n", argv[0], optopt);
-                       if (*optstring == ':')
-                               return ':';
-                       return '?';
-               }
-               optarg = argv[optind++];
-       }
-       return p[0];
-}
+/*\r
+ * $Id$\r
+ * This is an unpublished work copyright (c) 1998 HELIOS Software GmbH\r
+ * 30827 Garbsen, Germany\r
+ */\r
+\r
+\r
+#include <stdio.h>\r
+#include <string.h>\r
+#ifdef HAS_UNISTD\r
+# include <unistd.h>\r
+#endif\r
+\r
+char *optarg;\r
+int optind = 1;\r
+int opterr = 1;\r
+int optopt;\r
+static int subopt;\r
+static int suboptind = 1;\r
+\r
+int getopt(int argc, char *const argv[], const char * optstring)\r
+{\r
+       char *curopt;\r
+       char *p;\r
+       int cursubopt;\r
+\r
+       if (suboptind == optind-1 && argv[suboptind][subopt] != '\0') {\r
+               curopt = (char *)argv[suboptind];\r
+       } else {\r
+               curopt = (char *)argv[optind];\r
+               if (curopt == NULL || curopt[0] != '-' || strcmp(curopt, "-") == 0)\r
+                       return -1;\r
+               suboptind = optind;\r
+               subopt = 1;\r
+               optind++;\r
+               if (strcmp(curopt, "--") == 0)\r
+                       return -1;\r
+       }\r
+       cursubopt = subopt++;\r
+       if ((p = strchr(optstring, curopt[cursubopt])) == NULL) {\r
+               optopt = curopt[cursubopt];\r
+               if (opterr)\r
+                       fprintf(stderr, "%s: illegal option -- %c\n", argv[0], optopt);\r
+               return '?';\r
+       }\r
+       if (p[1] == ':') {\r
+               if (curopt[cursubopt+1] != '\0') {\r
+                       optarg = curopt+cursubopt+1;\r
+                       suboptind++;\r
+                       return p[0];\r
+               }\r
+               if (argv[optind] == NULL) {\r
+                       optopt = p[0];\r
+                       if (opterr)\r
+                               fprintf(stderr, "%s: option requires an argument -- %c\n", argv[0], optopt);\r
+                       if (*optstring == ':')\r
+                               return ':';\r
+                       return '?';\r
+               }\r
+               optarg = argv[optind++];\r
+       }\r
+       return p[0];\r
+}\r
index 894a714..e4e231f 100644 (file)
@@ -1,28 +1,28 @@
-/* io.c  -  Virtual disk input/output */
-
-/* Written 1993 by Werner Almesberger */
-
-/*
- * Thu Feb 26 01:15:36 CET 1998: Martin Schulze <joey@infodrom.north.de>
- *     Fixed nasty bug that caused every file with a name like
- *     xxxxxxxx.xxx to be treated as bad name that needed to be fixed.
- */
-
-/* FAT32, VFAT, Atari format support, and various fixes additions May 1998
- * by Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-//#include <unistd.h>
-#include <sys/stat.h>
-//#include <sys/ioctl.h>
-#include <errno.h>
+/* io.c  -  Virtual disk input/output */\r
+\r
+/* Written 1993 by Werner Almesberger */\r
+\r
+/*\r
+ * Thu Feb 26 01:15:36 CET 1998: Martin Schulze <joey@infodrom.north.de>\r
+ *     Fixed nasty bug that caused every file with a name like\r
+ *     xxxxxxxx.xxx to be treated as bad name that needed to be fixed.\r
+ */\r
+\r
+/* FAT32, VFAT, Atari format support, and various fixes additions May 1998\r
+ * by Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> */\r
+\r
+#include <stdlib.h>\r
+#include <stdio.h>\r
+#include <string.h>\r
+//#include <unistd.h>\r
+#include <sys/stat.h>\r
+//#include <sys/ioctl.h>\r
+#include <errno.h>\r
 #include <fcntl.h>\r
-#include <assert.h>
-//#include <linux/fd.h>
-
-
+#include <assert.h>\r
+//#include <linux/fd.h>\r
+\r
+\r
 #ifdef _WIN32\r
 #define _WIN32_WINNT   0x0400\r
 #include <windows.h>\r
 #define inline\r
 #define __attribute__(x)\r
 #define BLOCK_SIZE             512\r
-#endif
-
-
-#include "dosfsck.h"
-#include "common.h"
-#include "io.h"
-
-
-typedef struct _change {
-    void *data;
-    loff_t pos;
-    int size;
-    struct _change *next;
-} CHANGE;
-
-
-static CHANGE *changes,*last;
-static int fd,did_change = 0;
-
-unsigned device_no;
-
-static int WIN32open(const char *path, int oflag, ...);
-#define open   WIN32open
+#endif\r
+\r
+\r
+#include "dosfsck.h"\r
+#include "common.h"\r
+#include "io.h"\r
+\r
+\r
+typedef struct _change {\r
+    void *data;\r
+    loff_t pos;\r
+    int size;\r
+    struct _change *next;\r
+} CHANGE;\r
+\r
+\r
+static CHANGE *changes,*last;\r
+static int fd,did_change = 0;\r
+\r
+unsigned device_no;\r
+\r
+static int WIN32open(const char *path, int oflag, ...);\r
+#define open   WIN32open\r
 static int WIN32close(int fd);\r
-#define close  WIN32close
+#define close  WIN32close\r
 static int WIN32read(int fd, void *buf, unsigned int len);\r
-#define read   WIN32read
+#define read   WIN32read\r
 static int WIN32write(int fd, void *buf, unsigned int len);\r
-#define write  WIN32write
+#define write  WIN32write\r
 static loff_t WIN32llseek(int fd, loff_t offset, int whence);\r
 #ifdef llseek\r
 #undef llseek\r
 #endif\r
 #define llseek WIN32llseek\r
-
-static int is_device = 0;
-
-void fs_open(char *path,int rw)
-{
+\r
+static int is_device = 0;\r
+\r
+void fs_open(char *path,int rw)\r
+{\r
 #ifdef _WIN32\r
   static char dev_buf[] = "\\\\.\\X:";\r
-#else
-    struct stat stbuf;
-#endif
-
+#else\r
+    struct stat stbuf;\r
+#endif\r
+\r
   if (path[1] == ':' && path[2] == '\0') {\r
          dev_buf[4] = path[0];\r
          path = dev_buf;\r
 //       is_device = 1;\r
   }\r
-
-    if ((fd = open(path,rw ? O_RDWR : O_RDONLY)) < 0)
-       pdie("open %s",path);
-    changes = last = NULL;
-    did_change = 0;
-
-#if 0
-    if (fstat(fd,&stbuf) < 0)
-       pdie("fstat %s",path);
-    device_no = S_ISBLK(stbuf.st_mode) ? (stbuf.st_rdev >> 8) & 0xff : 0;
-#endif
-}
-
-
-void fs_read(loff_t pos,int size,void *data)
-{
-    CHANGE *walk;
+\r
+    if ((fd = open(path,rw ? O_RDWR : O_RDONLY)) < 0)\r
+       pdie("open %s",path);\r
+    changes = last = NULL;\r
+    did_change = 0;\r
+\r
+#if 0\r
+    if (fstat(fd,&stbuf) < 0)\r
+       pdie("fstat %s",path);\r
+    device_no = S_ISBLK(stbuf.st_mode) ? (stbuf.st_rdev >> 8) & 0xff : 0;\r
+#endif\r
+}\r
+\r
+\r
+void fs_read(loff_t pos,int size,void *data)\r
+{\r
+    CHANGE *walk;\r
     int got;\r
 #if 1 // TMN\r
        const size_t readsize_aligned = (size % 512) ? (size + (512 - (size % 512))) : size;        // TMN:\r
@@ -115,123 +115,123 @@ void fs_read(loff_t pos,int size,void *data)
      if ((got = read(fd,tmpBuf,readsize_aligned)) < 0) pdie("Read %d bytes at %lld",size,pos);\r
 #endif\r
        assert(got >= size);\r
-       got = size;
+       got = size;\r
        assert(seek_delta + size <= readsize);\r
        memcpy(data, tmpBuf+seek_delta, size);\r
        free(tmpBuf);\r
-#else // TMN:
-    if (llseek(fd,pos,0) != pos) pdie("Seek to %lld",pos);
+#else // TMN:\r
+    if (llseek(fd,pos,0) != pos) pdie("Seek to %lld",pos);\r
     if ((got = read(fd,data,size)) < 0) pdie("Read %d bytes at %lld",size,pos);\r
-#endif // TMN:
-    if (got != size) die("Got %d bytes instead of %d at %lld",got,size,pos);
-    for (walk = changes; walk; walk = walk->next) {
-       if (walk->pos < pos+size && walk->pos+walk->size > pos) {
-           if (walk->pos < pos)
-               memcpy(data,(char *) walk->data+pos-walk->pos,min((size_t)size,
-                 (size_t)(walk->size-pos+walk->pos)));
-           else memcpy((char *) data+walk->pos-pos,walk->data,min((size_t)walk->size,
-                 (size_t)(size+pos-walk->pos)));
-       }
-    }
-}
-
-
-int fs_test(loff_t pos,int size)
-{
-    void *scratch;
-    int okay;
-
-#if 1 // TMN
-       const size_t readsize_aligned = (size % 512) ? (size + (512 - (size % 512))) : size;        // TMN:
-       const loff_t seekpos_aligned = pos - (pos % 512);                   // TMN:
-       const size_t seek_delta = (size_t)(pos - seekpos_aligned);          // TMN:
-       const size_t readsize = (size_t)(pos - seekpos_aligned) + readsize_aligned; // TMN: 
-    scratch = alloc(readsize_aligned);
-    if (llseek(fd,seekpos_aligned,0) != seekpos_aligned) pdie("Seek to %lld",pos);
-    okay = read(fd,scratch,readsize_aligned) == (int)readsize_aligned;
-    free(scratch);
-#else // TMN:
-    if (llseek(fd,pos,0) != pos) pdie("Seek to %lld",pos);
-    scratch = alloc(size);
-    okay = read(fd,scratch,size) == size;
-    free(scratch);
-#endif // TMN:
-    return okay;
-}
-
-
-void fs_write(loff_t pos,int size,void *data)
-{
-    CHANGE *new;
-    int did;
-
-    if (write_immed) {
-       did_change = 1;
-       if (llseek(fd,pos,0) != pos) pdie("Seek to %lld",pos);
-       if ((did = write(fd,data,size)) == size) return;
-       if (did < 0) pdie("Write %d bytes at %lld",size,pos);
-       die("Wrote %d bytes instead of %d at %lld",did,size,pos);
-    }
-    new = alloc(sizeof(CHANGE));
-    new->pos = pos;
-    memcpy(new->data = alloc(new->size = size),data,size);
-    new->next = NULL;
-    if (last) last->next = new;
-    else changes = new;
-    last = new;
-}
-
-
-static void fs_flush(void)
-{
-    CHANGE *this;
-    int size;
-
-    while (changes) {
-       this = changes;
-       changes = changes->next;
-       if (llseek(fd,this->pos,0) != this->pos)
-           fprintf(stderr,"Seek to %lld failed: %s\n  Did not write %d bytes.\n",
-             (__int64)this->pos,strerror(errno),this->size);
-       else if ((size = write(fd,this->data,this->size)) < 0)
-               fprintf(stderr,"Writing %d bytes at %lld failed: %s\n",this->size,
-                 (__int64)this->pos,strerror(errno));
-           else if (size != this->size)
-                   fprintf(stderr,"Wrote %d bytes instead of %d bytes at %lld."
-                     "\n",size,this->size,(__int64)this->pos);
-       free(this->data);
-       free(this);
-    }
-}
-
-
-int fs_close(int write)
-{
-    CHANGE *next;
-    int changed;
-
-    changed = !!changes;
-    if (write) fs_flush();
-    else while (changes) {
-           next = changes->next;
-           free(changes->data);
-           free(changes);
-           changes = next;
-       }
-    if (close(fd) < 0) pdie("closing file system");
-    return changed || did_change;
-}
-
-
-int fs_changed(void)
-{
-    return !!changes || did_change;
-}
-
-/* Local Variables: */
-/* tab-width: 8     */
-/* End:             */
-
+#endif // TMN:\r
+    if (got != size) die("Got %d bytes instead of %d at %lld",got,size,pos);\r
+    for (walk = changes; walk; walk = walk->next) {\r
+       if (walk->pos < pos+size && walk->pos+walk->size > pos) {\r
+           if (walk->pos < pos)\r
+               memcpy(data,(char *) walk->data+pos-walk->pos,min((size_t)size,\r
+                 (size_t)(walk->size-pos+walk->pos)));\r
+           else memcpy((char *) data+walk->pos-pos,walk->data,min((size_t)walk->size,\r
+                 (size_t)(size+pos-walk->pos)));\r
+       }\r
+    }\r
+}\r
+\r
+\r
+int fs_test(loff_t pos,int size)\r
+{\r
+    void *scratch;\r
+    int okay;\r
+\r
+#if 1 // TMN\r
+       const size_t readsize_aligned = (size % 512) ? (size + (512 - (size % 512))) : size;        // TMN:\r
+       const loff_t seekpos_aligned = pos - (pos % 512);                   // TMN:\r
+       const size_t seek_delta = (size_t)(pos - seekpos_aligned);          // TMN:\r
+       const size_t readsize = (size_t)(pos - seekpos_aligned) + readsize_aligned; // TMN: \r
+    scratch = alloc(readsize_aligned);\r
+    if (llseek(fd,seekpos_aligned,0) != seekpos_aligned) pdie("Seek to %lld",pos);\r
+    okay = read(fd,scratch,readsize_aligned) == (int)readsize_aligned;\r
+    free(scratch);\r
+#else // TMN:\r
+    if (llseek(fd,pos,0) != pos) pdie("Seek to %lld",pos);\r
+    scratch = alloc(size);\r
+    okay = read(fd,scratch,size) == size;\r
+    free(scratch);\r
+#endif // TMN:\r
+    return okay;\r
+}\r
+\r
+\r
+void fs_write(loff_t pos,int size,void *data)\r
+{\r
+    CHANGE *new;\r
+    int did;\r
+\r
+    if (write_immed) {\r
+       did_change = 1;\r
+       if (llseek(fd,pos,0) != pos) pdie("Seek to %lld",pos);\r
+       if ((did = write(fd,data,size)) == size) return;\r
+       if (did < 0) pdie("Write %d bytes at %lld",size,pos);\r
+       die("Wrote %d bytes instead of %d at %lld",did,size,pos);\r
+    }\r
+    new = alloc(sizeof(CHANGE));\r
+    new->pos = pos;\r
+    memcpy(new->data = alloc(new->size = size),data,size);\r
+    new->next = NULL;\r
+    if (last) last->next = new;\r
+    else changes = new;\r
+    last = new;\r
+}\r
+\r
+\r
+static void fs_flush(void)\r
+{\r
+    CHANGE *this;\r
+    int size;\r
+\r
+    while (changes) {\r
+       this = changes;\r
+       changes = changes->next;\r
+       if (llseek(fd,this->pos,0) != this->pos)\r
+           fprintf(stderr,"Seek to %lld failed: %s\n  Did not write %d bytes.\n",\r
+             (__int64)this->pos,strerror(errno),this->size);\r
+       else if ((size = write(fd,this->data,this->size)) < 0)\r
+               fprintf(stderr,"Writing %d bytes at %lld failed: %s\n",this->size,\r
+                 (__int64)this->pos,strerror(errno));\r
+           else if (size != this->size)\r
+                   fprintf(stderr,"Wrote %d bytes instead of %d bytes at %lld."\r
+                     "\n",size,this->size,(__int64)this->pos);\r
+       free(this->data);\r
+       free(this);\r
+    }\r
+}\r
+\r
+\r
+int fs_close(int write)\r
+{\r
+    CHANGE *next;\r
+    int changed;\r
+\r
+    changed = !!changes;\r
+    if (write) fs_flush();\r
+    else while (changes) {\r
+           next = changes->next;\r
+           free(changes->data);\r
+           free(changes);\r
+           changes = next;\r
+       }\r
+    if (close(fd) < 0) pdie("closing file system");\r
+    return changed || did_change;\r
+}\r
+\r
+\r
+int fs_changed(void)\r
+{\r
+    return !!changes || did_change;\r
+}\r
+\r
+/* Local Variables: */\r
+/* tab-width: 8     */\r
+/* End:             */\r
+\r
 \r
 #define O_SHORT_LIVED   _O_SHORT_LIVED\r
 //#define O_ACCMODE       3\r
index cdf3c58..a9cc75d 100644 (file)
@@ -1,54 +1,54 @@
-/* io.h  -  Virtual disk input/output */
-
-/* Written 1993 by Werner Almesberger */
-
-/* FAT32, VFAT, Atari format support, and various fixes additions May 1998
- * by Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> */
-
-
-#ifndef _IO_H
-#define _IO_H
-
-//#include <sys/types.h> /* for loff_t */
-#include "dosfsck.h"
-
-/* In earlier versions, an own llseek() was used, but glibc lseek() is
- * sufficient (or even better :) for 64 bit offsets in the meantime */
-#define llseek lseek
-
-void fs_open(char *path,int rw);
-
-/* Opens the file system PATH. If RW is zero, the file system is opened
-   read-only, otherwise, it is opened read-write. */
-
-void fs_read(loff_t pos,int size,void *data);
-
-/* Reads SIZE bytes starting at POS into DATA. Performs all applicable
-   changes. */
-
-int fs_test(loff_t pos,int size);
-
-/* Returns a non-zero integer if SIZE bytes starting at POS can be read without
-   errors. Otherwise, it returns zero. */
-
-void fs_write(loff_t pos,int size,void *data);
-
-/* If write_immed is non-zero, SIZE bytes are written from DATA to the disk,
-   starting at POS. If write_immed is zero, the change is added to a list in
-   memory. */
-
-int fs_close(int write);
-
-/* Closes the file system, performs all pending changes if WRITE is non-zero
-   and removes the list of changes. Returns a non-zero integer if the file
-   system has been changed since the last fs_open, zero otherwise. */
-
-int fs_changed(void);
-
-/* Determines whether the file system has changed. See fs_close. */
-
-extern unsigned device_no;
-
-/* Major number of device (0 if file) and size (in 512 byte sectors) */
-
-#endif
+/* io.h  -  Virtual disk input/output */\r
+\r
+/* Written 1993 by Werner Almesberger */\r
+\r
+/* FAT32, VFAT, Atari format support, and various fixes additions May 1998\r
+ * by Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> */\r
+\r
+\r
+#ifndef _IO_H\r
+#define _IO_H\r
+\r
+//#include <sys/types.h> /* for loff_t */\r
+#include "dosfsck.h"\r
+\r
+/* In earlier versions, an own llseek() was used, but glibc lseek() is\r
+ * sufficient (or even better :) for 64 bit offsets in the meantime */\r
+#define llseek lseek\r
+\r
+void fs_open(char *path,int rw);\r
+\r
+/* Opens the file system PATH. If RW is zero, the file system is opened\r
+   read-only, otherwise, it is opened read-write. */\r
+\r
+void fs_read(loff_t pos,int size,void *data);\r
+\r
+/* Reads SIZE bytes starting at POS into DATA. Performs all applicable\r
+   changes. */\r
+\r
+int fs_test(loff_t pos,int size);\r
+\r
+/* Returns a non-zero integer if SIZE bytes starting at POS can be read without\r
+   errors. Otherwise, it returns zero. */\r
+\r
+void fs_write(loff_t pos,int size,void *data);\r
+\r
+/* If write_immed is non-zero, SIZE bytes are written from DATA to the disk,\r
+   starting at POS. If write_immed is zero, the change is added to a list in\r
+   memory. */\r
+\r
+int fs_close(int write);\r
+\r
+/* Closes the file system, performs all pending changes if WRITE is non-zero\r
+   and removes the list of changes. Returns a non-zero integer if the file\r
+   system has been changed since the last fs_open, zero otherwise. */\r
+\r
+int fs_changed(void);\r
+\r
+/* Determines whether the file system has changed. See fs_close. */\r
+\r
+extern unsigned device_no;\r
+\r
+/* Major number of device (0 if file) and size (in 512 byte sectors) */\r
+\r
+#endif\r
index 0c5c92c..1af73ed 100644 (file)
-/* lfn.c  -  Functions for handling VFAT long filenames */
-
-/* Written 1998 by Roman Hodek */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <limits.h>
-#include <time.h>
-
-#include "common.h"
-#include "io.h"
-#include "dosfsck.h"
-#include "lfn.h"
-#include "file.h"
-
-typedef struct {
-       __u8    id;             /* sequence number for slot */
-       __u8    name0_4[10];    /* first 5 characters in name */
-       __u8    attr;           /* attribute byte */
-       __u8    reserved;       /* always 0 */
-       __u8    alias_checksum; /* checksum for 8.3 alias */
-       __u8    name5_10[12];   /* 6 more characters in name */
-       __u16   start;          /* starting cluster number, 0 in long slots */
-       __u8    name11_12[4];   /* last 2 characters in name */
-} LFN_ENT;
-
-#define LFN_ID_START   0x40
-#define LFN_ID_SLOTMASK        0x1f
-
-#define CHARS_PER_LFN  13
-
-/* These modul-global vars represent the state of the LFN parser */
-unsigned char *lfn_unicode = NULL;
-unsigned char lfn_checksum;
-int lfn_slot = -1;
-loff_t *lfn_offsets = NULL;
-int lfn_parts = 0;
-
-static unsigned char fat_uni2esc[64] = {
-    '0', '1', '2', '3', '4', '5', '6', '7',
-    '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
-    'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
-    'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
-    'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
-    'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
-    'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
-    'u', 'v', 'w', 'x', 'y', 'z', '+', '-'
-};
-
-/* This defines which unicode chars are directly convertable to ISO-8859-1 */
-#define UNICODE_CONVERTABLE(cl,ch)     (ch == 0 && (cl < 0x80 || cl >= 0xa0))
-
-/* for maxlen param */
-#define UNTIL_0                INT_MAX
-
+/* lfn.c  -  Functions for handling VFAT long filenames */\r
+\r
+/* Written 1998 by Roman Hodek */\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include <limits.h>\r
+#include <time.h>\r
+\r
+#include "common.h"\r
+#include "io.h"\r
+#include "dosfsck.h"\r
+#include "lfn.h"\r
+#include "file.h"\r
+\r
+typedef struct {\r
+       __u8    id;             /* sequence number for slot */\r
+       __u8    name0_4[10];    /* first 5 characters in name */\r
+       __u8    attr;           /* attribute byte */\r
+       __u8    reserved;       /* always 0 */\r
+       __u8    alias_checksum; /* checksum for 8.3 alias */\r
+       __u8    name5_10[12];   /* 6 more characters in name */\r
+       __u16   start;          /* starting cluster number, 0 in long slots */\r
+       __u8    name11_12[4];   /* last 2 characters in name */\r
+} LFN_ENT;\r
+\r
+#define LFN_ID_START   0x40\r
+#define LFN_ID_SLOTMASK        0x1f\r
+\r
+#define CHARS_PER_LFN  13\r
+\r
+/* These modul-global vars represent the state of the LFN parser */\r
+unsigned char *lfn_unicode = NULL;\r
+unsigned char lfn_checksum;\r
+int lfn_slot = -1;\r
+loff_t *lfn_offsets = NULL;\r
+int lfn_parts = 0;\r
+\r
+static unsigned char fat_uni2esc[64] = {\r
+    '0', '1', '2', '3', '4', '5', '6', '7',\r
+    '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',\r
+    'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',\r
+    'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',\r
+    'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',\r
+    'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',\r
+    'm', 'n', 'o', 'p', 'q', 'r', 's', 't',\r
+    'u', 'v', 'w', 'x', 'y', 'z', '+', '-'\r
+};\r
+\r
+/* This defines which unicode chars are directly convertable to ISO-8859-1 */\r
+#define UNICODE_CONVERTABLE(cl,ch)     (ch == 0 && (cl < 0x80 || cl >= 0xa0))\r
+\r
+/* for maxlen param */\r
+#define UNTIL_0                INT_MAX\r
+\r
 static void copy_lfn_part( char *dst, LFN_ENT *lfn );\r
 static char *cnv_unicode( const unsigned char *uni, int maxlen, int use_q );\r
 \r
 /* Convert name part in 'lfn' from unicode to ASCII */\r
-static __inline char* CNV_THIS_PART(LFN_ENT *lfn)
-{                                                      \
-       char __part_uni[CHARS_PER_LFN*2];
-       copy_lfn_part( __part_uni, lfn );
-       cnv_unicode( __part_uni, CHARS_PER_LFN, 0 );
-}
-    
-/* Convert name parts collected so far (from previous slots) from unicode to
- * ASCII */
-#define CNV_PARTS_SO_FAR()                                     \
-       (cnv_unicode( lfn_unicode+(lfn_slot*CHARS_PER_LFN*2),   \
-                     lfn_parts*CHARS_PER_LFN, 0 ))
-
-/* This function converts an unicode string to a normal ASCII string, assuming
- * ISO-8859-1 charset. Characters not in 8859-1 are converted to the same
- * escape notation as used by the kernel, i.e. the uuencode-like ":xxx" */
-static char *cnv_unicode( const unsigned char *uni, int maxlen, int use_q )
-{
-    const unsigned char *up;
-    unsigned char *out, *cp;
-    int len, val;
-    
-    for( len = 0, up = uni; (up-uni)/2 < maxlen && (up[0] || up[1]); up += 2 ){
-       if (UNICODE_CONVERTABLE(up[0],up[1]))
-           ++len;
-       else
-           len += 4;
-    }
-    cp = out = use_q ? qalloc( &mem_queue, len+1 ) : alloc( len+1 );
-
-    for( up = uni; (up-uni)/2 < maxlen && (up[0] || up[1]); up += 2 ) {
-       if (UNICODE_CONVERTABLE(up[0],up[1]))
-           *cp++ = up[0];
-       else {
-           /* here the same escape notation is used as in the Linux kernel */
-           *cp++ = ':';
-           val = (up[1] << 8) + up[0];
-           cp[2] = fat_uni2esc[val & 0x3f];
-           val >>= 6;
-           cp[1] = fat_uni2esc[val & 0x3f];
-           val >>= 6;
-           cp[0] = fat_uni2esc[val & 0x3f];
-           cp += 3;
-       }
-    }
-    *cp = 0;
-
-    return( out );
-}
-
-
-static void copy_lfn_part( char *dst, LFN_ENT *lfn )
-{
-    memcpy( dst,    lfn->name0_4,   10 );
-    memcpy( dst+10, lfn->name5_10,  12 );
-    memcpy( dst+22, lfn->name11_12, 4 );
-}
-
-
-static void clear_lfn_slots( int start, int end )
-{
-    int i;
-    LFN_ENT empty;
-
-    /* New dir entry is zeroed except first byte, which is set to 0xe5.
-     * This is to avoid that some FAT-reading OSes (not Linux! ;) stop reading
-     * a directory at the first zero entry...
-     */
-    memset( &empty, 0, sizeof(empty) );
-    empty.id = DELETED_FLAG;
-    
-    for( i = start; i <= end; ++i ) {
-       fs_write( lfn_offsets[i], sizeof(LFN_ENT), &empty );
-    }
-}
-
-void lfn_reset( void )
-{
-    if (lfn_unicode)
-       free( lfn_unicode );
-    lfn_unicode = NULL;
-    if (lfn_offsets)
-       free( lfn_offsets );
-    lfn_offsets = NULL;
-    lfn_slot = -1;
-}
-
-
-/* This function is only called with de->attr == VFAT_LN_ATTR. It stores part
- * of the long name. */
-void lfn_add_slot( DIR_ENT *de, loff_t dir_offset )
-{
-    LFN_ENT *lfn = (LFN_ENT *)de;
-    unsigned offset;
-
-    if (de->attr != VFAT_LN_ATTR)
-       die("lfn_add_slot called with non-LFN directory entry");
-
-    if (lfn->id & LFN_ID_START) {
-       if (lfn_slot != -1) {
-           int can_clear = 0;
-           /* There is already a LFN "in progess", so it is an error that a
-            * new start entry is here. */
-           /* Causes: 1) if slot# == expected: start bit set mysteriously, 2)
-            *         old LFN overwritten by new one */
-           /* Fixes: 1) delete previous LFN 2) if slot# == expected and
-            *        checksum ok: clear start bit */
-           /* XXX: Should delay that until next LFN known (then can better
-            * display the name) */
-           printf( "A new long file name starts within an old one.\n" );
-           if ((lfn->id & LFN_ID_SLOTMASK) == lfn_slot &&
-               lfn->alias_checksum == lfn_checksum) {
-               char *part1 = CNV_THIS_PART(lfn);
-               char *part2 = CNV_PARTS_SO_FAR();
-               printf( "  It could be that the LFN start bit is wrong here\n"
-                       "  if \"%s\" seems to match \"%s\".\n", part1, part2 );
-               free( part1 );
-               free( part2 );
-               can_clear = 1;
-           }
-           if (interactive) {
-               printf( "1: Delete previous LFN\n2: Leave it as it is.\n" );
-               if (can_clear)
-                   printf( "3: Clear start bit and concatenate LFNs\n" );
-           }
-           else printf( "  Not auto-correcting this.\n" );
-           if (interactive) {
-               switch( get_key( can_clear ? "123" : "12", "?" )) {
-                 case '1':
-                   clear_lfn_slots( 0, lfn_parts-1 );
-                   lfn_reset();
-                   break;
-                 case '2':
-                   break;
-                 case '3':
-                   lfn->id &= ~LFN_ID_START;
-                   fs_write( dir_offset+offsetof(LFN_ENT,id),
-                             sizeof(lfn->id), &lfn->id );
-                   break;
-               }
-           }
-       }
-       lfn_slot = lfn->id & LFN_ID_SLOTMASK;
-       lfn_checksum = lfn->alias_checksum;
-       lfn_unicode = alloc( (lfn_slot*CHARS_PER_LFN+1)*2 );
-       lfn_offsets = alloc( lfn_slot*sizeof(loff_t) );
-       lfn_parts = 0;
-    }
-    else if (lfn_slot == -1) {
-       /* No LFN in progress, but slot found; start bit missing */
-       /* Causes: 1) start bit got lost, 2) Previous slot with start bit got
-        *         lost */
-       /* Fixes: 1) delete LFN, 2) set start bit */
-       char *part = CNV_THIS_PART(lfn);
-       printf( "Long filename fragment \"%s\" found outside a LFN "
-               "sequence.\n  (Maybe the start bit is missing on the "
-               "last fragment)\n", part );
-       if (interactive) {
-           printf( "1: Delete fragment\n2: Leave it as it is.\n"
-                   "3: Set start bit\n" );
-       }
-       else printf( "  Not auto-correcting this.\n" );
-       if (interactive) {
-           switch( get_key( "123", "?" )) {
-             case '1':
-               if (!lfn_offsets)
-                   lfn_offsets = alloc( sizeof(loff_t) );
-               lfn_offsets[0] = dir_offset;
-               clear_lfn_slots( 0, 0 );
-               lfn_reset();
-               return;
-             case '2':
-               lfn_reset();
-               return;
-             case '3':
-               lfn->id |= LFN_ID_START;
-               fs_write( dir_offset+offsetof(LFN_ENT,id),
-                         sizeof(lfn->id), &lfn->id );
-               lfn_slot = lfn->id & LFN_ID_SLOTMASK;
-               lfn_checksum = lfn->alias_checksum;
-               lfn_unicode = alloc( (lfn_slot*CHARS_PER_LFN+1)*2 );
-               lfn_offsets = alloc( lfn_slot*sizeof(loff_t) );
-               lfn_parts = 0;
-               break;
-           }
-       }
-    }
-    else if ((lfn->id & LFN_ID_SLOTMASK) != lfn_slot) {
-       /* wrong sequence number */
-       /* Causes: 1) seq-no destroyed */
-       /* Fixes: 1) delete LFN, 2) fix number (maybe only if following parts
-        *        are ok?, maybe only if checksum is ok?) (Attention: space
-        *        for name was allocated before!) */
-       int can_fix = 0;
-       printf( "Unexpected long filename sequence number "
-               "(%d vs. expected %d).\n",
-               (lfn->id & LFN_ID_SLOTMASK), lfn_slot );
-       if (lfn->alias_checksum == lfn_checksum) {
-           char *part1 = CNV_THIS_PART(lfn);
-           char *part2 = CNV_PARTS_SO_FAR();
-           printf( "  It could be that just the number is wrong\n"
-                   "  if \"%s\" seems to match \"%s\".\n", part1, part2 );
-           free( part1 );
-           free( part2 );
-           can_fix = 1;
-       }
-       if (interactive) {
-           printf( "1: Delete LFN\n2: Leave it as it is (and ignore LFN so far)\n" );
-           if (can_fix)
-               printf( "3: Correct sequence number\n" );
-       }
-       else printf( "  Not auto-correcting this.\n" );
-       if (interactive) {
-           switch( get_key( can_fix ? "123" : "12", "?" )) {
-             case '1':
-               lfn_offsets[lfn_parts++] = dir_offset;
-               clear_lfn_slots( 0, lfn_parts-1 );
-               lfn_reset();
-               return;
-             case '2':
-               lfn_reset();
-               return;
-             case '3':
-               lfn->id = (lfn->id & ~LFN_ID_SLOTMASK) | lfn_slot;
-               fs_write( dir_offset+offsetof(LFN_ENT,id),
-                         sizeof(lfn->id), &lfn->id );
-               break;
-           }
-       }
-    }
-
-    if (lfn->alias_checksum != lfn_checksum) {
-       /* checksum mismatch */
-       /* Causes: 1) checksum field here destroyed */
-       /* Fixes: 1) delete LFN, 2) fix checksum */
-       printf( "Checksum in long filename part wrong "
-               "(%02x vs. expected %02x).\n",
-               lfn->alias_checksum, lfn_checksum );
-       if (interactive) {
-           printf( "1: Delete LFN\n2: Leave it as it is.\n"
-                   "3: Correct checksum\n" );
-       }
-       else printf( "  Not auto-correcting this.\n" );
-       if (interactive) {
-           switch( get_key( "123", "?" )) {
-             case '1':
-               lfn_offsets[lfn_parts++] = dir_offset;
-               clear_lfn_slots( 0, lfn_parts-1 );
-               lfn_reset();
-               return;
-             case '2':
-               break;
-             case '3':
-               lfn->alias_checksum = lfn_checksum;
-               fs_write( dir_offset+offsetof(LFN_ENT,alias_checksum),
-                         sizeof(lfn->alias_checksum), &lfn->alias_checksum );
-               break;
-           }
-       }
-    }
-
-    if (lfn_slot != -1) {
-       lfn_slot--;
-       offset = lfn_slot * CHARS_PER_LFN*2;
-       copy_lfn_part( lfn_unicode+offset, lfn );
-       if (lfn->id & LFN_ID_START)
-           lfn_unicode[offset+26] = lfn_unicode[offset+27] = 0;
-       lfn_offsets[lfn_parts++] = dir_offset;
-    }
-
-    if (lfn->reserved != 0) {
-       printf( "Reserved field in VFAT long filename slot is not 0 "
-               "(but 0x%02x).\n", lfn->reserved );
-       if (interactive)
-           printf( "1: Fix.\n2: Leave it.\n" );
-       else printf( "Auto-setting to 0.\n" );
-       if (!interactive || get_key("12","?") == '1') {
-           lfn->reserved = 0;
-           fs_write( dir_offset+offsetof(LFN_ENT,reserved),
-                     sizeof(lfn->reserved), &lfn->reserved );
-       }
-    }
-    if (lfn->start != CT_LE_W(0)) {
-       printf( "Start cluster field in VFAT long filename slot is not 0 "
-               "(but 0x%04x).\n", lfn->start );
-       if (interactive)
-           printf( "1: Fix.\n2: Leave it.\n" );
-       else printf( "Auto-setting to 0.\n" );
-       if (!interactive || get_key("12","?") == '1') {
-           lfn->start = CT_LE_W(0);
-           fs_write( dir_offset+offsetof(LFN_ENT,start),
-                     sizeof(lfn->start),&lfn->start );
-       }
-    }
-}
-
-
-/* This function is always called when de->attr != VFAT_LN_ATTR is found, to
- * retrieve the previously constructed LFN. */
-char *lfn_get( DIR_ENT *de )
-{
-    char *lfn;
-    __u8 sum;
-    int i;
-    
-    if (de->attr == VFAT_LN_ATTR)
-       die("lfn_get called with LFN directory entry");
-
-#if 0
-    if (de->lcase)
-       printf( "lcase=%02x\n",de->lcase );
-#endif
-
-    if (lfn_slot == -1)
-       /* no long name for this file */
-       return NULL;
-
-    if (lfn_slot != 0) {
-       /* The long name isn't finished yet. */
-       /* Causes: 1) LFN slot overwritten by non-VFAT aware tool */
-       /* Fixes: 1) delete LFN 2) move overwriting entry to somewhere else
-        * and let user enter missing part of LFN (hard to do :-()
-        * 3) renumber entries and truncate name */
-       char *long_name = CNV_PARTS_SO_FAR();
-       char *short_name = file_name(de->name);
-       printf( "Unfinished long file name \"%s\".\n"
-               "  (Start may have been overwritten by %s)\n",
-               long_name, short_name );
-       free( long_name );
-       if (interactive) {
-           printf( "1: Delete LFN\n2: Leave it as it is.\n"
-                   "3: Fix numbering (truncates long name and attaches "
-                   "it to short name %s)\n", short_name );
-       }
-       else printf( "  Not auto-correcting this.\n" );
-       if (interactive) {
-           switch( get_key( "123", "?" )) {
-             case '1':
-               clear_lfn_slots( 0, lfn_parts-1 );
-               lfn_reset();
-               return NULL;
-             case '2':
-               lfn_reset();
-               return NULL;
-             case '3':
-               for( i = 0; i < lfn_parts; ++i ) {
-                   __u8 id = (lfn_parts-i) | (i==0 ? LFN_ID_START : 0);
-                   fs_write( lfn_offsets[i]+offsetof(LFN_ENT,id),
-                             sizeof(id), &id );
-               }
-               memmove( lfn_unicode, lfn_unicode+lfn_slot*CHARS_PER_LFN*2,
-                        lfn_parts*CHARS_PER_LFN*2 );
-               break;
-           }
-       }
-    }
-
-    for (sum = 0, i = 0; i < 11; i++)
-       sum = (((sum&1) << 7) | ((sum&0xfe) >> 1)) + de->name[i];
-    if (sum != lfn_checksum) {
-       /* checksum doesn't match, long name doesn't apply to this alias */
-       /* Causes: 1) alias renamed */
-       /* Fixes: 1) Fix checksum in LFN entries */
-       char *long_name = CNV_PARTS_SO_FAR();
-       char *short_name = file_name(de->name);
-       printf( "Wrong checksum for long file name \"%s\".\n"
-               "  (Short name %s may have changed without updating the long name)\n",
-               long_name, short_name );
-       free( long_name );
-       if (interactive) {
-           printf( "1: Delete LFN\n2: Leave it as it is.\n"
-                   "3: Fix checksum (attaches to short name %s)\n",
-                   short_name );
-       }
-       else printf( "  Not auto-correcting this.\n" );
-       if (interactive) {
-           switch( get_key( "123", "?" )) {
-             case '1':
-               clear_lfn_slots( 0, lfn_parts-1 );
-               lfn_reset();
-               return NULL;
-             case '2':
-               lfn_reset();
-               return NULL;
-             case '3':
-               for( i = 0; i < lfn_parts; ++i ) {
-                   fs_write( lfn_offsets[i]+offsetof(LFN_ENT,alias_checksum),
-                             sizeof(sum), &sum );
-               }
-               break;
-           }
-       }
-    }
-
-    lfn = cnv_unicode( lfn_unicode, UNTIL_0, 1 );
-    lfn_reset();
-    return( lfn );
-}
-
-void lfn_check_orphaned(void)
-{
-    char *long_name;
-
-    if (lfn_slot == -1)
-       return;
-
-    long_name = CNV_PARTS_SO_FAR();
-    printf("Orphaned long file name part \"%s\"\n", long_name);
-    if (interactive)
-       printf( "1: Delete.\n2: Leave it.\n" );
-    else printf( "  Auto-deleting.\n" );
-    if (!interactive || get_key("12","?") == '1') {
-       clear_lfn_slots(0, lfn_parts - 1);
-    }
-    lfn_reset();
-}
-
-/* Local Variables: */
-/* tab-width: 8     */
-/* End:             */
+static __inline char* CNV_THIS_PART(LFN_ENT *lfn)\r
+{                                                      \\r
+       char __part_uni[CHARS_PER_LFN*2];\r
+       copy_lfn_part( __part_uni, lfn );\r
+       cnv_unicode( __part_uni, CHARS_PER_LFN, 0 );\r
+}\r
+    \r
+/* Convert name parts collected so far (from previous slots) from unicode to\r
+ * ASCII */\r
+#define CNV_PARTS_SO_FAR()                                     \\r
+       (cnv_unicode( lfn_unicode+(lfn_slot*CHARS_PER_LFN*2),   \\r
+                     lfn_parts*CHARS_PER_LFN, 0 ))\r
+\r
+/* This function converts an unicode string to a normal ASCII string, assuming\r
+ * ISO-8859-1 charset. Characters not in 8859-1 are converted to the same\r
+ * escape notation as used by the kernel, i.e. the uuencode-like ":xxx" */\r
+static char *cnv_unicode( const unsigned char *uni, int maxlen, int use_q )\r
+{\r
+    const unsigned char *up;\r
+    unsigned char *out, *cp;\r
+    int len, val;\r
+    \r
+    for( len = 0, up = uni; (up-uni)/2 < maxlen && (up[0] || up[1]); up += 2 ){\r
+       if (UNICODE_CONVERTABLE(up[0],up[1]))\r
+           ++len;\r
+       else\r
+           len += 4;\r
+    }\r
+    cp = out = use_q ? qalloc( &mem_queue, len+1 ) : alloc( len+1 );\r
+\r
+    for( up = uni; (up-uni)/2 < maxlen && (up[0] || up[1]); up += 2 ) {\r
+       if (UNICODE_CONVERTABLE(up[0],up[1]))\r
+           *cp++ = up[0];\r
+       else {\r
+           /* here the same escape notation is used as in the Linux kernel */\r
+           *cp++ = ':';\r
+           val = (up[1] << 8) + up[0];\r
+           cp[2] = fat_uni2esc[val & 0x3f];\r
+           val >>= 6;\r
+           cp[1] = fat_uni2esc[val & 0x3f];\r
+           val >>= 6;\r
+           cp[0] = fat_uni2esc[val & 0x3f];\r
+           cp += 3;\r
+       }\r
+    }\r
+    *cp = 0;\r
+\r
+    return( out );\r
+}\r
+\r
+\r
+static void copy_lfn_part( char *dst, LFN_ENT *lfn )\r
+{\r
+    memcpy( dst,    lfn->name0_4,   10 );\r
+    memcpy( dst+10, lfn->name5_10,  12 );\r
+    memcpy( dst+22, lfn->name11_12, 4 );\r
+}\r
+\r
+\r
+static void clear_lfn_slots( int start, int end )\r
+{\r
+    int i;\r
+    LFN_ENT empty;\r
+\r
+    /* New dir entry is zeroed except first byte, which is set to 0xe5.\r
+     * This is to avoid that some FAT-reading OSes (not Linux! ;) stop reading\r
+     * a directory at the first zero entry...\r
+     */\r
+    memset( &empty, 0, sizeof(empty) );\r
+    empty.id = DELETED_FLAG;\r
+    \r
+    for( i = start; i <= end; ++i ) {\r
+       fs_write( lfn_offsets[i], sizeof(LFN_ENT), &empty );\r
+    }\r
+}\r
+\r
+void lfn_reset( void )\r
+{\r
+    if (lfn_unicode)\r
+       free( lfn_unicode );\r
+    lfn_unicode = NULL;\r
+    if (lfn_offsets)\r
+       free( lfn_offsets );\r
+    lfn_offsets = NULL;\r
+    lfn_slot = -1;\r
+}\r
+\r
+\r
+/* This function is only called with de->attr == VFAT_LN_ATTR. It stores part\r
+ * of the long name. */\r
+void lfn_add_slot( DIR_ENT *de, loff_t dir_offset )\r
+{\r
+    LFN_ENT *lfn = (LFN_ENT *)de;\r
+    unsigned offset;\r
+\r
+    if (de->attr != VFAT_LN_ATTR)\r
+       die("lfn_add_slot called with non-LFN directory entry");\r
+\r
+    if (lfn->id & LFN_ID_START) {\r
+       if (lfn_slot != -1) {\r
+           int can_clear = 0;\r
+           /* There is already a LFN "in progess", so it is an error that a\r
+            * new start entry is here. */\r
+           /* Causes: 1) if slot# == expected: start bit set mysteriously, 2)\r
+            *         old LFN overwritten by new one */\r
+           /* Fixes: 1) delete previous LFN 2) if slot# == expected and\r
+            *        checksum ok: clear start bit */\r
+           /* XXX: Should delay that until next LFN known (then can better\r
+            * display the name) */\r
+           printf( "A new long file name starts within an old one.\n" );\r
+           if ((lfn->id & LFN_ID_SLOTMASK) == lfn_slot &&\r
+               lfn->alias_checksum == lfn_checksum) {\r
+               char *part1 = CNV_THIS_PART(lfn);\r
+               char *part2 = CNV_PARTS_SO_FAR();\r
+               printf( "  It could be that the LFN start bit is wrong here\n"\r
+                       "  if \"%s\" seems to match \"%s\".\n", part1, part2 );\r
+               free( part1 );\r
+               free( part2 );\r
+               can_clear = 1;\r
+           }\r
+           if (interactive) {\r
+               printf( "1: Delete previous LFN\n2: Leave it as it is.\n" );\r
+               if (can_clear)\r
+                   printf( "3: Clear start bit and concatenate LFNs\n" );\r
+           }\r
+           else printf( "  Not auto-correcting this.\n" );\r
+           if (interactive) {\r
+               switch( get_key( can_clear ? "123" : "12", "?" )) {\r
+                 case '1':\r
+                   clear_lfn_slots( 0, lfn_parts-1 );\r
+                   lfn_reset();\r
+                   break;\r
+                 case '2':\r
+                   break;\r
+                 case '3':\r
+                   lfn->id &= ~LFN_ID_START;\r
+                   fs_write( dir_offset+offsetof(LFN_ENT,id),\r
+                             sizeof(lfn->id), &lfn->id );\r
+                   break;\r
+               }\r
+           }\r
+       }\r
+       lfn_slot = lfn->id & LFN_ID_SLOTMASK;\r
+       lfn_checksum = lfn->alias_checksum;\r
+       lfn_unicode = alloc( (lfn_slot*CHARS_PER_LFN+1)*2 );\r
+       lfn_offsets = alloc( lfn_slot*sizeof(loff_t) );\r
+       lfn_parts = 0;\r
+    }\r
+    else if (lfn_slot == -1) {\r
+       /* No LFN in progress, but slot found; start bit missing */\r
+       /* Causes: 1) start bit got lost, 2) Previous slot with start bit got\r
+        *         lost */\r
+       /* Fixes: 1) delete LFN, 2) set start bit */\r
+       char *part = CNV_THIS_PART(lfn);\r
+       printf( "Long filename fragment \"%s\" found outside a LFN "\r
+               "sequence.\n  (Maybe the start bit is missing on the "\r
+               "last fragment)\n", part );\r
+       if (interactive) {\r
+           printf( "1: Delete fragment\n2: Leave it as it is.\n"\r
+                   "3: Set start bit\n" );\r
+       }\r
+       else printf( "  Not auto-correcting this.\n" );\r
+       if (interactive) {\r
+           switch( get_key( "123", "?" )) {\r
+             case '1':\r
+               if (!lfn_offsets)\r
+                   lfn_offsets = alloc( sizeof(loff_t) );\r
+               lfn_offsets[0] = dir_offset;\r
+               clear_lfn_slots( 0, 0 );\r
+               lfn_reset();\r
+               return;\r
+             case '2':\r
+               lfn_reset();\r
+               return;\r
+             case '3':\r
+               lfn->id |= LFN_ID_START;\r
+               fs_write( dir_offset+offsetof(LFN_ENT,id),\r
+                         sizeof(lfn->id), &lfn->id );\r
+               lfn_slot = lfn->id & LFN_ID_SLOTMASK;\r
+               lfn_checksum = lfn->alias_checksum;\r
+               lfn_unicode = alloc( (lfn_slot*CHARS_PER_LFN+1)*2 );\r
+               lfn_offsets = alloc( lfn_slot*sizeof(loff_t) );\r
+               lfn_parts = 0;\r
+               break;\r
+           }\r
+       }\r
+    }\r
+    else if ((lfn->id & LFN_ID_SLOTMASK) != lfn_slot) {\r
+       /* wrong sequence number */\r
+       /* Causes: 1) seq-no destroyed */\r
+       /* Fixes: 1) delete LFN, 2) fix number (maybe only if following parts\r
+        *        are ok?, maybe only if checksum is ok?) (Attention: space\r
+        *        for name was allocated before!) */\r
+       int can_fix = 0;\r
+       printf( "Unexpected long filename sequence number "\r
+               "(%d vs. expected %d).\n",\r
+               (lfn->id & LFN_ID_SLOTMASK), lfn_slot );\r
+       if (lfn->alias_checksum == lfn_checksum) {\r
+           char *part1 = CNV_THIS_PART(lfn);\r
+           char *part2 = CNV_PARTS_SO_FAR();\r
+           printf( "  It could be that just the number is wrong\n"\r
+                   "  if \"%s\" seems to match \"%s\".\n", part1, part2 );\r
+           free( part1 );\r
+           free( part2 );\r
+           can_fix = 1;\r
+       }\r
+       if (interactive) {\r
+           printf( "1: Delete LFN\n2: Leave it as it is (and ignore LFN so far)\n" );\r
+           if (can_fix)\r
+               printf( "3: Correct sequence number\n" );\r
+       }\r
+       else printf( "  Not auto-correcting this.\n" );\r
+       if (interactive) {\r
+           switch( get_key( can_fix ? "123" : "12", "?" )) {\r
+             case '1':\r
+               lfn_offsets[lfn_parts++] = dir_offset;\r
+               clear_lfn_slots( 0, lfn_parts-1 );\r
+               lfn_reset();\r
+               return;\r
+             case '2':\r
+               lfn_reset();\r
+               return;\r
+             case '3':\r
+               lfn->id = (lfn->id & ~LFN_ID_SLOTMASK) | lfn_slot;\r
+               fs_write( dir_offset+offsetof(LFN_ENT,id),\r
+                         sizeof(lfn->id), &lfn->id );\r
+               break;\r
+           }\r
+       }\r
+    }\r
+\r
+    if (lfn->alias_checksum != lfn_checksum) {\r
+       /* checksum mismatch */\r
+       /* Causes: 1) checksum field here destroyed */\r
+       /* Fixes: 1) delete LFN, 2) fix checksum */\r
+       printf( "Checksum in long filename part wrong "\r
+               "(%02x vs. expected %02x).\n",\r
+               lfn->alias_checksum, lfn_checksum );\r
+       if (interactive) {\r
+           printf( "1: Delete LFN\n2: Leave it as it is.\n"\r
+                   "3: Correct checksum\n" );\r
+       }\r
+       else printf( "  Not auto-correcting this.\n" );\r
+       if (interactive) {\r
+           switch( get_key( "123", "?" )) {\r
+             case '1':\r
+               lfn_offsets[lfn_parts++] = dir_offset;\r
+               clear_lfn_slots( 0, lfn_parts-1 );\r
+               lfn_reset();\r
+               return;\r
+             case '2':\r
+               break;\r
+             case '3':\r
+               lfn->alias_checksum = lfn_checksum;\r
+               fs_write( dir_offset+offsetof(LFN_ENT,alias_checksum),\r
+                         sizeof(lfn->alias_checksum), &lfn->alias_checksum );\r
+               break;\r
+           }\r
+       }\r
+    }\r
+\r
+    if (lfn_slot != -1) {\r
+       lfn_slot--;\r
+       offset = lfn_slot * CHARS_PER_LFN*2;\r
+       copy_lfn_part( lfn_unicode+offset, lfn );\r
+       if (lfn->id & LFN_ID_START)\r
+           lfn_unicode[offset+26] = lfn_unicode[offset+27] = 0;\r
+       lfn_offsets[lfn_parts++] = dir_offset;\r
+    }\r
+\r
+    if (lfn->reserved != 0) {\r
+       printf( "Reserved field in VFAT long filename slot is not 0 "\r
+               "(but 0x%02x).\n", lfn->reserved );\r
+       if (interactive)\r
+           printf( "1: Fix.\n2: Leave it.\n" );\r
+       else printf( "Auto-setting to 0.\n" );\r
+       if (!interactive || get_key("12","?") == '1') {\r
+           lfn->reserved = 0;\r
+           fs_write( dir_offset+offsetof(LFN_ENT,reserved),\r
+                     sizeof(lfn->reserved), &lfn->reserved );\r
+       }\r
+    }\r
+    if (lfn->start != CT_LE_W(0)) {\r
+       printf( "Start cluster field in VFAT long filename slot is not 0 "\r
+               "(but 0x%04x).\n", lfn->start );\r
+       if (interactive)\r
+           printf( "1: Fix.\n2: Leave it.\n" );\r
+       else printf( "Auto-setting to 0.\n" );\r
+       if (!interactive || get_key("12","?") == '1') {\r
+           lfn->start = CT_LE_W(0);\r
+           fs_write( dir_offset+offsetof(LFN_ENT,start),\r
+                     sizeof(lfn->start),&lfn->start );\r
+       }\r
+    }\r
+}\r
+\r
+\r
+/* This function is always called when de->attr != VFAT_LN_ATTR is found, to\r
+ * retrieve the previously constructed LFN. */\r
+char *lfn_get( DIR_ENT *de )\r
+{\r
+    char *lfn;\r
+    __u8 sum;\r
+    int i;\r
+    \r