From a086e631e63acf190d1b7d63378628161c4e29ae Mon Sep 17 00:00:00 2001 From: Robert Pengelly Date: Wed, 8 Oct 2025 16:33:20 +0100 Subject: [PATCH] Fixed master branch --- common.c | 44 +++++++++++++- common.h | 8 ++- mcopy.c | 168 ++++++++++++++++++++++++++++++++++++++++++++++++----- mcopy.h | 6 ++ mkfs.c | 36 ++++++++---- mls.c | 2 +- mmd.c | 173 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- mmd.h | 6 ++ msdos.h | 4 ++ 9 files changed, 406 insertions(+), 41 deletions(-) diff --git a/common.c b/common.c index 66cd0c8..8fc99f6 100644 --- a/common.c +++ b/common.c @@ -222,8 +222,11 @@ int create_name (struct fat_dirent *dp, const char *path) { ; } - if (si > 0 || dp->lfn[si] == '.') { + while (dp->lfn[si] == '.') { + cf |= 3; + si++; + } while (di > 0 && dp->lfn[di - 1] != '.') { @@ -708,6 +711,45 @@ unsigned char sum_sfn (unsigned char *dir) { } +unsigned int mode_con (char *p) { + + unsigned long o1, o2, o3; + + char c1, c2, c3; + unsigned int mode; + + c1 = *p++; + c2 = *p++; + c3 = *p++; + + o1 = *p++ - '0'; + o2 = *p++ - '0'; + o3 = *p++ - '0'; + + mode = (o1 << 6) | (o2 << 3) | o3; + + if (c1 == 'c') { + mode |= 0020000; + } else if (c1 == 'd') { + mode |= 0040000; + } else if (c1 == 'b') { + mode |= 0060000; + } else if (c1 == '-') { + mode |= 0100000; + } + + if (c2 == 'u') { + mode |= 0004000; + } + + if (c3 == 'g') { + mode |= 0002000; + } + + return mode; + +} + unsigned short generate_datestamp (void) { diff --git a/common.h b/common.h index 501db44..5140f74 100644 --- a/common.h +++ b/common.h @@ -13,13 +13,17 @@ struct fat_dirent { }; +unsigned short generate_datestamp (void); +unsigned short generate_timestamp (void); + +/* Long filenames. */ int create_name (struct fat_dirent *dp, const char *path); void gen_numname (unsigned char *dst, const unsigned char *src, const unsigned short *lfn, unsigned int seq); int cmp_lfn (const unsigned short *lfnbuf, unsigned char *dir); unsigned char sum_sfn (unsigned char *dir); -unsigned short generate_datestamp (void); -unsigned short generate_timestamp (void); +/* Unix mode. */ +unsigned int mode_con (char *p); #endif /* _COMMON_H */ diff --git a/mcopy.c b/mcopy.c index 8c8bf46..7480067 100644 --- a/mcopy.c +++ b/mcopy.c @@ -92,10 +92,14 @@ enum options { OPTION_IGNORED = 1, OPTION_ARCA, + OPTION_GID, OPTION_HELP, OPTION_INPUT, + OPTION_MODE, OPTION_OFFSET, - OPTION_STATUS + OPTION_STATUS, + OPTION_UID, + OPTION_UNIX }; @@ -104,9 +108,13 @@ static struct option opts[] = { { "i", OPTION_INPUT, OPTION_HAS_ARG }, { "-arca", OPTION_ARCA, OPTION_NO_ARG }, + { "-gid", OPTION_GID, OPTION_HAS_ARG }, { "-help", OPTION_HELP, OPTION_NO_ARG }, + { "-mode", OPTION_MODE, OPTION_HAS_ARG }, { "-offset", OPTION_OFFSET, OPTION_HAS_ARG }, { "-status", OPTION_STATUS, OPTION_NO_ARG }, + { "-gid", OPTION_UID, OPTION_HAS_ARG }, + { "-unix", OPTION_UNIX, OPTION_NO_ARG }, { 0, 0, 0 } @@ -297,6 +305,26 @@ static void parse_args (int *pargc, char ***pargv, int optind) { } + case OPTION_GID: { + + if (!state->unix_extension) { + + report_at (program_name, 0, REPORT_WARNING, "--gid is ignored without --unix"); + break; + + } + + if (!(state->gid = atoi (optarg))) { + + report_at (program_name, 0, REPORT_ERROR, "bad number for --gid"); + exit (EXIT_FAILURE); + + } + + break; + + } + case OPTION_HELP: { print_help (EXIT_SUCCESS); @@ -318,6 +346,27 @@ static void parse_args (int *pargc, char ***pargv, int optind) { } + case OPTION_MODE: { + + if (!state->unix_extension) { + + report_at (program_name, 0, REPORT_WARNING, "--mode is ignored without --unix"); + break; + + } + + if (strlen (optarg) != 3) { + + report_at (program_name, 0, REPORT_ERROR, "invalid mode provided"); + exit (EXIT_FAILURE); + + } + + memmove (state->mode + 3, optarg, 3); + break; + + } + case OPTION_OFFSET: { long conversion; @@ -352,6 +401,33 @@ static void parse_args (int *pargc, char ***pargv, int optind) { } + case OPTION_UID: { + + if (!state->unix_extension) { + + report_at (program_name, 0, REPORT_WARNING, "--uid is ignored without --unix"); + break; + + } + + if (!(state->uid = atoi (optarg))) { + + report_at (program_name, 0, REPORT_ERROR, "bad number for --uid"); + exit (EXIT_FAILURE); + + } + + break; + + } + + case OPTION_UNIX: { + + state->unix_extension = 1; + break; + + } + default: { report_at (program_name, 0, REPORT_ERROR, "unsupported option '%s'", r); @@ -368,8 +444,8 @@ static void parse_args (int *pargc, char ***pargv, int optind) { #ifndef __PDOS__ /** Get a single character from the terminal. */ -static char getch () { - +static char getch (void) { + #if defined(_WIN32) && !defined (__PDOS__) KEY_EVENT_RECORD keyevent; @@ -641,6 +717,24 @@ static int set_fat_entry (unsigned char *scratch, unsigned int cluster, unsigned static unsigned int get_free_fat (unsigned char *scratch); static const unsigned char lfn_ofs[] = { 1, 3, 5, 7, 9, 14, 16, 18, 20, 22, 24, 28, 30 }; +static void put_unix_attributes (struct msdos_dirent *de, unsigned char *sfn) { + + unsigned char *p; + memset (de, 0, sizeof (*de)); + + de->attr = ATTR_UNIX_MODE | ATTR_LONG_NAME; + de->csum = sum_sfn (sfn); + + p = (unsigned char *) de; + p[0] = ATTR_ARCHIVE; + + write721_to_byte_array (p + 1, mode_con (state->mode)); + write721_to_byte_array (p + 4, state->uid); + + p[7] = state->gid; + +} + static void put_lfn (const unsigned short *lfn, int ord, int sum, struct msdos_dirent *de) { unsigned short wc; @@ -785,12 +879,12 @@ static int copy_file (const char *source, struct file_info *fi, const char *fnam } - num_clusters = (flen + clust_size - 1) / clust_size; + num_clusters = (flen + clust_size - 1) / clust_size; memset (cluster_chain, 0, cluster_count * sizeof (unsigned int)); - for (i = 2, j = 0; i < cluster_count && j < num_clusters; i++) { + for (i = (size_fat == 12 ? 3 : 2), j = 0; i < cluster_count && j < num_clusters; i++) { - if (get_fat_entry (fi->scratch, i) == 0) { + if (!(get_fat_entry (fi->scratch, i))) { cluster_chain[j++] = i; } @@ -823,9 +917,8 @@ static int copy_file (const char *source, struct file_info *fi, const char *fnam while ((bytes = fread (buffer, 1, clust_size, ifp)) > 0) { size += bytes; - i = cluster_chain[j++]; - if (i == cluster_count) { + if ((i = cluster_chain[j++]) == cluster_count) { free (cluster_chain); free (buffer); @@ -1133,13 +1226,13 @@ static int follow_path (const char *target, struct dir_info *di) { a = de.attr & 0x3f; c = de.name[0]; - if (c == 0xe5 || ((a & 0x08) && a != 15)) { + if (c == 0xE5 || ((a & 0x08) && a != 15)) { ord = 0xff; } else { if (a == 15) { - if (!(dp.fn[11] & 2)) { + if (!(dp.fn[11] & 0x40)) { if (c & 0x40) { @@ -1601,7 +1694,7 @@ static int open_file (const char *target, unsigned char *scratch, struct file_in } - fi->cluster = 0; + /*fi->cluster = 0;*/ if (seekto ((unsigned long) fi->dir_sector * 512) || fread (scratch, 512, 1, ofp) != 1) { return -1; @@ -1643,8 +1736,46 @@ static int open_file (const char *target, unsigned char *scratch, struct file_in nent = 1; } - if (dir_alloc ((char *) tmppath, &di, nent) < 0) { - return -1; + if (state->unix_extension) { + + unsigned char dir_offset; + unsigned int dir_sector; + + if (dir_alloc ((char *) tmppath, &di, nent + 1) < 0) { + return -1; + } + + if (get_free_dirent ((char *) tmppath, &di) < 0) { + return -1; + } + + put_unix_attributes (&de, dp.fn); + + if (di.current_cluster == 0) { + dir_sector = root_dir + di.current_sector; + } else { + dir_sector = data_area + ((di.current_cluster - 2) * sectors_per_cluster) + di.current_sector; + } + + /*fi->dir_offset = di.current_entry - 1;*/ + dir_offset = di.current_entry; + + if (seekto ((unsigned long) dir_sector * 512) || fread (scratch, 512, 1, ofp) != 1) { + return -1; + } + + memcpy (&(((struct msdos_dirent *) scratch)[dir_offset]), &de, sizeof (de)); + + if (seekto ((unsigned long) dir_sector * 512) || fwrite (scratch, 512, 1, ofp) != 1) { + return -1; + } + + } else { + + if (dir_alloc ((char *) tmppath, &di, nent) < 0) { + return -1; + } + } if (--nent) { @@ -1709,7 +1840,7 @@ static int open_file (const char *target, unsigned char *scratch, struct file_in if (di.current_cluster == 0) { fi->dir_sector = root_dir + di.current_sector; } else { - fi->dir_sector = data_area + ((di.current_cluster - 2) * sectors_per_cluster) + di.current_sector; + fi->dir_sector = data_area + ((di.current_cluster - 2) * sectors_per_cluster) + di.current_sector; } fi->dir_offset = di.current_entry; @@ -1918,7 +2049,7 @@ static unsigned int get_free_fat (unsigned char *scratch) { unsigned int i, result; - for (i = 2; i < cluster_count; i++) { + for (i = (size_fat == 12 ? 3 : 2); i < cluster_count; i++) { if (!(result = get_fat_entry (scratch, i))) { return i; @@ -1977,7 +2108,7 @@ int get_file (const char *source, unsigned char *scratch, struct file_info *fi) return -1; } - report_at (program_name, 0, REPORT_WARNING, "get_file: %ls - %.*s", dp.lfn, 11, dp.fn); + /*report_at (program_name, 0, REPORT_WARNING, "get_file: %ls - %.*s", dp.lfn, 11, dp.fn);*/ if (p > tmppath) { p--; @@ -2184,6 +2315,11 @@ int main (int argc, char **argv) { } state = xmalloc (sizeof (*state)); + + state->gid = 1; + state->uid = 2; + + state->mode = xstrdup ("---755"); parse_args (&argc, &argv, 1); if (!state->outfile || state->nb_files < 2) { diff --git a/mcopy.h b/mcopy.h index dee7b92..90f6271 100644 --- a/mcopy.h +++ b/mcopy.h @@ -15,6 +15,12 @@ struct mcopy_state { size_t offset; int chs_align; + int unix_extension; + + unsigned int gid; + unsigned int uid; + + char *mode; }; diff --git a/mkfs.c b/mkfs.c index d752a9d..50696eb 100644 --- a/mkfs.c +++ b/mkfs.c @@ -397,108 +397,120 @@ static void establish_bpb (void) { sectors_per_cluster = 2; root_entries = 112; - media_descriptor = 0xfe; sectors_per_track = 8; heads_per_cylinder = 1; + + media_descriptor = 0xFE; break; case 360: /* 180KB 5.25" */ sectors_per_cluster = 2; root_entries = 112; - media_descriptor = 0xfc; sectors_per_track = 9; heads_per_cylinder = 1; + + media_descriptor = 0xFC; break; case 640: /* 320KB 5.25" */ sectors_per_cluster = 2; root_entries = 112; - media_descriptor = 0xff; sectors_per_track = 8; heads_per_cylinder = 2; + + media_descriptor = 0xFF; break; case 720: /* 360KB 5.25" */ sectors_per_cluster = 2; root_entries = 112; - media_descriptor = 0xfd; sectors_per_track = 9; heads_per_cylinder = 2; + + media_descriptor = 0xFD; break; case 1280: /* 640KB 5.25" / 3.5" */ sectors_per_cluster = 2; root_entries = 112; - media_descriptor = 0xfb; sectors_per_track = 8; heads_per_cylinder = 2; + + media_descriptor = 0xFB; break; case 1440: /* 720KB 5.25" / 3.5" */ sectors_per_cluster = 2; root_entries = 112; - media_descriptor = 0xf9; sectors_per_track = 9; heads_per_cylinder = 2; + + media_descriptor = 0xF9; break; case 1640: /* 820KB 3.5" */ sectors_per_cluster = 2; root_entries = 112; - media_descriptor = 0xf9; sectors_per_track = 10; heads_per_cylinder = 2; + + media_descriptor = 0xF9; break; case 2400: /* 1.20MB 5.25" / 3.5" */ sectors_per_cluster = 1; root_entries = 224; - media_descriptor = 0xf9; sectors_per_track = 15; heads_per_cylinder = 2; + + media_descriptor = 0xF9; break; case 2880: /* 1.44MB 3.5" */ sectors_per_cluster = 1; root_entries = 224; - media_descriptor = 0xf0; sectors_per_track = 18; heads_per_cylinder = 2; + + media_descriptor = 0xF0; break; case 3360: /* 1.68MB 3.5" */ sectors_per_cluster = 1; root_entries = 224; - media_descriptor = 0xf0; sectors_per_track = 21; heads_per_cylinder = 2; + + media_descriptor = 0xF0; break; case 3444: /* 1.72MB 3.5" */ sectors_per_cluster = 1; root_entries = 224; - media_descriptor = 0xf0; sectors_per_track = 21; heads_per_cylinder = 2; + + media_descriptor = 0xF0; break; case 5760: /* 2.88MB 3.5" */ sectors_per_cluster = 2; root_entries = 240; - media_descriptor = 0xf0; sectors_per_track = 36; heads_per_cylinder = 2; + + media_descriptor = 0xF0; break; } diff --git a/mls.c b/mls.c index a53f2c7..46db2cf 100644 --- a/mls.c +++ b/mls.c @@ -965,7 +965,7 @@ int main (int argc, char **argv) { continue; } - if ((de.attr & ATTR_VOLUME_ID) == ATTR_VOLUME_ID || de.attr == ATTR_LONG_NAME) { + if ((de.attr & ATTR_VOLUME_ID) == ATTR_VOLUME_ID || (de.attr & 0x80) != 0) { continue; } diff --git a/mmd.c b/mmd.c index edc69fc..86d956d 100644 --- a/mmd.c +++ b/mmd.c @@ -64,9 +64,13 @@ enum options { OPTION_IGNORED = 1, OPTION_ARCA, + OPTION_GID, OPTION_HELP, OPTION_INPUT, - OPTION_OFFSET + OPTION_MODE, + OPTION_OFFSET, + OPTION_UID, + OPTION_UNIX }; @@ -75,8 +79,12 @@ static struct option opts[] = { { "i", OPTION_INPUT, OPTION_HAS_ARG }, { "-arca", OPTION_ARCA, OPTION_NO_ARG }, + { "-gid", OPTION_GID, OPTION_HAS_ARG }, { "-help", OPTION_HELP, OPTION_NO_ARG }, + { "-mode", OPTION_MODE, OPTION_HAS_ARG }, { "-offset", OPTION_OFFSET, OPTION_HAS_ARG }, + { "-uid", OPTION_UID, OPTION_HAS_ARG }, + { "-unix", OPTION_UNIX, OPTION_NO_ARG }, { 0, 0, 0 } @@ -267,6 +275,26 @@ static void parse_args (int *pargc, char ***pargv, int optind) { } + case OPTION_GID: { + + if (!state->unix_extension) { + + report_at (program_name, 0, REPORT_WARNING, "--gid is ignored without --unix"); + break; + + } + + if (!(state->gid = atoi (optarg))) { + + report_at (program_name, 0, REPORT_ERROR, "bad number for --gid"); + exit (EXIT_FAILURE); + + } + + break; + + } + case OPTION_HELP: { print_help (EXIT_SUCCESS); @@ -288,6 +316,27 @@ static void parse_args (int *pargc, char ***pargv, int optind) { } + case OPTION_MODE: { + + if (!state->unix_extension) { + + report_at (program_name, 0, REPORT_WARNING, "--mode is ignored without --unix"); + break; + + } + + if (strlen (optarg) != 3) { + + report_at (program_name, 0, REPORT_ERROR, "invalid mode provided"); + exit (EXIT_FAILURE); + + } + + memmove (state->mode + 3, optarg, 3); + break; + + } + case OPTION_OFFSET: { long conversion; @@ -315,6 +364,33 @@ static void parse_args (int *pargc, char ***pargv, int optind) { } + case OPTION_UID: { + + if (!state->unix_extension) { + + report_at (program_name, 0, REPORT_WARNING, "--uid is ignored without --unix"); + break; + + } + + if (!(state->uid = atoi (optarg))) { + + report_at (program_name, 0, REPORT_ERROR, "bad number for --uid"); + exit (EXIT_FAILURE); + + } + + break; + + } + + case OPTION_UNIX: { + + state->unix_extension = 1; + break; + + } + default: { report_at (program_name, 0, REPORT_ERROR, "unsupported option '%s'", r); @@ -346,6 +422,24 @@ static int set_fat_entry (unsigned char *scratch, unsigned int cluster, unsigned static unsigned int get_free_fat (unsigned char *scratch); static const unsigned char lfn_ofs[] = { 1, 3, 5, 7, 9, 14, 16, 18, 20, 22, 24, 28, 30 }; +static void put_unix_attributes (struct msdos_dirent *de, unsigned char *sfn) { + + unsigned char *p; + memset (de, 0, sizeof (*de)); + + de->attr = ATTR_UNIX_MODE | ATTR_LONG_NAME; + de->csum = sum_sfn (sfn); + + p = (unsigned char *) de; + p[0] = ATTR_DIR; + + write721_to_byte_array (p + 1, mode_con (state->mode)); + write721_to_byte_array (p + 4, state->uid); + + p[7] = state->gid; + +} + static void put_lfn (const unsigned short *lfn, int ord, int sum, struct msdos_dirent *de) { unsigned short wc; @@ -616,8 +710,50 @@ static int create_dir (const char *target, unsigned char *scratch) { nent = 1; } - if (dir_alloc ((char *) tmppath, &di, nent) < 0) { - return -1; + if (state->unix_extension) { + + struct msdos_dirent de; + struct dir_info udi; + + unsigned char dir_offset; + unsigned int dir_sector; + + if (dir_alloc ((char *) tmppath, &di, nent + 1) < 0) { + return -1; + } + + memcpy (&udi, &di, sizeof (udi)); + + if (get_free_dirent ((char *) tmppath, &udi) < 0) { + return -1; + } + + put_unix_attributes (&de, dp.fn); + + if (di.current_cluster == 0) { + dir_sector = root_dir + udi.current_sector; + } else { + dir_sector = data_area + ((udi.current_cluster - 2) * sectors_per_cluster) + udi.current_sector; + } + + dir_offset = udi.current_entry; + + if (seekto ((unsigned long) dir_sector * 512) || fread (scratch, 512, 1, ofp) != 1) { + return -1; + } + + memcpy (&(((struct msdos_dirent *) scratch)[dir_offset]), &de, sizeof (de)); + + if (seekto ((unsigned long) dir_sector * 512) || fwrite (scratch, 512, 1, ofp) != 1) { + return -1; + } + + } else { + + if (dir_alloc ((char *) tmppath, &di, nent) < 0) { + return -1; + } + } if (--nent) { @@ -718,8 +854,11 @@ static int create_dir (const char *target, unsigned char *scratch) { } - dir_offset = 0; + de.type = 0; + de.csum = 0; + dir_sector = data_area + ((cluster - 2) * sectors_per_cluster); + dir_offset = 0; memset (de.name, ' ', 11); de.name[0] = '.'; @@ -1109,6 +1248,7 @@ static int get_free_dirent (const char *path, struct dir_info *di) { static int get_next_entry (struct dir_info *di, struct msdos_dirent *de) { unsigned long offset; + unsigned int cluster; if (di->current_entry >= 512 / sizeof (*de)) { @@ -1145,13 +1285,23 @@ static int get_next_entry (struct dir_info *di, struct msdos_dirent *de) { } - di->current_cluster = get_fat_entry (di->scratch, di->current_cluster); + cluster = get_fat_entry (di->scratch, di->current_cluster); + + if ((size_fat == 12 && cluster >= 0x0FF8) || (size_fat == 16 && cluster >= 0xFFF8) || (size_fat == 32 && cluster >= 0x0FFFFFF8)) { + + cluster = get_free_fat (di->scratch); + + if (cluster == 0x0FFFFFF7 || set_fat_entry (di->scratch, di->current_cluster, cluster) < 0 || set_fat_entry (di->scratch, cluster, 0x0FFFFFF8) < 0) { + return -1; + } + + } + + di->current_cluster = cluster; } - offset = (unsigned long) data_area; - offset += ((di->current_cluster - 2) * sectors_per_cluster); - offset += di->current_sector; + offset = ((unsigned long) data_area + ((di->current_cluster - 2) * sectors_per_cluster)) + di->current_sector; if (seekto (offset * 512) || fread (di->scratch, 512, 1, ofp) != 1) { return -1; @@ -1375,7 +1525,7 @@ static unsigned int get_free_fat (unsigned char *scratch) { unsigned int i, result = 0xFFFFFFFF; - for (i = 2; i < cluster_count; i++) { + for (i = (size_fat == 12 ? 3 : 2); i < cluster_count; i++) { result = get_fat_entry (scratch, i); @@ -1452,6 +1602,11 @@ int main (int argc, char **argv) { } state = xmalloc (sizeof (*state)); + + state->gid = 1; + state->uid = 2; + + state->mode = xstrdup ("d--644"); parse_args (&argc, &argv, 1); if (!state->outfile || state->nb_dirs == 0) { diff --git a/mmd.h b/mmd.h index 0286400..030c51e 100644 --- a/mmd.h +++ b/mmd.h @@ -13,6 +13,12 @@ struct mmd_state { unsigned long offset; int chs_align; + int unix_extension; + + unsigned int gid; + unsigned int uid; + + char *mode; }; diff --git a/msdos.h b/msdos.h index b104ea3..35722e9 100644 --- a/msdos.h +++ b/msdos.h @@ -39,6 +39,10 @@ #define ATTR_VOLUME_ID 0x08 #define ATTR_DIR 0x10 #define ATTR_ARCHIVE 0x20 + +#define ATTR_UNIX_LINK 0x40 +#define ATTR_UNIX_MODE 0x80 + #define ATTR_LONG_NAME (ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME_ID) struct msdos_volume_info { -- 2.34.1