/* ============================================================= */ /* Rob Hamerling's MAXIMUS download file scan and sort utility. */ /* -> Functions to collect download file information. */ /* ============================================================= */ #define INCL_BASE #include #include "downsort.h" #include #include #include #include #include #include #include #include #include /* ---------------------------- */ /* Collect download file area's */ /* ---------------------------- */ USHORT collect_down(area) struct _downpath **area; // pointer to area-info pointer array { USHORT af,oaction; // file handle, open_action int i,j,m,rc; // counters, returncode unsigned int k; // #area's union _areamax u; // MAXIMUS area-file record(s) struct _downpath *d; // ptrs to array of area-info struct stat fs; // file status buffer rc = DosOpen(areadat_path, // Open 'carefully' &af, // pointer to File Handle &oaction, // pointer to action field 0L, // new filesize (N/A) FILE_NORMAL, // attributes FILE_OPEN, // open flags OPEN_ACCESS_READONLY | // access flags OPEN_SHARE_DENYWRITE | OPEN_FLAGS_RANDOMSEQUENTIAL | OPEN_FLAGS_NOINHERIT, 0L); // reserved if (rc != NO_ERROR) { // open error printf(OPEN_FAIL,areadat_path); exit(rc); } if (oaction != FILE_EXISTED) { // not found printf(OPEN_FAIL,areadat_path); exit(5); } else { if (oper_mode == VERBOSE) printf("\nReading file-area information from %s",areadat_path); stat(areadat_path,&fs); // get status of AREA.DAT read(af,(char *)&u,sizeof(struct _area)); // obtain first record if (u.a.id == AREA_id) { MAX_level = 102; // looks like version 1.02 k = (int)(fs.st_size / u.a.struct_len); } else if (u.a1.struct_len == sizeof(struct _area100)) { MAX_level = 100; // looks like version 1.00 k = (int)(fs.st_size / u.a1.struct_len); } else { printf("\nSorry, unsupported format of %s-file!",areadat_path); printf("\n%s %d.%d%c works for %s version 1.00 and 1.02!", PROGNAME,VERSION,SUBVERS,SUFFIX,MAX); exit(8); // wrong version of AREA.DATA } d = (struct _downpath *)calloc(k,sizeof(struct _downpath)); if (d == NULL) { // memory not obtained? printf(MSG_MEM,PROGNAME); exit(6); } else { *area = d; // return pointer to caller for (i=0,m=0; i0 && d[m-1].pname[j-1] != '\\') d[m-1].pname[j] = '\\'; // add backslash if needed } } DosClose(af); // close area.dat-file return(m); // report number of downloadarea's } } /* ---------------------------- */ /* Collect all file information */ /* ---------------------------- */ USHORT collect_file(m,area) USHORT m; // number of download area's struct _downpath *area; // pointer to download path array { unsigned int i,k,fc; // counters struct _filechain *ca,*ce; // ptrs to file info ca = NULL; // empty chain! fc = 0; // total file-counter for (i=0; i 0) { // any files in this area? if (first_element == NULL) first_element = ca; // pointer to very first get_desc(k,ca,&area[i]); // obtain descriptions fc += k; // total counter } ca = ce; // for next area } return(fc); } /* ---------------------------------------- */ /* Add all subdir-filenames to the chain, */ /* for further processing by mainline. */ /* NOTE: full path name assumed! */ /* ---------------------------------------- */ USHORT fill_chn(parea,cp,cq) struct _downpath *parea; // pointer to download-info struct _filechain **cp,**cq; // ptrs to ptr first/last element { int rc; // returncode of DOS-calls USHORT fc; // area-file counter struct _filechain *ca,*ce,*tp; // new curr temp chain pointers struct _FILEFINDBUF cf; // OS file-info buffer char down_spec[MAXPATH]; // file specification buffer HDIR fhandle; // FindFirst/Last handle USHORT fentries; // # entries to be retrieved fc = 0; // init filecount of this area ce = ca = *cp; // ptr to last active element strcpy(down_spec,parea->pname); // path strcat(down_spec,"*.*"); // file-spec fentries = 1; // one at a time! fhandle = HDIR_CREATE; // new file handle // #define FILE_NORMAL 0 // not defined in TOOLKIT 1.1 rc = DosFindFirst(down_spec,&fhandle,FILE_NORMAL,&cf, sizeof(struct _FILEFINDBUF),&fentries,0L); while (rc == 0) { if ((wild_comp(0,cf.achName,"FILES.?BS") != 0) && (wild_comp(0,cf.achName,"*.BAK") != 0) && (wild_comp(0,cf.achName,"SYSTEM*.?BS") != 0) && (wild_comp(0,cf.achName,"DIR.?BS") != 0)) { tp = (struct _filechain *)malloc(sizeof(struct _filechain)); if (tp == NULL) { printf(MSG_MEM,PROGNAME); // not enough memory exit(11); } if (ca == NULL) // very first element ca = ce = tp; // ptr to first and last active! else { // not very first if (fc == 0) // first in this area ca = tp; // ptr to first active this area ce->next_element = tp; // chain-ptr in current element ce = tp; // ptr to last active } ++fc; // update filecount this area ce->next_element = NULL; // copy/init fields ce->parea = parea; ce->wdate = cf.fdateLastWrite; ce->wtime = cf.ftimeLastWrite; if (file_time(cf.fdateCreation,cf.ftimeCreation) > file_time(cf.fdateLastWrite,cf.ftimeLastWrite) ) { ce->cdate = cf.fdateCreation; // creation most recent ce->ctime = cf.ftimeCreation; } else { // otherwise and non-HPFS volumes ce->cdate = cf.fdateLastWrite; ce->ctime = cf.ftimeLastWrite; } ce->size = cf.cbFile; byte_count += cf.cbFile; ce->attr = cf.attrFile; ce->priv = HIDDEN; // unless FILES.BBS proves otherwise strncpy(ce->fname,cf.achName,MAXFN); ce->fdesc = NULL; // unless later found in FILES.BBS } rc = DosFindNext(fhandle,&cf,sizeof(struct _FILEFINDBUF),&fentries); } DosFindClose(fhandle); // close directory association *cp = ca; // pointer to first new this area *cq = ce; // pointer to last new this area return(fc); } /* ------------------------------ */ /* Add file description to chain */ /* ------------------------------ */ void get_desc(x,cp,parea) int x; // number of file-entries struct _filechain *cp; // ptr to ptr to first of group struct _downpath *parea; // pointer to area-info { FILE *fi; // file pointer USHORT fih,oaction; // file handle, open-action struct _filechain *ce; // ptrs to file-info char buf[MAXRCD]; // read-buffer for FILES.BBS char filename[MAXFN]; // filename from FILES.BBS buf char *desc,*rp; // ptr to desc / return val gets() char buf2[MAXDESC]; // cumulated (multiline) desc. int b,i,j,k,m,n,p; // counters int low,high,index; // indexes int fpriv, rc; // file privilege, returncode char desc_spec[MAXPATH]; char *fd; // pointer to file description struct _filechain **fa; // pointer to file sort-array static char prop[4] = "/Ä\\|"; // rotating propeller if (strlen(parea->filesbbs) > 0) // explicit specification? strcpy(desc_spec,parea->filesbbs); // explicitly specified FileList else { // no strcpy(desc_spec,parea->pname); // get path to download directory strcat(desc_spec,lp[P_FIL].name); // add filename strcat(desc_spec,"."); // add separator strcat(desc_spec,lp[P_FIL].ext); // add extension } fpriv = parea->priv; // area-priv is default file priv // FILES.BBS may be in use!!! rc = DosOpen(desc_spec, // Open 'carefully' &fih, // pointer to File Handle &oaction, // pointer to action field 0L, // new filesize (N/A) FILE_NORMAL, // attributes FILE_OPEN, // open flags OPEN_ACCESS_READONLY | // access flags OPEN_SHARE_DENYNONE | OPEN_FLAGS_SEQUENTIAL | OPEN_FLAGS_NOINHERIT, 0L); // reserved if (rc != NO_ERROR || oaction != FILE_EXISTED) { // not found printf("\n Description file %s not found,",desc_spec); return; // no: return to caller } if ((fi = fdopen(fih,"r")) == NULL) { // open stream with file handle printf("\n Description file %s not found,",desc_spec); return; // no: return to caller } fa = (struct _filechain **)malloc(x*sizeof(struct _filechain *)); if (fa == NULL) { // not enough memory printf(MSG_MEM,PROGNAME); exit(11); } ce = cp; // ptr to first file-info for (i=0; inext_element; } qsort(fa,x,sizeof(struct _filechain *),sort_gbl); // sort file pointers rp = fgets(buf,sizeof buf,fi); // get first record while (rp != NULL) { // until end of file reached m = strlen(buf); // length of input string if (buf[0] == '\20') { // privilege change (^P?) for (k=0; k parea->priv) // only higher accepted fpriv = TWIT + k; // new (higher) prilivege rp = fgets(buf,sizeof buf,fi); // continue } else if ( buf[0] <= ' ' || buf[0] == '\"' || (buf[0] >= '+' && buf[0] <= '/') || (buf[0] >= ':' && buf[0] <= '>') || (buf[0] >= '[' && buf[0] <= ']') || buf[0] == '|' || buf[0] >= 128) // non-filename: ignore line rp = fgets(buf,sizeof buf,fi); // continue else { // probably file descr record for (i=0; i < MAXFN-1 && // maximum filename length (8.3) i < m && // input string length buf[i] != ' ' && buf[i] != '\n'; i++); // scan for filespec strncpy(filename,buf,i); // save filename filename[i] = '\0'; // end of string desc = next_word(buf); // locate description if (desc != NULL) { // start of description found for (k=0; desc[k]; ++k) if (desc[k]=='\r' || desc[k]=='\n') { desc[k] = '\0'; break; } strcpy(buf2,desc); // save desc in buf2 while (((rp = fgets(buf,sizeof buf,fi)) != NULL) && // next rcd (buf[0] == ' ') && // probably desc continuation ((desc = next_word(buf)) != NULL)) { // locate desc for (k=0; desc[k]!='\0'; ++k) if (desc[k]=='\r' || desc[k]=='\n') { desc[k] = '\0'; break; } if ((strlen(buf2) + k + 1) <= sizeof(buf2)) { // not too long strcat(buf2," "); // single space strcat(buf2,desc); // concat desc to buf2 } } fd = malloc(strlen(buf2)+1); // obtain memory if (fd == NULL) { printf(MSG_MEM,PROGNAME); // not enough memory exit(12); } else strcpy(fd,buf2); // store description } else rp = fgets(buf,sizeof buf,fi); // no desc: continue j = 0; // first wild-compare low = 0; // index of first entry high = x-1; // index of last entry while (low <= high) { // binary search in array index = (high + low) / 2; // middle of interval if ((b = wild_comp(j,fa[index]->fname,filename)) < 0) low = index + 1; // new low boundary else if (b > 0) high = index - 1; // new high boundary else break; // equal: found j = 1; // subsequent wild-compares } n = index; while (n>=0 && wild_comp(0,fa[n]->fname,filename) == 0) { if (fa[n]->fdesc == NULL) // no description assigned yet fa[n]->fdesc = (desc) ? fd : NDS; // ptr to description fa[n]->priv = fpriv; // copy privilege --n; // next lower } n = index + 1; while (nfname,filename) == 0) { if (fa[n]->fdesc == NULL) // no description assigned yet fa[n]->fdesc = (desc) ? fd : NDS; // ptr to description fa[n]->priv = fpriv; // copy privilege ++n; // next higher } } if (oper_mode == VERBOSE) cprintf("\r%c",prop[p=(++p)&3]); // propeller } if (oper_mode == VERBOSE) cprintf("\r "); // clear propeller free(fa); // free temp sort array fclose(fi); // finished with this FILES.BBS DosClose(fih); // close the handle } /* ------------------------------ */ /* Build pointer-array for sorts */ /* ------------------------------ */ struct _filechain **prep_sort(cnt,chn) USHORT cnt; // file count struct _filechain *chn; // pointer to fileinfo struct { USHORT i; // counter struct _filechain **dm; // pointer to file-sort array struct _filechain *ca; // pointer to fileinfo (chain) dm = (struct _filechain **)malloc(cnt*sizeof(struct _filechain *)); if (dm == NULL) { // not enough memory printf(MSG_MEM,PROGNAME); exit(11); } ca = chn; // ptr to first file-info for (i=0; ca != NULL; i++) { // init sort array dm[i] = ca; ca = ca->next_element; } return(dm); }