;
}
- if (si > 0 || dp->lfn[si] == '.') {
+ while (dp->lfn[si] == '.') {
+
cf |= 3;
+ si++;
+
}
while (di > 0 && dp->lfn[di - 1] != '.') {
}
+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) {
};
+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 */
OPTION_IGNORED = 1,
OPTION_ARCA,
+ OPTION_GID,
OPTION_HELP,
OPTION_INPUT,
+ OPTION_MODE,
OPTION_OFFSET,
- OPTION_STATUS
+ OPTION_STATUS,
+ OPTION_UID,
+ OPTION_UNIX
};
{ "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 }
}
+ 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);
}
+ 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;
}
+ 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);
#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;
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;
}
- 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;
}
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);
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) {
}
- fi->cluster = 0;
+ /*fi->cluster = 0;*/
if (seekto ((unsigned long) fi->dir_sector * 512) || fread (scratch, 512, 1, ofp) != 1) {
return -1;
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) {
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;
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;
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--;
}
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) {
size_t offset;
int chs_align;
+ int unix_extension;
+
+ unsigned int gid;
+ unsigned int uid;
+
+ char *mode;
};
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;
}
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;
}
OPTION_IGNORED = 1,
OPTION_ARCA,
+ OPTION_GID,
OPTION_HELP,
OPTION_INPUT,
- OPTION_OFFSET
+ OPTION_MODE,
+ OPTION_OFFSET,
+ OPTION_UID,
+ OPTION_UNIX
};
{ "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 }
}
+ 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);
}
+ 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;
}
+ 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);
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;
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) {
}
- 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] = '.';
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)) {
}
- 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;
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);
}
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) {
unsigned long offset;
int chs_align;
+ int unix_extension;
+
+ unsigned int gid;
+ unsigned int uid;
+
+ char *mode;
};
#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 {