summaryrefslogtreecommitdiffstats
path: root/perl-install/resize_fat/c_rewritten.xs
diff options
context:
space:
mode:
Diffstat (limited to 'perl-install/resize_fat/c_rewritten.xs')
-rw-r--r--perl-install/resize_fat/c_rewritten.xs265
1 files changed, 265 insertions, 0 deletions
diff --git a/perl-install/resize_fat/c_rewritten.xs b/perl-install/resize_fat/c_rewritten.xs
new file mode 100644
index 000000000..2bca483c0
--- /dev/null
+++ b/perl-install/resize_fat/c_rewritten.xs
@@ -0,0 +1,265 @@
+#include "EXTERN.h"
+#include "perl.h"
+#include "XSUB.h"
+
+/* set by scan_fat, used by next */
+short *fat = NULL;
+char *fat_flag_map = NULL;
+unsigned int *fat_remap = NULL;
+int fat_remap_size;
+int type_size, nb_clusters, bad_cluster_value;
+
+void free_all() {
+#define FREE(p) if (p) free(p), p = NULL;
+ FREE(fat);
+ FREE(fat_flag_map);
+ FREE(fat_remap);
+#undef FREE
+}
+
+unsigned int next(unsigned int cluster) {
+ short *p = fat + type_size * cluster;
+ if (!fat) {
+ free_all();
+ croak("fat::next: trying to use null pointer");
+ }
+ if (cluster >= nb_clusters + 2) {
+ free_all();
+ croak("fat::next: cluster %d outside filesystem", cluster);
+ }
+ return type_size == 1 ? *p : *((unsigned int *) p);
+}
+
+void set_next(unsigned int cluster, unsigned int val) {
+ short *p = fat + type_size * cluster;
+ if (!fat) {
+ free_all();
+ croak("fat::set_next: trying to use null pointer");
+ }
+ if (cluster >= nb_clusters + 2) {
+ free_all();
+ croak("fat::set_next: cluster %d outside filesystem", cluster);
+ }
+ if (type_size == 1)
+ *p = val;
+ else
+ *((unsigned int *) p) = val;
+}
+
+MODULE = resize_fat::c_rewritten PACKAGE = resize_fat::c_rewritten
+
+PROTOTYPES: DISABLE
+
+
+void
+read_fat(fd, offset, size, magic)
+ int fd
+ int offset
+ int size
+ unsigned char magic
+ PPCODE:
+{
+ fat = (short *) malloc(size);
+ if (!fat) {
+ free_all();
+ croak("read_fat: not enough memory");
+ }
+ if (lseek(fd, offset, SEEK_SET) != offset ||
+ read(fd, fat, size) != size) {
+ free_all();
+ croak("read_fat: reading FAT failed");
+ }
+ if (magic != *(unsigned char *) fat) {
+ free_all();
+ croak("read_fat: FAT has invalid signature");
+ }
+}
+
+void
+write_fat(fd, size)
+ int fd
+ int size
+ PPCODE:
+{
+ if (write(fd, fat, size) != size) {
+ free_all();
+ croak("write_fat: write failed");
+ }
+}
+
+void
+free_all()
+ PPCODE:
+ free_all();
+
+void
+scan_fat(nb_clusters_, type_size_)
+ int nb_clusters_
+ int type_size_
+ PPCODE:
+{
+ unsigned int v;
+ int free = 0, bad = 0, used = 0;
+ short *p;
+
+ type_size = type_size_; nb_clusters = nb_clusters_;
+ bad_cluster_value = type_size == 32 ? 0x0ffffff7 : 0xfff7;
+
+ if (type_size % 16) {
+ free_all();
+ croak("scan_fat: unable to handle FAT%d", type_size);
+ }
+ type_size /= 16;
+
+ for (p = fat + 2 * type_size; p < fat + type_size * (nb_clusters + 2); p += type_size) {
+ v = type_size == 1 ? *p : *((unsigned int *) p);
+
+ if (v == 0) free++;
+ else if (v == bad_cluster_value) bad++;
+ }
+ used = nb_clusters - free - bad;
+ EXTEND(SP, 3);
+ PUSHs(sv_2mortal(newSViv(free)));
+ PUSHs(sv_2mortal(newSViv(bad)));
+ PUSHs(sv_2mortal(newSViv(used)));
+}
+
+unsigned int
+next(unused, cluster)
+ void *unused
+ unsigned int cluster
+ CODE:
+ RETVAL = next(cluster);
+ OUTPUT:
+ RETVAL
+
+void
+set_next(unused, cluster, val)
+ void *unused
+ unsigned int cluster
+ unsigned int val
+ CODE:
+ set_next(cluster, val);
+
+void
+allocate_fat_flag(size)
+ int size
+ CODE:
+ fat_flag_map = calloc(size, 1);
+ if (!fat_flag_map) {
+ free_all();
+ croak("allocate_fat_flag: not enough memory");
+ }
+
+int
+checkFat(cluster, type, name)
+ unsigned int cluster
+ int type
+ char *name
+ CODE:
+ int nb = 0;
+
+ if (!fat_flag_map) {
+ free_all();
+ croak("Bad FAT: trying to use null pointer");
+ }
+ for (; cluster < bad_cluster_value; cluster = next(cluster)) {
+ if (cluster == 0) {
+ free_all();
+ croak("Bad FAT: unterminated chain for %s\n", name);
+ }
+ if (cluster >= nb_clusters + 2) {
+ free_all();
+ croak("Bad FAT: chain outside filesystem for %s\n", name);
+ }
+ if (fat_flag_map[cluster]) {
+ free_all();
+ croak("Bad FAT: cluster %d is cross-linked for %s\n", cluster, name);
+ }
+ fat_flag_map[cluster] = type;
+ nb++;
+ }
+ RETVAL = nb;
+ OUTPUT:
+ RETVAL
+
+unsigned int
+flag(cluster)
+ unsigned int cluster
+ CODE:
+ if (!fat_flag_map) {
+ free_all();
+ croak("Bad FAT: trying to use null pointer");
+ }
+ if (cluster >= nb_clusters + 2) {
+ free_all();
+ croak("Bad FAT: going outside filesystem");
+ }
+ RETVAL = fat_flag_map[cluster];
+ OUTPUT:
+ RETVAL
+
+void
+set_flag(cluster, flag)
+ unsigned int cluster
+ int flag
+ CODE:
+ if (!fat_flag_map) {
+ free_all();
+ croak("Bad FAT: trying to use null pointer");
+ }
+ if (cluster >= nb_clusters + 2) {
+ free_all();
+ croak("Bad FAT: going outside filesystem");
+ }
+ fat_flag_map[cluster] = flag;
+
+void
+allocate_fat_remap(size)
+ int size
+ CODE:
+ fat_remap_size = size;
+ fat_remap = (unsigned int *) calloc(size, sizeof(unsigned int *));
+ if (!fat_remap) {
+ free_all();
+ croak("allocate_fat_remap: not enough memory");
+ }
+
+unsigned int
+fat_remap(cluster)
+ unsigned int cluster
+ CODE:
+ if (!fat_remap) {
+ free_all();
+ croak("fat_remap: trying to use null pointer");
+ }
+ if (cluster >= bad_cluster_value) {
+ RETVAL = cluster; /* special cases */
+ } else {
+ if (cluster >= fat_remap_size) {
+ free_all();
+ croak("fat_remap: cluster %d >= %d in fat_remap", cluster, fat_remap_size);
+ }
+ RETVAL = fat_remap[cluster];
+ }
+ OUTPUT:
+ RETVAL
+
+void
+set_fat_remap(cluster, val)
+ unsigned int cluster
+ unsigned int val
+ CODE:
+ if (!fat_remap) {
+ free_all();
+ croak("set_fat_remap: trying to use null pointer");
+ }
+ if (cluster >= fat_remap_size) {
+ free_all();
+ croak("set_fat_remap: cluster %d >= %d in set_fat_remap", cluster, fat_remap_size);
+ }
+ if (val < bad_cluster_value && val >= fat_remap_size) {
+ free_all();
+ croak("set_fat_remap: remapping cluster %d to cluster %d >= %d in set_fat_remap", cluster, val, fat_remap_size);
+ }
+ fat_remap[cluster] = val;