#include #if XVT_OS == XVT_OS_WIN #define XVT_INCL_NATIVE #define STRICT #endif #include #include #include #include #include #include #include #include #include #include #include #if XVT_OS == XVT_OS_WIN #include /////////////////////////////////////////////////////////// // TProgress_win declaration /////////////////////////////////////////////////////////// class TProgress_win : public TMask { ALWindowsMessage* _monitor; TArchive* _arc; protected: static bool cancel_handler(TMask_field&, KEY k); public: ALWindowsMessage* monitor() const { return _monitor; } TProgress_win(const char* title, TArchive* = NULL); ~TProgress_win(); }; /////////////////////////////////////////////////////////// // TArchive /////////////////////////////////////////////////////////// // @doc EXTERNAL // @mfunc Funzione per richiedere all'utente il dischetto e per controllare la // corretta sequenza dei dischetti da inserire // // @rdesc Ritorna il puntatore al file presente (o meno) sul dischetto FILE* TArchive::ask_disk( TFilename& name, // @parm Nome del file da creare/cercare su disco int disk, // @parm Numero progressivo del set char floppy, // @parm Drive sul quale effettuare l'operazione (A, B, C, ...) bool lettura) const // @parm Indica il modo di apertura del file: // // @flag TRUE | Apre il file in lettura // @flag FALSE | Apre il file in scrittura { TFilename prev(name); TString16 ext; ext.format("%03d", disk-1); prev.ext(ext); // File precedente bool first = TRUE; do { if (first) { message_box("Inserire il disco %d nel drive %c:\n" "File '%s'", disk, floppy, (const char*)prev.name()); first = FALSE; } else { const bool ok = yesno_box("Inserire il disco %d nel drive %c\n" "Estrarre il disco %d e continuare?", disk, floppy, disk-1); if (!ok) return NULL; } } while (prev.exist()); // Non facciamo i furbetti! ext.format("%03d", disk); name.ext(ext); // File attuale FILE* f = NULL; bool retry = TRUE; while (retry) { f = fopen(name, lettura ? "rb" : "wb"); if (f == NULL) retry = yesno_box("Il file %s non e' accessibile: riprovare?", (const char*)name); else { setvbuf(f, NULL, _IOFBF, BUFSIZE); retry = FALSE; } } return f; } #endif long TArchive::fsize(FILE* f) const { CHECK(f, "Can't measure NULL file"); fseek(f, 0, SEEK_END); const long s = ftell(f); fseek(f, 0, SEEK_SET); return s; } int TArchive::build_backup_list(long firm, TString_array& fl) const { fl.destroy(); if (firm < 0L) { fl.add(firm2dir(0L)); TLocalisamfile ditte(LF_NDITTE); for (int err = ditte.first(); err == NOERR; err = ditte.next()) { const long cod = ditte.get_long("CODDITTA"); if (prefix().exist(cod)) { TFilename dir = firm2dir(cod); fl.add(dir); } } TFilename name(firm2dir(-1)); // __ptprf name.add("config"); // Aggiungi configurazioni if (name.exist()) fl.add(name); } else fl.add(firm2dir(firm)); return fl.items(); } // @doc EXTERNAL // @mfunc Costruisce la lista delle directory da scompattare // // @rdesc Ritorna il numero di direttori da ripristinare int TArchive::build_restore_list( long firm, // @parm Ditta di cui effettuare il salvataggio char floppy, // @parm Floppy su cui effettuare il backup TString_array& fl) const // @parm Nomi dei direttori da ripristinare { fl.destroy(); if (firm < 0) // Crea lista automaticamente { TFilename name("a:/backup.ini"); name[0] = floppy; TConfig ini(name); TString_array pl; const int max = ini.list_paragraphs(pl); // Lista degli archivi for (int i = 0; i < max; i++) { const TString& name = pl.row(i); const int disk = ini.get_int("Disk", name); if (disk == 1) { if (name == "config") { TFilename fn(firm2dir(-1)); // __ptprf fn.add(name); // Aggiungi configurazioni fl.add(fn); } else { firm = atol(name); fl.add(firm2dir(firm)); // Aggiungi gli archivi che iniziano qui } } } } else { fl.add(firm2dir(firm)); // Inserisci solo una ditta (o COM) } return fl.items(); } #if XVT_OS == XVT_OS_WIN // @doc EXTERNAL // @mfunc Spezza il file in modo da farlo stare sul dischetto // // @rdesc Ritorna se e' riuscito a spezzare il file bool TArchive::fsplit( const char* filename, // @parm Nome del file da spezzare char floppy, // @parm Floppy su cui scaricare il file const char* desc) const // @parm Descrizione dell'archivio { const TFilename from(filename); // File da splittare FILE* i = fopen(from, "rb"), *o = NULL; if (i == NULL) return error_box("Impossibile aprire il file '%s'", from); setvbuf(i, NULL, _IOFBF, BUFSIZE); const long tot = fsize(i); long scritti = 0; TFilename work; work << floppy << ":/" << from.name(); // File su dischetto TString msg("Archiviazione di "); msg << work << " (" << (tot/1024) << "K)"; TProgind w(tot, msg, TRUE, TRUE, 40); if (!os_test_disk_free_space(work, tot)) { TString16 dev("A:/*.*"); dev[0] = floppy; // TString_array dir; if (list_files(dev, dir) > 0) { warning_box("Il file %s non puo' essere contenuto per intero nel dischetto corrente:\n" "Accertarsi di aver inserito un dischetto formattato e completamente vuoto prima di continuare.", (const char*)from.name()); } } int disk = 0; TString buffer(BUFSIZE); bool ok = TRUE; while (ok) { const size_t letti = fread((char*)(const char*)buffer, 1, BUFSIZE, i); if (o != NULL) ok = (letti > 0) ? (fwrite((char*)(const char*)buffer, letti, 1, o) == 1) : TRUE; else ok = FALSE; if (!ok) { if (o != NULL) { chsize(fileno(o),scritti); // Must truncate output file or some information will be rewritten on next disk! scritti = 0; // Reset count bytes written to disk. fclose(o); } o = ask_disk(work, ++disk, floppy, FALSE); ok = o != NULL; if (ok) { TFilename parag(work.name()); parag.ext(""); TFilename ini("a:/backup.ini"); ini[0] = floppy; if (ini.exist()) { TConfig c(ini, parag); const int d = c.get_int("Disk"); if (d == disk) { ok = yesno_box("Il disco %d contiene gia' un backup del direttorio %s del %s" "\nSi desidera continuare?", disk, (const char*)parag, (const char*)c.get("Date")); } } else { FILE* i = fopen(ini, "w"); // Crea il file backup.ini per evitare messaggi fclose(i); } if (ok) { TConfig c(ini, parag); const char* oggi = TDate(TODAY).string(); c.set("Date", oggi); c.set("Description", desc); c.set("Disk", disk); c.set("Size", tot); } else break; ok = (letti > 0) ? (fwrite((char*)(const char*)buffer, letti, 1, o) == 1) : TRUE; if (!ok) error_box("Impossibile scrivere i dati sul dischetto"); else scritti +=letti; } } else scritti += letti; w.addstatus(letti); if (ok) ok = !w.iscancelled(); if (letti < BUFSIZE) break; } fclose(i); if (o != NULL) fclose(o); return ok; } // @doc EXTERNAL // @mfunc Ricostruisce il file spezzato // // @rdesc Ritorna se e' riuscito a ricostruire il file bool TArchive::fbuild( const char* filename, // @parm Nome del file da ricostrutire char floppy) const // @parm Floppy da cui recupare i pezzi del file { const TFilename work(filename); FILE* o = fopen(work, "wb"), *i = NULL; if (o == NULL) return error_box("Impossibile creare il file '%s'", (const char*)work); setvbuf(o, NULL, _IOFBF, BUFSIZE); long totale = 0L; // Bytes letti long max = 1440000L; // Bytes da leggere TFilename name; // Nome del file su dischetto name << floppy << ":/" << work.name(); TString256 msg("Ripristino da "); msg << name; TProgind w(max, msg, TRUE, TRUE, 40); int disk = 0; TString buffer(BUFSIZE); bool ok = TRUE; while (ok) { size_t letti = 0; if (i != NULL) { letti = fread((char*)(const char*)buffer, 1, BUFSIZE, i); ok = letti > 0; } else ok = FALSE; if (!ok) // Richiedi nuovo disco { if (i != NULL) fclose(i); i = ask_disk(name, ++disk, floppy, TRUE); ok = i != NULL; if (ok) { if (disk == 1) { TFilename ini("a:/backup.ini"); ini[0] = floppy; if (ini.exist()) { TFilename parag(name.name()); parag.ext(""); TConfig c(ini, parag); max = c.get_long("Size"); } else ok = yesno_box("Manca il file %s: continuare ugualmente?", (const char*)ini); } w.setmax(max); if (ok) // Leggi primo blocco di bytes { letti = fread((char*)(const char*)buffer, 1, BUFSIZE, i); ok = letti > 0; } } } if (ok) // La lettura e stata fatta bene { ok = fwrite((char*)(const char*)buffer, 1, letti, o) == letti; if (ok) { w.addstatus(letti); totale += letti; ok = !w.iscancelled(); } else error_box("Impossibile scrivere i dati sul file %s", (const char*)work); } if (!ok || totale == max) // Esci in caso di errore o se hai finito break; } fclose(o); if (i != NULL) fclose(i); return ok; } // @doc EXTERNAL // @mfunc Effettua il backup della ditta o della directory // // @rdesc Ritorna il risultato dell'operazione bool TArchive::backup( const char* dir, // @parm Directory di cui effettuare il backup char floppy, // @parm Floppy su cui effettuare il backup const char* desc) // @parm Descrizione da assegnare al backup // @syntax bool backup(const char* dir, char floppy, const char* desc, bool pr_set); // @syntax bool backup(long firm, char floppy, const char* desc, bool pr_set); // @comm Il parametro

e' utilizzato per evitare errori di riaperture di files. { const TString16 old(prefix().name()); prefix().set(NULL); DIRECTORY curdir; xvt_fsys_get_dir(&curdir); chdir(dir); const TFilename d(dir); const TString16 name(d.name()); TFilename work; work.tempdir(); work.add(name); work.ext("gal"); // Cancella eventuali gal residui TString_array gals; list_files("*.gal", gals); list_files("*.000", gals); for (int g = gals.items()-1; g >= 0; g--) ::remove(gals.row(g)); _arc = new ALArchive(work); TString title("Archiviazione di "); title << name; TProgress_win w(title, this); ALEntryList list(w.monitor()); _arc->AddWildCardFiles(list, "*.*", 1); w.open_modal(); _arc->Create( list ); w.close_modal(); bool ok = _arc->mStatus == AL_SUCCESS; if (ok) ok = fsplit(work, floppy, desc); else error_box("Compressione degli archivi errata o incompleta:\n%s", _arc->mStatus.GetStatusDetail()); delete _arc; _arc = NULL; remove(work); xvt_fsys_set_dir(&curdir); prefix().set(old); return ok; } bool TArchive::backup(long firm, char floppy, const char* desc) { TString_array fl; const int num_ditte = build_backup_list(firm, fl); bool ok = TRUE; for (int f = 0; f < num_ditte; f++) { ok = backup(fl.row(f), floppy, desc); if (!ok) break; } return ok; } // @doc EXTERNAL // @mfunc Effettua il restore della ditta o dell directory // // @rdesc Ritorna il risultato dell'operazione bool TArchive::restore( const char* dir, // @parm Directory di cui effettuare il restore char floppy, // @parm Floppy da cui leggere i dati bool tmp) // @parm Directory temporanea da utilizzare // @syntax bool restore(const char* dir, char floppy, bool temp, bool pr_set); // @syntax bool restore(long firm, char floppy, bool temp, bool pr_set); { TFilename work; if (tmp) work.tempdir(); else work = dir; TFilename output(dir); output = output.name(); output.ext("gal"); if (!yesno_box("Attenzione l'archivio sul disco %c: verra' ripristinato\n" "nel direttorio %s. Continuare?", floppy, (const char*)work)) return FALSE; xvt_fsys_save_dir(); bool ok = chdir(work) == 0; if (!ok) { ok = yesno_box("Non esiste il direttorio %s: si desidera crearlo?", (const char*)work); if (ok) { make_dir(work); ok = chdir(work) == 0; } if (!ok) return error_box("Impossibile accedere a %s", (const char*)work); } const TString16 old(prefix().name()); prefix().set(NULL); ok = fbuild(output, floppy); if (ok) { _arc = new ALArchive(output); TAssoc_array subdirs; // Array dei sottodirettori da creare TProgress_win w("Ripristino", this); ALEntryList list(w.monitor()); _arc->ReadDirectory(list); // Naviga attraverso l'archivio e compone l'array dei sottodirettori da creare ALEntry *entry = list.GetFirstEntry(); TFilename path; while (entry) { path = entry->mpStorageObject->mName; path = path.path(); if (path.not_empty() && subdirs.objptr(path) == NULL) // Se non c'e' lo aggiunge alla lista if (!fexist(path)) subdirs.add(path,path); entry = entry->GetNextEntry(); } // Scorre la lista dei sottodirettori da creare for (TFilename* p = (TFilename*)subdirs.first_item(); p != NULL; p = (TFilename*)subdirs.succ_item()) { p->rtrim(1); // Strip trailing / make_dir(*p); } w.open_modal(); _arc->Extract( list ); ok = _arc->mStatus == AL_SUCCESS; if (!ok) error_box("Ripristino degli archivi errato o incompleto:\n%s", _arc->mStatus.GetStatusString()); w.close_modal(); delete _arc; _arc = NULL; remove(output); } xvt_fsys_restore_dir(); prefix().set(old); return ok; } bool TArchive::restore(long firm, char floppy, bool temp) { bool lastdisk = firm >= 0; bool ok = TRUE; do { TString_array fl; const int num_ditte = build_restore_list(firm, floppy, fl); for (int f = 0; f < num_ditte; f++) { const TToken_string& code = fl.row(f); ok = restore(code, floppy, temp); if (ok) { if (!lastdisk) lastdisk = code.find("config") >= 0; } else break; } if (!lastdisk) { TFilename cfg("a:/config.001"); cfg[0] = floppy; if (!fexist(cfg)) lastdisk = !yesno_box("Si desidera procedere col prossimo disco di ripristino?\n" "(Rispondere NO se si desidera interrompere la procedura)"); } } while(!lastdisk); return ok; } void TArchive::stop_job() { if (_arc != NULL) _arc->GetStorageObject()->mStatus.SetError(AL_USER_ABORT, "Interrotto dall'utente"); } /////////////////////////////////////////////////////////// // TProgress_win implementation /////////////////////////////////////////////////////////// TProgress_win::TProgress_win(const char* title, TArchive* arc) : TMask(title, 1, 60, 6), _arc(arc), _monitor(NULL) { RCT rct; xvt_rect_set(&rct, CHARX, CHARY, 58*CHARX, 5*CHARY/2); WINDOW wtxt = xvt_ctl_create(WC_EDIT, &rct, "", win(), CTL_FLAG_DISABLED, (long)this, 101); xvt_rect_set(&rct, 28*CHARX, 3*CHARY, 33*CHARX, 9*CHARY/2); WINDOW wnum = xvt_ctl_create(WC_EDIT, &rct, "", win(), CTL_FLAG_DISABLED, (long)this, 102); add_button(DLG_USER, 0, "Cancel", -11, -1, 10, 2, "", BMP_CANCEL); set_handler(DLG_USER, cancel_handler); HWND txt = (HWND)xvt_vobj_get_attr(wtxt, ATTR_NATIVE_WINDOW); HWND num = (HWND)xvt_vobj_get_attr(wnum, ATTR_NATIVE_WINDOW); _monitor = new ALWindowsMessage(AL_MONITOR_OBJECTS, txt, AL_SEND_RATIO, num); } TProgress_win::~TProgress_win() { if (_monitor) delete _monitor; } bool TProgress_win::cancel_handler(TMask_field& f, KEY k) { if (k == K_SPACE) { TProgress_win& m = (TProgress_win&)f.mask(); if (m._arc != NULL) m._arc->stop_job(); } return TRUE; } #endif bool TArchive::move_file(const TFilename& file, const char* dir) const { TFilename dest(dir); dest.add(file.name()); long filesize = ::fsize(file); filesize -= ::fsize(dest); bool space_ok = filesize <= 0; while (!space_ok) { space_ok = ::os_test_disk_free_space(dest, filesize); if (!space_ok) { TString msg(128); msg << "Lo spazio sull'unita' e' insufficiente:\n"; if (::os_is_removable_drive(dest)) msg << "Inserire un nuovo disco e ritentare?"; else msg << "Liberare dello spazio e ritentare?"; if (!yesno_box(msg)) return FALSE; } } bool write_ok = TRUE; bool user_abort = FALSE; do { write_ok = ::fcopy(file, dest); if (write_ok) ::remove(file); else { if (!yesno_box("Errore di copia del file %s.\nSi desidera riprovare?", (const char*)file)) user_abort = TRUE; } } while (!write_ok && !user_abort); return write_ok; } bool TArchive::fsplit_zip( const char* filename, // @parm Nome del file da spezzare char floppy, // @parm Floppy su cui scaricare il file const char* desc) const // @parm Descrizione dell'archivio { const TFilename archive(filename); unsigned long size = 0; TFilename path; path << floppy << ':'; while (size <= 0) { message_box("Inserire il disco 1 nel drive %c:", floppy); size = os_get_disk_size(path) - (64L*1024L); if (size <= 0) { if (!yesno_box("Errore di accesso al drive %c\nSi desidera ritentare?", floppy)) return FALSE; } do_events(); } const long minsize = 360*1024L; if (size < minsize) size = minsize; // Costruisce percorso dello splitter TFilename cmd("zipsplit.pif"); cmd << " -n " << (long)size << " -b " << archive.path() << ' ' << archive; // Esegue lo splitter nella directory temporanea TExternal_app app(cmd); int err = app.run(FALSE, FALSE, FALSE, FALSE); if (err != NOERR) return error_box("Errore %d durante lo splitting del file %s", err, (const char*)archive); size = ::fsize(archive); ::remove(archive); for (int d = 1; ; d++) { TFilename src(archive); src.ext(""); src << d; src.ext("zip"); if (src.exist()) { if (d > 1) { message_box("Inserire il disco %d nel drive %c:", d, floppy); do_events(); } if (move_file(src, path)) { TFilename ini(path); ini.add("backup.ini"); TConfig c(ini, archive.name()); c.set("Size", size); c.set("Disk", d); c.set("Description", desc); c.set("Date", TDate(TODAY).string()); } else break; } else break; } return TRUE; } const char* const file[] = { "zip.pif", "zip386.bat", "zip386.exe", "ziplist.txt", NULL }; bool TArchive::copy_zipper(const char* dir) const { bool ok = TRUE; TFilename dest; for (int f = 0; ok && file[f]; f++) { dest = dir; dest.add(file[f]); ok &= ::fcopy(file[f], dest); } return ok; } bool TArchive::remove_zipper(const char* dir) const { TFilename dest; for (int f = 0; file[f]; f++) { dest = dir; dest.add(file[f]); ::remove(dest); } return TRUE; } void TArchive::add_zipper_list(TString& str) const { for (int f = 0; file[f]; f++) str << ' ' << file[f]; } // @doc EXTERNAL // @mfunc Effettua il backup della directory // // @rdesc Ritorna il risultato dell'operazione bool TArchive::zip( const char* dir, // @parm Directory di cui effettuare il backup char floppy, // @parm Floppy su cui effettuare il backup const char* desc) // @parm Descrizione da assegnare al backup // @parm long | firm | Ditta di cui effettuare il backup // @syntax bool backup(const char* dir, char floppy, const char* desc, bool pr_set); // @syntax bool backup(long firm, char floppy, const char* desc, bool pr_set); // @comm Il parametro

e' utilizzato per evitare errori di riaperture di files. { const TString16 old(prefix().name()); prefix().set(NULL); const TFilename workdir(dir); TString16 name(workdir.name()); // Trasforma com in datcom altrimenti lo splitter lo trasforma in com1 e com2! if (name.compare("com", -1, TRUE) == 0) name = "datcom"; // Nome del file compresso TFilename work; work.tempdir(); work.add(name); work.ext("zip"); TString title("Archiviazione di "); title << workdir; TIndwin waitw(100,title,FALSE,FALSE); TWait_cursor hourglass; // Crea il file con la lista dei file da comprimere const char* const ZIPLIST = "ziplist.txt"; FILE* flist = fopen(ZIPLIST, "w"); fprintf(flist, "*.*"); fclose(flist); copy_zipper(workdir); // Esegui lo zippatore TFilename cmd = workdir; cmd.add("zip.pif"); cmd << ' ' << work << ' ' << ZIPLIST << " -D -r"; TExternal_app zipapp(cmd); int err = zipapp.run(FALSE, FALSE, FALSE, FALSE); // Elimina files temporanei dallo zip /* cmd = workdir; cmd.add("zip386.exe"); cmd << ' ' << work << " -d"; add_zipper_list(cmd); TExternal_app zipdel(cmd); zipdel.run(FALSE, FALSE, FALSE, FALSE); */ // Elimina i file temporanei dalla directory remove_zipper(workdir); // Splitta su floppy bool ok = err == 0; if (ok) ok = fsplit_zip(work, floppy, desc); else error_box("Compressione degli archivi errata o incompleta"); prefix().set(old); return ok; } bool TArchive::zip(long firm, char floppy, const char* desc) { TString_array fl; const int num_ditte = build_backup_list(firm, fl); bool ok = TRUE; for (int f = 0; f < num_ditte; f++) { ok = zip(fl.row(f), floppy, desc); if (!ok) break; } return ok; } // @doc EXTERNAL // @mfunc Effettua il restore della directory // // @rdesc Ritorna il risultato dell'operazione bool TArchive::unzip( const char* dir, // @parm Directory di cui effettuare il restore char floppy, // @parm Floppy da cui leggere i dati bool tmp) // @parm Directory temporanea da utilizzare // @syntax bool restore(const char* dir, char floppy, bool temp, bool pr_set); // @syntax bool restore(long firm, char floppy, bool temp, bool pr_set); // @comm Il parametro

e' utilizzato per evitare errori di riaperture di files. { TFilename work; if (tmp) work.tempdir(); else work = dir; TFilename output(dir); output = output.name(); if (output.compare("com", -1, TRUE) == 0) output = "datcom"; output.ext("zip"); if (!yesno_box("Attenzione l'archivio %c:%s verra' ripristinato\n" "nel direttorio %s. Continuare?", floppy, (const char*)output, (const char*)work)) return FALSE; bool ok = work.exist(); if (!ok) { ok = yesno_box("Non esiste il direttorio %s: si desidera crearlo?", (const char*)work); if (ok) { make_dir(work); ok = work.exist(); } if (!ok) return error_box("Impossibile accedere a %s", (const char*)work); } TString title("Ripristino di "); title << output; TIndwin waitw(100,title,FALSE,FALSE); const TString16 old(prefix().name()); prefix().set(NULL); TFilename cfg; cfg << floppy << ':'; cfg.add("backup.ini"); TConfig c(cfg, output.name()); long total_size = c.get_long("Size"); long read_size = 0; for (int d = 1; read_size < total_size; d++) { TFilename src; src << floppy << ':' << SLASH << output.name(); src.ext(""); src << d << ".zip"; message_box("Inserire il disco %d contenente il file %s", d, (const char*)src); while (!src.exist()) { if (!yesno_box("Impossibile aprire il file %s:\nSi desidera ritentare?", (const char *)src)) break; } if (src.exist()) { TFilename cmd; cmd << "unzip.pif -o " << src << " -d " << work; TExternal_app app(cmd); int err = app.run(FALSE, FALSE, FALSE, FALSE); if (err == 0) read_size += ::fsize(src); else { error_box("Errore %d durante il ripristino del file %s", err, (const char*)src); break; } } else break; } prefix().set(old); return ok; } bool TArchive::unzip(long firm, char floppy, bool temp) { TString_array fl; const int num_ditte = build_restore_list(firm, floppy, fl); bool ok = TRUE; for (int f = 0; f < num_ditte; f++) { ok = unzip(fl.row(f), floppy, temp); if (!ok) break; } return ok; }