/*\ |*| Parity Archive - A way to restore missing files in a set. |*| |*| Copyright (C) 2001 Willem Monsuwe (willem@stack.nl) |*| |*| File format by Stefan Wehlus - |*| initial idea by Tobias Rieper, further suggestions by Kilroy Balore |*| |*| This file holds an interface abstraction, |*| to be called by different user interfaces. \*/ #include "interface.h" #include "par.h" #include "rwpar.h" #include "backend.h" #include "util.h" #include "fileops.h" #include #include static pfile_t *volumes = 0, *files = 0; static sub_t *sub = 0; extern hfile_t *hfile; /*\ Get the current flags |*| Returns: Current flags \*/ int par_flags(void) { int ret = 0; if (cmd.move) ret |= PARFLAG_MOVE; if (cmd.usecase) ret |= PARFLAG_CASE; if (cmd.ctrl) ret |= PARFLAG_CTRL; if (cmd.keep) ret |= PARFLAG_KEEP; return ret; } /*\ Set some flags |*| Returns: Current flags \*/ int par_setflags(int flags) { if (flags & PARFLAG_MOVE) cmd.move = 1; if (flags & PARFLAG_CASE) cmd.usecase = 1; if (flags & PARFLAG_CTRL) cmd.ctrl = 1; if (flags & PARFLAG_KEEP) cmd.keep = 1; return par_flags(); } /*\ Set some flags |*| Returns: Current flags \*/ int par_unsetflags(int flags) { if (flags & PARFLAG_MOVE) cmd.move = 0; if (flags & PARFLAG_CASE) cmd.usecase = 0; if (flags & PARFLAG_CTRL) cmd.ctrl = 0; if (flags & PARFLAG_KEEP) cmd.keep = 0; return par_flags(); } /*\ Add a PARfile to the current parlist. |*| filename: Name of file to load \*/ int par_load(u16 *filename) { pfile_t *p, **pp; par_t *par; if (!filename) return PAR_ERR_INVALID; par = read_par_header(filename, 1, 0, 0); if (!par) return PAR_ERR_ERRNO; for (p = volumes; p; p = p->next) { if (!unicode_cmp(p->filename, par->filename)) { free_par(par); return PAR_ERR_ALREADY_LOADED; } } CNEW(p, 1); p->match = find_file_name(par->filename, 0); p->vol_number = par->vol_number; p->file_size = par->data_size; if (par->files) p->fnrs = file_numbers(&files, &par->files); p->f = par->f; p->filename = unicode_copy(par->filename); par->f = 0; free_par(par); /*\ Insert in alphabetically correct place \*/ for (pp = &volumes; *pp; pp = &((*pp)->next)) if (unicode_gt((*pp)->filename, filename)) break; p->next = *pp; *pp = p; return PAR_OK; } /*\ Search for additional PARfiles matching the current ones |*| partial: Load files that only match partially. \*/ int par_search(int partial) { find_par_files(&volumes, &files, partial); return PAR_OK; } /*\ Remove a PARfile from the current parlist. |*| entry: Name of file to remove \*/ int par_unload(u16 *entry) { pfile_t *p, **pp; for (pp = &volumes; *pp; pp = &((*pp)->next)) { if ((*pp)->filename == entry) { p = *pp; *pp = p->next; if (p->f) file_close(p->f); if (p->fnrs) free(p->fnrs); free(p->filename); free(p); return PAR_OK; } } return PAR_ERR_EXIST; } /*\ List the current PARfiles |*| Returns: Array of filenames, NULL-terminated. |*| Notes: Caller should free() returned array. \*/ u16 ** par_parlist(void) { u16 **ret; pfile_t *p; int n; for (n = 0, p = volumes; p; p = p->next) n++; CNEW(ret, n + 1); for (n = 0, p = volumes; p; p = p->next, n++) ret[n] = p->filename; ret[n] = 0; return ret; } /*\ List the current filelist |*| Returns: Array of filenames, NULL-terminated. |*| Notes: Caller should free() returned array. \*/ u16 ** par_filelist(void) { u16 **ret; pfile_t *p; int n; for (n = 0, p = files; p; p = p->next) n++; CNEW(ret, n + 1); for (n = 0, p = files; p; p = p->next, n++) ret[n] = p->filename; ret[n] = 0; return ret; } /*\ Check the MD5 sum of a file |*| entry: file to check \*/ int par_check(u16 *entry) { pfile_t *p; for (p = files; p; p = p->next) { if (p->filename == entry) { if (find_file(p, 0)) return PAR_OK; return PAR_ERR_CORRUPT; } } return PAR_ERR_EXIST; } /*\ Find a file by its MD5 sum |*| entry: the file to find |*| Returns: matching filename |*| Notes: Returned filename should NOT be free()d. \*/ u16 * par_find(u16 *entry) { pfile_t *p; for (p = files; p; p = p->next) { if (p->filename == entry) { if (!find_file(p, 0)) return 0; return p->match->filename; } } return 0; } /*\ Fix incorrect filenames |*| entry(optional): only fix this entry \*/ int par_fixname(u16 *entry) { int err = PAR_OK; pfile_t *p; u16 *path; for (p = files; p; p = p->next) { if (entry && (p->filename != entry)) continue; if (!find_file(p, 0)) { err = PAR_ERR_NOT_FOUND; continue; } path = do_sub(p->filename, sub); if (!unicode_cmp(path, p->match->filename)) continue; if (rename_away(p->match->filename, path)) err = PAR_ERR_ERRNO; } return err; } /*\ Get status word |*| entry: file to get status of |*| Returns: status word for entry. \*/ i64 par_getstatus(u16 *entry) { pfile_t *p; for (p = files; p; p = p->next) if (p->filename == entry) return p->status; return 0; } /*\ Set status word |*| entry: file to set status for \*/ int par_setstatus(u16 *entry, i64 status) { pfile_t *p; for (p = files; p; p = p->next) { if (p->filename == entry) { p->status = status; return PAR_OK; } } return PAR_ERR_EXIST; } /*\ Recover missing files |*| entry(optional): only recover this entry \*/ int par_recover(u16 *entry) { if (entry) return PAR_ERR_IMPL; if (restore_files(files, volumes, sub) < 0) return PAR_ERR_FAILED; return PAR_OK; } /*\ Add a file to the current filelist |*| filename: file to add \*/ int par_addfile(u16 *filename) { pfile_t *p, **pp; hfile_t *file; if (!filename) return PAR_ERR_INVALID; file = find_file_name(filename, 0); if (!file) return PAR_ERR_NOT_FOUND; if (!hash_file(file, HASH)) return PAR_ERR_ERRNO; for (p = files; p; p = p->next) { if (!unicode_cmp(p->filename, filename)) { if (CMP_MD5(p->hash, file->hash)) return PAR_ERR_ALREADY_LOADED; else return PAR_ERR_CLASH; } } /*\ Create new entry \*/ CNEW(p, 1); p->filename = file->filename; p->match = file; p->file_size = file->file_size; COPY(p->hash, file->hash, sizeof(md5)); COPY(p->hash_16k, file->hash_16k, sizeof(md5)); p->status |= 0x01; /*\ Insert in alphabetically correct place \*/ for (pp = &files; *pp; pp = &((*pp)->next)) if (unicode_gt((*pp)->filename, p->filename)) break; p->next = *pp; *pp = p; return PAR_OK; } /*\ Remove a file from the current filelist |*| entry: file to remove \*/ int par_removefile(u16 *entry) { return PAR_ERR_IMPL; } /*\ Add new PARfiles to the current parlist |*| number: the highest volume number to create \*/ int par_addpars(u16 *entry, int number) { int i, err = PAR_OK; pfile_t *p, **pp; hfile_t *h; if (number < 1) return PAR_ERR_INVALID; for (p = volumes; p; p = p->next) if (p->filename == entry) break; if (!p) return PAR_ERR_INVALID; for (i = 1; i <= number; i++) { h = find_volume(entry, i); if (!h) { err = PAR_ERR_ERRNO; continue; } for (p = volumes; p; p = p->next) if (!unicode_cmp(p->filename, h->filename)) break; if (p) continue; CNEW(p, 1); p->match = h; p->vol_number = i; p->filename = unicode_copy(h->filename); /*\ Insert in alphabetically correct place \*/ for (pp = &volumes; *pp; pp = &((*pp)->next)) if (unicode_gt((*pp)->filename, p->filename)) break; p->next = *pp; *pp = p; } return err; } /*\ Create PARfiles from the current filelist |*| entry(optional): only create this entry \*/ int par_create(u16 *entry) { pfile_t *p; if (entry) return PAR_ERR_IMPL; for (p = volumes; p; p = p->next) { if (p->f) { file_close(p->f); p->f = 0; } if (!p->vol_number) { par_t *par; par = create_par_header(p->filename, 0); par->files = files; write_par_header(par); par->files = 0; free_par(par); } if (!p->fnrs) p->fnrs = file_numbers(&files, &files); } if (restore_files(files, volumes, sub) < 0) return PAR_ERR_FAILED; return PAR_OK; } /*\ List the current directories |*| Returns: Array of filenames, NULL-terminated. |*| Notes: Calles should free() returned array. \*/ u16 ** par_dirlist(void) { u16 **ret; hfile_t *p; int n; for (n = 0, p = hfile; p; p = p->next) n++; CNEW(ret, n + 1); for (n = 0, p = hfile; p; p = p->next, n++) ret[n] = p->filename; ret[n] = 0; return ret; } /*\ |*| Set the smart renaming pattern |*| Note: Optional arguments are to specify pattern, |*| otherwise the pattern is taken from the current list. \*/ int par_setsmart(u16 *from, u16 *to) { if (!from) { if (!to) { free_sub(sub); sub = find_best_sub(files, 2); return PAR_OK; } else { return PAR_ERR_IMPL; } } else { if (!to) { return PAR_ERR_IMPL; } else { free_sub(sub); sub = make_sub(from, to); return PAR_OK; } } }