campo-sirio/include/archives.cpp

565 lines
16 KiB
C++
Raw Normal View History

#define STRICT
#include <windows.h>
#include <direct.h>
#include <al.h>
#include <archives.h>
#include <config.h>
#include <isam.h>
#include <mask.h>
#include <prefix.h>
#include <progind.h>
#include <urldefid.h>
#include <utility.h>
///////////////////////////////////////////////////////////
// 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
TString256 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, 32);
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 <p pr_set> 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);
TString256 title("Archiviazione di "); title << name;
TProgress_win w(title, this);
ALEntryList list(w.monitor());
_arc->AddWildCardFiles(list, "*.*");
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 <p pr_set> 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);
TProgress_win w("Ripristino", this);
ALEntryList list(w.monitor());
_arc->ReadDirectory(list);
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_NT
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;
}