#include #include #define XVT_INCL_NATIVE #define STRICT #include #include #include #include #include #include #include #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); prev.ext(format("%03d", disk-1)); // File precedente bool first = TRUE; do { if (first) { message_box("Inserire il disco %d nel drive %c:", disk, floppy); 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 (fexist(prev)); // Non facciamo i furbetti! name.ext(format("%03d", disk)); // 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; } 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 char* dir = firm2dir(ditte.get_long("CODDITTA")); if (fexist(dir)) fl.add(dir); } TFilename name(firm2dir(-1)); // __ptprf name.add("config"); // Aggiungi configurazioni if (fexist(name)) 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 { if (firm < 0) // Crea lista automaticamente { TFilename name("a:/backup.ini"); name[0] = floppy; TConfig ini(name); const int max = ini.list_paragraphs(fl); // Lista degli archivi for (int i = max-1; i >= 0; i--) { const int disk = ini.get_int("Disk", fl.row(i)); if (disk == 1) { firm = atol(fl.row(i)); fl.add(firm2dir(firm), i); // Aggiungi gli archivi che iniziano qui } else fl.destroy(i, TRUE); // Elimina gli archivi che non iniziano qui } name = firm2dir(-1); // __ptprf name.add("config"); // Aggiungi configurazioni fl.add(name); } else { fl.destroy(); fl.add(firm2dir(firm)); // Inserisci solo una ditta (o COM) } return fl.items(); } // @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 spezare 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); 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 (fexist(ini)) { 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) break; TConfig c(ini, parag); const char* oggi = TDate(TODAY).string(); c.set("Size", tot , NULL, TRUE); c.set("Disk", disk, NULL, TRUE); c.set("Description", desc, NULL, TRUE); c.set("Date", oggi, NULL, TRUE); 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 (fexist(ini)) { 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 bool pr_set) // @parm Se TRUE setta il prefix come vuoto (default TRUE) // @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()); if (pr_set) prefix().set(NULL); xvt_fsys_save_dir(); chdir(dir); const TFilename d(dir); const TString16 name(d.name()); TFilename work; work.tempdir(); work.add(name); work.ext("gal"); _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_restore_dir(); if (pr_set) prefix().set(old); return ok; } bool TArchive::backup(long firm, char floppy, const char* desc, bool pr_set) { 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, pr_set); 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 bool pr_set) // @parm Se TRUE setta il prefix come vuoto (default TRUE) // @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(); 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()); if(pr_set) 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(); if(pr_set) prefix().set(old); return ok; } bool TArchive::restore(long firm, char floppy, bool temp, bool pr_set) { 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 = restore(fl.row(f), floppy, temp, pr_set); if (!ok) break; } 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) { 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); #if XVT_OS == XVT_OS_WIN || XVT_OS == XVT_OS_WIN32 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); #endif } 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; }