mirror of
https://github.com/gryf/ADFlib.git
synced 2026-02-07 08:45:55 +01:00
473 lines
14 KiB
Plaintext
473 lines
14 KiB
Plaintext
--- unadf.c 2013-02-22 09:16:21.585508471 +0100
|
|
+++ /var/tmp/unadf_2010_0209.c 2013-03-13 15:26:48.915232398 +0100
|
|
@@ -29,6 +29,11 @@
|
|
#include<errno.h>
|
|
#include<string.h>
|
|
|
|
+#include <sys/types.h>
|
|
+#include <utime.h>
|
|
+#include <sys/time.h>
|
|
+
|
|
+
|
|
#include "adflib.h"
|
|
|
|
/* The portable way used to create a directory is to call the MKDIR command via the
|
|
@@ -65,6 +70,62 @@
|
|
puts(" -d dir : extract to 'dir' directory");
|
|
}
|
|
|
|
+int nukeIllegalWindowsTrailingChars(char *filename, char *endMem)
|
|
+{
|
|
+ int l = strlen(filename);
|
|
+ int i = l - 1;
|
|
+ char *j;
|
|
+ int count = 0;
|
|
+ while (filename[i] == ' ' || filename[i] == '.') {
|
|
+ for(j=filename+i; j < endMem; ++j)
|
|
+ *j = *(j+1);
|
|
+ --endMem;
|
|
+ ++count;
|
|
+ --i;
|
|
+ if (i == 0) {
|
|
+ fprintf(stderr, "unexpected error trimming illegal trailing chars \".\" and space from filename left nothing.\n");
|
|
+ exit(1);
|
|
+ }
|
|
+ }
|
|
+ return count;
|
|
+
|
|
+}
|
|
+
|
|
+void setFileDateTime(char *filename, struct Entry* entry)
|
|
+{
|
|
+
|
|
+ struct tm t;
|
|
+ time_t t_of_day;
|
|
+ struct utimbuf tb;
|
|
+
|
|
+ /*
|
|
+ Floor the year for windows to 1980.
|
|
+ This is because some users did not set their clock right
|
|
+ and the first possible Amiga year 1978 would appear frequently making
|
|
+ the file dates on early Amiga computers potentially less useful.
|
|
+ Windows (although not NTFS itself) barfs on dates with year less than 1980.
|
|
+ */
|
|
+ if (entry->year < 1980)
|
|
+ entry->year = 1980;
|
|
+
|
|
+ t.tm_year = entry->year - 1900;
|
|
+ t.tm_mon = entry->month - 1;
|
|
+ t.tm_mday = entry->days;
|
|
+ t.tm_hour = entry->hour;
|
|
+ t.tm_min = entry->mins;
|
|
+ t.tm_sec = entry->secs;
|
|
+ t.tm_isdst = -1;
|
|
+
|
|
+ t_of_day = mktime(&t);
|
|
+
|
|
+ memcpy (&tb.actime, &t_of_day, sizeof (time_t));
|
|
+ memcpy (&tb.modtime, &t_of_day, sizeof (time_t));
|
|
+
|
|
+ if (utime(filename, &tb) != 0)
|
|
+ fprintf(stderr, "error calling utime on %s\n", filename);
|
|
+
|
|
+}
|
|
+
|
|
void printEnt(struct Volume *vol, struct Entry* entry, char *path, BOOL sect)
|
|
{
|
|
/* do not print the links entries, ADFlib do not support them yet properly */
|
|
@@ -97,21 +158,26 @@
|
|
|
|
|
|
void extractFile(struct Volume *vol, char* name, char* path, unsigned char *extbuf,
|
|
- BOOL pflag, BOOL qflag)
|
|
+ BOOL pflag, BOOL qflag, struct Entry * entry)
|
|
{
|
|
struct File *file;
|
|
FILE* out;
|
|
long n;
|
|
char *filename;
|
|
+ char *fixedFileName = malloc(strlen(name)+1);
|
|
+
|
|
+ strcpy(fixedFileName, name);
|
|
+
|
|
+ nukeIllegalWindowsTrailingChars(fixedFileName, fixedFileName+strlen(fixedFileName));
|
|
|
|
filename = NULL;
|
|
if (pflag)
|
|
out = stdout;
|
|
else {
|
|
if (strlen(path)>0) {
|
|
- filename=(char*)malloc(sizeof(char)* (strlen(path)+1+strlen(name)+1) );
|
|
+ filename=(char*)malloc(sizeof(char)* (strlen(path)+1+strlen(fixedFileName)+1) );
|
|
if (!filename) return;
|
|
- sprintf(filename,"%s%c%s",path,DIRSEP,name);
|
|
+ sprintf(filename,"%s%c%s",path,DIRSEP,fixedFileName);
|
|
out = fopen(filename, "wb");
|
|
}
|
|
else
|
|
@@ -130,16 +196,27 @@
|
|
if (n>0)
|
|
fwrite(extbuf, sizeof(unsigned char), n, out);
|
|
|
|
- if (!pflag)
|
|
+ adfCloseFile(file);
|
|
+
|
|
+ if (!pflag) {
|
|
+
|
|
fclose(out);
|
|
|
|
- adfCloseFile(file);
|
|
+ printf("%4d/%02d/%02d %2d:%02d:%02d ",entry->year, entry->month, entry->days,
|
|
+ entry->hour, entry->mins, entry->secs);
|
|
+
|
|
+ setFileDateTime(filename, entry);
|
|
+
|
|
+ }
|
|
+
|
|
|
|
if (!qflag) {
|
|
if (filename!=NULL)
|
|
printf("x - %s\n", filename);
|
|
else
|
|
printf("x - %s\n", name);
|
|
+
|
|
+
|
|
}
|
|
|
|
if (filename!=NULL)
|
|
@@ -150,34 +227,47 @@
|
|
void extractTree(struct Volume *vol, struct List* tree, char *path, unsigned char *extbuf,
|
|
BOOL pflag, BOOL qflag)
|
|
{
|
|
- struct Entry* entry;
|
|
+ struct Entry* entry;
|
|
char *buf;
|
|
char sysbuf[200];
|
|
|
|
while(tree) {
|
|
entry = (struct Entry*)tree->content;
|
|
if (entry->type==ST_DIR) {
|
|
+ char mysep[2];
|
|
buf = NULL;
|
|
+ if (!qflag && !pflag) {
|
|
+ printf("%4d/%02d/%02d %2d:%02d:%02d ",
|
|
+ entry->year, entry->month, entry->days,
|
|
+ entry->hour, entry->mins, entry->secs);
|
|
+ }
|
|
if (strlen(path)>0) {
|
|
- buf=(char*)malloc(strlen(path)+1+strlen(entry->name)+1);
|
|
- if (!buf) return;
|
|
- sprintf(buf,"%s%c%s",path,DIRSEP,entry->name);
|
|
- sprintf(sysbuf,"%s %s",MKDIR,buf);
|
|
- if (!qflag) printf("x - %s%c\n",buf,DIRSEP);
|
|
+ mysep[0] = DIRSEP;
|
|
+ mysep[1] = 0;
|
|
}
|
|
else {
|
|
- sprintf(sysbuf,"%s %s",MKDIR,entry->name);
|
|
- if (!qflag) printf("x - %s%c\n",entry->name,DIRSEP);
|
|
+ mysep[0] = 0;
|
|
}
|
|
|
|
- if (!pflag) system(sysbuf);
|
|
+ buf=(char*)malloc(strlen(path)+strlen(mysep)+strlen(entry->name)+1);
|
|
+ if (!buf) return;
|
|
+ sprintf(buf,"%s%s%s",path,mysep,entry->name);
|
|
+
|
|
+
|
|
+ nukeIllegalWindowsTrailingChars(buf, buf+strlen(buf));
|
|
|
|
- if (tree->subdir!=NULL) {
|
|
+
|
|
+ /* use double quotes around argument for paths with embedded spaces */
|
|
+ sprintf(sysbuf,"%s \"%s\"",MKDIR,buf);
|
|
+ if (!qflag) printf("x - %s%s\n",buf,mysep);
|
|
+
|
|
+ if (!pflag)
|
|
+ system(sysbuf);
|
|
+
|
|
+
|
|
+ if (tree->subdir!=NULL) {
|
|
if (adfChangeDir(vol,entry->name)==RC_OK) {
|
|
- if (buf!=NULL)
|
|
- extractTree(vol,tree->subdir,buf,extbuf, pflag, qflag);
|
|
- else
|
|
- extractTree(vol,tree->subdir,entry->name,extbuf, pflag, qflag);
|
|
+ extractTree(vol,tree->subdir,buf,extbuf, pflag, qflag);
|
|
adfParentDir(vol);
|
|
}
|
|
else {
|
|
@@ -188,17 +278,22 @@
|
|
}
|
|
}
|
|
|
|
+ if (!pflag) {
|
|
+ setFileDateTime(buf, entry);
|
|
+ }
|
|
+
|
|
if (buf!=NULL)
|
|
free(buf);
|
|
}
|
|
else if (entry->type==ST_FILE) {
|
|
- extractFile(vol,entry->name,path,extbuf, pflag, qflag);
|
|
+ extractFile(vol,entry->name,path,extbuf, pflag, qflag, entry);
|
|
}
|
|
tree = tree->next;
|
|
}
|
|
}
|
|
|
|
|
|
+
|
|
void printTree(struct Volume *vol, struct List* tree, char* path, BOOL sect)
|
|
{
|
|
char *buf;
|
|
@@ -286,83 +381,166 @@
|
|
|
|
}
|
|
|
|
+struct Entry* findEntryInDir(struct Volume *vol, char *filename, struct List** plist) {
|
|
+ struct List *list, *cell;
|
|
+ cell = list = adfGetDirEnt(vol,vol->curDirPtr);
|
|
+ *plist = list;
|
|
+ while(cell) {
|
|
+ struct Entry *entry = (struct Entry*)cell->content;
|
|
+ if (strcmp(entry->name, filename)==0)
|
|
+ return entry;
|
|
+ cell = cell->next;
|
|
+ }
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+struct saveParentDir {
|
|
+ struct saveParentDir *next;
|
|
+ char *fullname;
|
|
+ struct Entry* entry;
|
|
+ struct List* list;
|
|
+};
|
|
+
|
|
|
|
void processFile(struct Volume *vol, char* name, char* path, unsigned char *extbuf,
|
|
BOOL pflag, BOOL qflag)
|
|
{
|
|
- char *sepptr, *cdstr, *fullname, *filename;
|
|
- char *bigstr;
|
|
+ char *sepptr, *cdstr, *fullname, *filename;
|
|
+ char *bigstr = NULL;
|
|
FILE *tfile;
|
|
+ struct List *list;
|
|
+ struct Entry* entry;
|
|
+ struct saveParentDir* spdhead = NULL, *n;
|
|
+ char mysep[2];
|
|
+ int bigsize;
|
|
+ char *endMem;
|
|
+ int trimCount;
|
|
|
|
adfToRootDir(vol);
|
|
|
|
sepptr = strchr(name, '/');
|
|
if (sepptr==NULL) {
|
|
- extractFile(vol, name, path, extbuf, pflag, qflag);
|
|
+ filename = name;
|
|
+ fullname = path;
|
|
}
|
|
else {
|
|
/* the all-in-one string : to call system(), to find the filename, the convert dir sep char ... */
|
|
- bigstr=(char*)malloc(strlen(MKDIR)+1+strlen(path)+1+strlen(name)+1);
|
|
+ bigsize=strlen(MKDIR)+1+1+strlen(path)+1+strlen(name)+1+1; // includes double-quotes around MKDIR arg
|
|
+ bigstr=(char*)malloc(bigsize);
|
|
if (!bigstr) { fprintf(stderr,"processFile : malloc"); return; }
|
|
|
|
+ if (strlen(path)>0) {
|
|
+ mysep[0] = DIRSEP;
|
|
+ mysep[1] = 0;
|
|
+ }
|
|
+ else {
|
|
+ mysep[0] = 0;
|
|
+ }
|
|
+
|
|
/* to build to extract path */
|
|
- if (strlen(path)>0) {
|
|
- sprintf(bigstr,"%s %s%c%s",MKDIR,path,DIRSEP,name);
|
|
- cdstr = bigstr+strlen(MKDIR)+1+strlen(path)+1;
|
|
- }
|
|
- else {
|
|
- sprintf(bigstr,"%s %s",MKDIR,name);
|
|
- cdstr = bigstr+strlen(MKDIR)+1;
|
|
- }
|
|
+ /* use double quotes around argument for paths with embedded spaces */
|
|
+ sprintf(bigstr,"%s \"%s%s%s",MKDIR,path,mysep,name);
|
|
+ bigsize = strlen(bigstr);
|
|
+ endMem = bigstr+bigsize;
|
|
+ cdstr = bigstr+strlen(MKDIR)+1+strlen(path)+strlen(mysep)+1;
|
|
+
|
|
/* the directory in which the file will be extracted */
|
|
- fullname = bigstr+strlen(MKDIR)+1;
|
|
+ fullname = bigstr+strlen(MKDIR)+1+1;
|
|
|
|
/* finds the filename, and separates it from the path */
|
|
filename = strrchr(bigstr,'/')+1;
|
|
filename[-1]='\0';
|
|
|
|
sepptr = cdstr;
|
|
- /* find the end of the first dir to create */
|
|
- while(sepptr[0]!='/' && sepptr[0]!='\0')
|
|
- sepptr++;
|
|
|
|
- while(strlen(cdstr)>0) {
|
|
+ BOOL found = TRUE;
|
|
+ while(found) {
|
|
+ /* find the end of the first dir to create */
|
|
+ while(sepptr[0]!='/' && sepptr[0]!='\0')
|
|
+ sepptr++;
|
|
if (sepptr[0]=='/') { /* not the last one */
|
|
sepptr[0]='\0';
|
|
- if (adfChangeDir(vol,cdstr)!=RC_OK)
|
|
- return;
|
|
- tfile = fopen(fullname,"r"); /* the only portable way to test if the dir exists */
|
|
- if (tfile==NULL) { /* does't exist : create it */
|
|
- if (!pflag) system(bigstr);
|
|
- if (!qflag) printf("x - %s%c\n",fullname,DIRSEP);
|
|
- }
|
|
- else
|
|
- fclose(tfile);
|
|
- sepptr[0] = DIRSEP; /* converts the '/' to '/' or '\' */
|
|
- cdstr = sepptr+1; /* next beginning of the next dir to create */
|
|
- /* to find the end of the next dir */
|
|
- sepptr++;
|
|
- while(sepptr[0]!='/' && sepptr[0]!='\0')
|
|
- sepptr++;
|
|
- }
|
|
- else { /* the last one */
|
|
- if (adfChangeDir(vol,cdstr)!=RC_OK)
|
|
- return;
|
|
- tfile = fopen(fullname,"r");
|
|
- if (tfile==NULL) {
|
|
- if (!pflag) system(bigstr);
|
|
- if (!qflag) printf("x - %s%c\n",fullname,DIRSEP);
|
|
- }
|
|
- else
|
|
- fclose(tfile);
|
|
- cdstr = cdstr+strlen(cdstr); /* at the end, ends the while loop */
|
|
- }
|
|
+ }
|
|
+ else
|
|
+ found = FALSE;
|
|
+
|
|
+
|
|
+ entry = findEntryInDir(vol, cdstr, &list);
|
|
+ if (!entry) {
|
|
+ fprintf(stderr, " subdir %s not found in dir list findEntryInDir\n", cdstr);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ printf("%4d/%02d/%02d %2d:%02d:%02d ",entry->year, entry->month, entry->days,
|
|
+ entry->hour, entry->mins, entry->secs);
|
|
+
|
|
+ if (adfChangeDir(vol,cdstr)!=RC_OK)
|
|
+ {
|
|
+ fprintf(stderr, " adfChangDir to subdir %s failed.\n", cdstr);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ trimCount = nukeIllegalWindowsTrailingChars(cdstr, endMem);
|
|
+ endMem -= trimCount;
|
|
+
|
|
+ n = spdhead;
|
|
+ spdhead = malloc(sizeof(struct saveParentDir));
|
|
+ spdhead->next = n;
|
|
+ spdhead->fullname = malloc(strlen(fullname)+1);
|
|
+ strcpy(spdhead->fullname, fullname);
|
|
+ spdhead->entry = entry;
|
|
+ spdhead->list = list;
|
|
+
|
|
+ tfile = fopen(fullname,"r"); /* the only portable way to test if the dir exists */
|
|
+ if (tfile==NULL) { /* does't exist : create it */
|
|
+ if (!pflag) {
|
|
+ int bsl = strlen(bigstr);
|
|
+ char saveEos = bigstr[bsl+1];
|
|
+ /* compensate for middle-string parsing */
|
|
+ bigstr[bsl] = '"';
|
|
+ bigstr[bsl+1] = 0;
|
|
+ system(bigstr);
|
|
+ bigstr[bsl] = 0;
|
|
+ bigstr[bsl+1] = saveEos;
|
|
+ }
|
|
+ if (!qflag)
|
|
+ printf("x - %s%c\n",fullname,DIRSEP);
|
|
+ }
|
|
+ else
|
|
+ fclose(tfile);
|
|
+
|
|
+ if (found) {
|
|
+ sepptr[0] = DIRSEP; /* converts the '/' to '/' or '\' */
|
|
+ cdstr = ++sepptr; /* next beginning of the next dir to create */
|
|
+ }
|
|
}
|
|
- extractFile(vol, filename, fullname, extbuf, pflag, qflag);
|
|
+ }
|
|
+ entry = findEntryInDir(vol, filename, &list);
|
|
+ if (entry) {
|
|
+ if (entry->type==ST_FILE)
|
|
+ extractFile(vol, filename, fullname, extbuf, pflag, qflag, entry);
|
|
+ else
|
|
+ fprintf(stderr, "file %s found but type not ST_FILE.\n", filename);
|
|
+ }
|
|
+ else {
|
|
+ fprintf(stderr, "file %s not found.\n", filename);
|
|
+ }
|
|
+
|
|
+ adfFreeDirList(list);
|
|
|
|
- free(bigstr);
|
|
+ while(spdhead) {
|
|
+ n = spdhead;
|
|
+ if (n->entry->type==ST_DIR)
|
|
+ setFileDateTime(n->fullname, n->entry);
|
|
+ free(n->fullname);
|
|
+ adfFreeDirList(n->list);
|
|
+ spdhead = spdhead->next;
|
|
+ free(n);
|
|
}
|
|
|
|
+ if (bigstr)
|
|
+ free(bigstr);
|
|
+
|
|
|
|
}
|
|
|
|
@@ -397,9 +575,12 @@
|
|
files = rtfiles = NULL;
|
|
volNum = 0;
|
|
|
|
- fprintf(stderr,"unADF v%s : a unzip like for .ADF files, powered by ADFlib (v%s - %s)\n\n",
|
|
+ fprintf(stderr,"\n\nunADF v%s : a unzip like for .ADF files, powered by ADFlib (v%s - %s)\n\n",
|
|
UNADF_VERSION, adfGetVersionNumber(),adfGetVersionDate());
|
|
|
|
+ fprintf(stderr,"Note: for windows compatibility, during extraction, dates with years before 1980 are set to 1980,\n");
|
|
+ fprintf(stderr," and directory and file names ending in \" \" or \".\" are trimmed.\n\n");
|
|
+
|
|
/* parse options */
|
|
i=1;
|
|
while(i<argc) {
|
|
@@ -438,13 +619,19 @@
|
|
break;
|
|
case 'd':
|
|
if (devname!=NULL && xflag && (i+1)==(argc-1)) {
|
|
+ char sysbuf[200];
|
|
i++;
|
|
dirname = argv[i];
|
|
if (dirname[strlen(dirname)-1]==DIRSEP)
|
|
dirname[strlen(dirname)-1]='\0';
|
|
nextArg = TRUE;
|
|
dflag = TRUE;
|
|
- }
|
|
+ /* as a convenience to the user, create the -d output dir if it doesn't exist */
|
|
+ /* use double quotes around argument for paths with embedded spaces */
|
|
+ sprintf(sysbuf,"%s \"%s\"",MKDIR,dirname);
|
|
+ if (!pflag)
|
|
+ system(sysbuf);
|
|
+ }
|
|
break;
|
|
case 'p':
|
|
if (xflag) {
|