free (p2);
+}
+#elif defined (__WATCOMC__)
+# include <i86.h>
+
+static int IsDirectory (const char *path) {
+
+ struct SREGS sr = { 0 };
+ union REGS r = { 0 };
+
+ char *temp = xstrdup (path);
+ unsigned len = strlen (temp);
+
+ if (len > 3) {
+
+ while (temp[len - 1] == '\\') {
+ temp[--len] = '\0';
+ }
+
+ }
+
+ r.w.ax = 0x4300;
+ r.w.dx = FP_OFF (temp);
+
+ sr.ds = FP_SEG (temp);
+ int86x (0x21, &r, &r, &sr);
+
+ free (temp);
+ return (!(r.w.cflag & 1) && (r.w.cx & 0x10));
+
+}
+
+int CreateDirectory (const char *path) {
+
+ struct SREGS sr = { 0 };
+ union REGS r = { 0 };
+
+ char *p = (char *) path;
+
+ while (p && *p != '\0') {
+
+ while (*p && *p == '\\') {
+ p++;
+ }
+
+ if (*p == '\0') { break; }
+
+ if ((p = strchr (p, '\\'))) {
+ *p = '\0';
+ }
+
+ r.w.ax = 0x3900;
+ r.w.dx = FP_OFF (path);
+
+ sr.ds = FP_SEG (path);
+ int86x (0x21, &r, &r, &sr);
+
+ if (r.w.cflag & 1) {
+
+ r.w.ax = 0x4300;
+ r.w.dx = FP_OFF (path);
+
+ sr.ds = FP_SEG (path);
+ int86x (0x21, &r, &r, &sr);
+
+ if (r.w.cflag & 1) {
+ return 1;
+ }
+
+ }
+
+ if (p) { *p = '\\'; }
+
+ }
+
+ return 0;
+
+}
+
+static int FindFirstFile (const char *path) {
+
+ struct SREGS sr = { 0 };
+ union REGS r = { 0 };
+
+ char *temp = xstrdup (path);
+ unsigned len = strlen (temp);
+
+ if (len > 3) {
+
+ while (temp[len - 1] == '\\') {
+ temp[--len] = '\0';
+ }
+
+ }
+
+ r.w.ax = 0x4E00;
+ r.w.cx = 0x30;
+ r.w.dx = FP_OFF (temp);
+
+ sr.ds = FP_SEG (temp);
+ int86x (0x21, &r, &r, &sr);
+
+ free (temp);
+ return (!(r.w.cflag & 1));
+
+}
+
+static int SetDiskTransfer (void *buf) {
+
+ struct SREGS sr = { 0 };
+ union REGS r = { 0 };
+
+ r.w.ax = 0x1A00;
+ r.w.dx = FP_OFF (buf);
+
+ sr.ds = FP_SEG (buf);
+ int86x (0x21, &r, &r, &sr);
+
+ return (!(r.w.cflag & 1));
+
+}
+
+static int FindNextFile (void) {
+
+ struct SREGS sr = { 0 };
+ union REGS r = { 0 };
+
+ r.w.ax = 0x4F00;
+ int86x (0x21, &r, &r, &sr);
+
+ return (!(r.w.cflag & 1));
+
+}
+
+static void add_entry (FILE *tarfp, char *root, const char *path) {
+
+ struct tar_raw_header header;
+
+ const char *p = path;
+ char *p2;
+
+ unsigned long len, i;
+ int mode;
+
+ if (isalpha ((int) p[0]) && p[1] == ':') {
+ p += 2;
+ }
+
+ while (*p == '/' || *p == '\\') {
+ p++;
+ }
+
+ if (root) {
+
+ len = strlen (root);
+
+ while (root[len - 1] == '/' || root[len - 1] == '\\') {
+
+ root[len - 1] = '\0';
+ len--;
+
+ }
+
+ for (i = 0; i < len; i++) {
+
+ if (root[i] == '\\') {
+ root[i] = '/';
+ }
+
+ }
+
+ p2 = xmalloc (len + 1);
+ sprintf (p2, "%s/", root);
+
+ } else {
+ p2 = xstrdup (path);
+ }
+
+ memset (&header, 0, sizeof (header));
+ strcpy (header.name, p);
+
+ memset (header.mtime, '0', 11);
+ sprintf (header.owner, "%07o", 0);
+
+ if (state->mode) {
+
+ int o1, o2, o3;
+
+ o1 = state->mode[1] - '0';
+ o2 = state->mode[2] - '0';
+ o3 = state->mode[3] - '0';
+
+ mode = (o1 << 6) | (o2 << 3) | o3;
+
+ } else {
+ mode = (IsDirectory (p2) ? 0775 : 0644);
+ }
+
+ sprintf (header.mode, "%07o", mode);
+
+ if (IsDirectory (p2)) {
+
+ unsigned char dta[128] = { 0 };
+ char *subpath, *filename;
+
+ memset (header.size, '0', 11);
+ header.type = '5'; /* MTAR_TDIR */
+
+ if (header.name[strlen(p) - 1] != '/') {
+ header.name[strlen(p)] = '/';
+ }
+
+ sprintf (header.checksum, "%06o", checksum (&header));
+ header.checksum[7] = ' ';
+
+ if (fwrite (&header, 1, sizeof (header), tarfp) != sizeof (header)) {
+ report_at (program_name, 0, REPORT_ERROR, "failed to write header to '%s'", state->target);
+ }
+
+ len = strlen (p2);
+
+ if (p2[len - 1] == '/') {
+
+ subpath = xmalloc (len + 5);
+ sprintf (subpath, "%s*.*", p2);
+
+ } else {
+
+ subpath = xmalloc (len + 6);
+ sprintf (subpath, "%s/*.*", p2);
+
+ }
+
+ if (!SetDiskTransfer (dta) || !FindFirstFile (subpath)) {
+
+ free (subpath);
+ return;
+
+ }
+
+ free (subpath);
+
+ do {
+
+ filename = dta + 0x1E;
+
+ if (filename[0] == '.' && (filename[1] == '\0' || (filename[1] == '.' && filename[2] == '\0'))) {
+ continue;
+ }
+
+ len = strlen (path);
+
+ if (path[len - 1] == '/') {
+
+ len += (strlen (filename) + 1);
+
+ if (!(subpath = malloc (len))) {
+
+ report_at (program_name, 0, REPORT_ERROR, "failed to allocate memory for '%s'", filename);
+ continue;
+
+ }
+
+ sprintf (subpath, "%s%s", path, filename);
+
+ } else {
+
+ len += (1 + strlen (filename) + 1);
+
+ if (!(subpath = malloc (len))) {
+
+ report_at (program_name, 0, REPORT_ERROR, "failed to allocate memory for '%s'", filename);
+ continue;
+
+ }
+
+ sprintf (subpath, "%s/%s", path, filename);
+
+ }
+
+ add_entry (tarfp, root, subpath);
+ free (subpath);
+
+ } while (FindNextFile ());
+
+ /*FindClose (hFind);*/
+
+ } else {
+
+ FILE *fp;
+
+ unsigned char *data;
+ uint64_t bytes, read;
+
+ if (!(fp = fopen (p2, "r+b"))) {
+
+ report_at (program_name, 0, REPORT_WARNING, "failed to open '%s' for reading", path);
+ goto _end;
+
+ }
+
+ fseek (fp, 0, SEEK_END);
+ bytes = ftell (fp);
+
+ fseek (fp, 0, SEEK_SET);
+
+ sprintf (header.size, "%011"I64_FMT"o", bytes);
+ header.type = '0'; /* MTAR_TREG */
+
+ sprintf (header.checksum, "%06o", checksum (&header));
+ header.checksum[7] = ' ';
+
+ if (fwrite (&header, 1, sizeof (header), tarfp) != sizeof (header)) {
+
+ report_at (program_name, 0, REPORT_ERROR, "failed to write header to '%s'", state->target);
+ fclose (fp);
+
+ goto _end;
+
+ }
+
+ data = xmalloc (512);
+
+ for (;;) {
+
+ if (bytes == 0 || feof (fp)) {
+ break;
+ }
+
+ read = (bytes > 512 ? 512 : bytes);
+
+ if (fread (data, 1, read, fp) != read) {
+
+ report_at (program_name, 0, REPORT_ERROR, "failed to read %lu bytes from %s", read, path);
+ break;
+
+ }
+
+ if (fwrite (data, 1, read, tarfp) != read) {
+
+ report_at (program_name, 0, REPORT_ERROR, "failed to write %lu bytes to %s", read, state->target);
+ break;
+
+ }
+
+ bytes -= read;
+
+ }
+
+ bytes = ftell (fp) % 512;
+ fclose (fp);
+
+ if (bytes != 0) {
+ write_null_bytes (tarfp, 512 - bytes);
+ }
+
+ }
+
+_end:
+
+ free (p2);
+
+}
+
+static void extract_files (FILE *tarfp, char *root) {
+
+ struct tar_raw_header header;
+
+ char *path, *p2;
+ FILE *fp;
+
+ unsigned long len, i;
+
+ if (root) {
+
+ len = strlen (root);
+
+ while (root[len - 1] == '/' || root[len - 1] == '\\') {
+
+ root[len - 1] = '\0';
+ len--;
+
+ }
+
+ for (i = 0; i < len; i++) {
+
+ if (root[i] == '\\') {
+ root[i] = '/';
+ }
+
+ }
+
+ if (!CreateDirectory (root)) {
+
+ report_at (program_name, 0, REPORT_ERROR, "failed to root directory %s", root);
+ return;
+
+ }
+
+ p2 = xmalloc (len + 1);
+ sprintf (p2, "%s/", root);
+
+ } else {
+ p2 = xstrdup ("");
+ }
+
+ for (;;) {
+
+ if (feof (tarfp)) {
+ break;
+ }
+
+ if (fread (&header, 1, sizeof (header), tarfp) != sizeof (header)) {
+
+ report_at (program_name, 0, REPORT_ERROR, "failed to read archive header");
+ break;
+
+ }
+
+ if (!header.name[0]) {
+ break;
+ }
+
+ path = xmalloc (strlen (p2) + strlen (header.name) + 1);
+ sprintf (path, "%s%s", p2, header.name);
+
+ printf ("extracting: %s\n", path);
+
+ if (path[strlen (path) - 1] == '/') {
+
+ path[strlen (path) - 1] = '\0';
+
+ if (!CreateDirectory (path)) {
+
+ report_at (program_name, 0, REPORT_ERROR, "failed to create directory %s, %lx", path);
+
+ free (path);
+ free (p2);
+
+ return;
+
+ }
+
+ } else {
+
+ unsigned long padding = 0, bytes, read;
+ unsigned char *data;
+
+ if (!(fp = fopen (path, "w+b"))) {
+
+ report_at (program_name, 0, REPORT_ERROR, "failed to create %s", path);
+
+ free (path);
+ free (p2);
+
+ return;
+
+ }
+
+ bytes = strtol (header.size, 0, 8);
+
+ if ((bytes % 512) != 0) {
+ padding = 512 - (bytes % 512);
+ }
+
+ data = xmalloc (512);
+
+ for (;;) {
+
+ memset (data, 0, 512);
+
+ if (bytes == 0) {
+ break;
+ }
+
+ read = (bytes > 512 ? 512 : bytes);
+
+ if (fread (data, 1, read, tarfp) != read) {
+
+ report_at (program_name, 0, REPORT_ERROR, "failed to read %lu bytes from %s", read, path);
+ break;
+
+ }
+
+ if (fwrite (data, 1, read, fp) != read) {
+
+ report_at (program_name, 0, REPORT_ERROR, "failed to write %lu bytes to %s", read, state->target);
+ break;
+
+ }
+
+ bytes -= read;
+
+ }
+
+ fseek (tarfp, padding, SEEK_CUR);
+
+ free (data);
+ fclose (fp);
+
+ }
+
+ free (path);
+
+ }
+
+ free (p2);
+
}
#endif