|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405 |
- /* Copyright (C) 2022-2023 Patrick H. E. Foubet - e2li.org
- Ecole du Logiciel Libre d'Ivry - FRANCE
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or any
- later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>
- *******************************************************************/
- #include <inttypes.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <ctype.h>
- #include <memory.h>
- #include <string.h>
- #include <getopt.h>
-
- #define VERSION "0.4"
- typedef uint32_t loc_t;
- typedef uint8_t byte;
- #define CD_SECTOR_SIZE 0x800 /* 2048 */
- #define ISO_PADSIZE 0x10 /* 16 */
-
- #ifndef __cplusplus
- typedef uint8_t bool;
- #define true (uint8_t)1
- #define false (uint8_t)0
- #endif
-
- #define ALIGN(x,y) (((x) + ((y)-1)) & (~((y)-1)))
-
- static char *isofilename, *targetfilename, *targetdirname, *hostfilename;
- static bool ecrase = false;
-
- struct iso_rep_t {
- uint8_t len;
- uint8_t ex_len;
- uint32_t lba;
- uint32_t big_lba;
- uint32_t file_len;
- uint32_t big_file_len;
- byte time_date[7];
- byte file_flags;
- byte file_unit_size;
- byte interleave_gap_size;
- uint16_t volseq_num;
- uint16_t big_volseq_num;
- uint8_t fileid_len;
- char fileid[0];
- } __attribute__((packed));
- typedef struct iso_rep_t iso_rep_t;
-
- int getfilesize(FILE *f) {
- int spos = ftell(f);
- fseek(f, 0, SEEK_END);
- int len = ftell(f);
- fseek(f, spos, SEEK_SET);
- return len;
- }
- static int Verbose;
- static int Mode=-2; /* 0=list, 1=put, -1=get */
-
- void CdSetloc(FILE *f, loc_t newpos) {
- fseeko(f, newpos * CD_SECTOR_SIZE, SEEK_SET);
- }
-
- void CdRead(void *buf, loc_t nsectors, FILE *f) {
- fread(buf, nsectors, CD_SECTOR_SIZE, f);
- }
-
- void CdWrite(void *buf, loc_t nsectors, FILE *f) {
- fwrite(buf, nsectors, CD_SECTOR_SIZE, f);
- }
-
- bool ispvd(byte *sec) {
- return( (sec[0] == 1) && (memcmp(sec+1, "CD001", 5) == 0));
- }
-
- bool streq(const char *s1, const char *s2) {
- return (strcasecmp(s1,s2) == 0);
- }
-
- bool scmplen(const char *s1, const char *s2, int len) {
- for(int i = 0; i < len; i += 1) {
- if(tolower(s1[i]) != tolower(s2[i])) return false;
- }
- return true;
- }
-
- loc_t CdTell(FILE *fdi) {
- loc_t s = ftell(fdi);
- return (s & (~(0x7FF))) / 0x800;
- }
-
- bool CdFindFileInDir(iso_rep_t *out_dir, FILE* fdi, const char *filename, int filename_len, loc_t *out_secnum, loc_t *out_offset) {
- byte sec[CD_SECTOR_SIZE];
- iso_rep_t *dir = (iso_rep_t*)(sec);
- int slen = filename_len;
- int dirp = 0;
-
- CdRead(sec, 1, fdi);
-
- if (Verbose) printf("FFID %s %d\n", filename, slen);
-
- while(dir->len != 0) {
- int dlen = dir->fileid_len;
- if(!(dir->file_flags & 2)) dlen -= 2;
- if ((Mode == 0)&&((strcmp(filename,"*")==0)||(strcmp(filename,"/*")==0))){
- if (dlen>0) {
- dir->fileid[dlen] = '\0';
- if ((dlen==1) && (dir->fileid[0] <= ' ')) {
- if (Verbose) printf(" + 0x%x %d\n",(int)dir->fileid[0], dlen);
- } else printf(" - %s %d\n",dir->fileid, dlen);
- }
- } else {
- if(dlen == slen) {
- if (Verbose) printf(" + %s\n",dir->fileid);
- if(scmplen(dir->fileid, filename, slen)) {
- *out_dir = *dir;
- if(out_secnum != NULL) *out_secnum = CdTell(fdi) - 1;
- if(out_offset != NULL) *out_offset = dirp;
- return true;
- }
- }
- }
- dirp += dir->len;
- if(dirp >= 0x800) {
- CdRead(sec, 1, fdi);
- dirp = dirp % 0x800;
- }
- dir = (iso_rep_t*)(sec + dirp);
- }
- return false;
- }
-
- bool CdFindFile(iso_rep_t *outdir, FILE *fdi, const char *filename, loc_t *out_secnum, loc_t *out_offset)
- {
- const char *next;
- const char *cur = filename;
- int slen;
- if (Verbose) printf("> %s\n",filename);
- do {
- next = strchr(cur, '/');
- if(next == NULL) slen = strlen(cur);
- else slen = (int)(next - cur);
- if (!CdFindFileInDir(outdir, fdi, cur, slen, out_secnum, out_offset))
- return false;
- if (next != NULL) {
- CdSetloc(fdi, outdir->lba);
- next++; cur = next;
- } else break;
- } while(next != NULL);
- return true;
- }
-
- /* options definitions */
- static int help_flag;
- static struct option long_options[] = {
- {"verbose", no_argument, &Verbose, 1},
- {"help", no_argument, &help_flag, 1},
- {"list", no_argument, 0, 'l'},
- {"put", no_argument, 0, 'p'},
- {"get", no_argument, 0, 'g'},
- {"host", required_argument, 0, 'h'},
- {"file", required_argument, 0, 'f'},
- {"dir", required_argument, 0, 'd'},
- {0, 0, 0, 0}
- };
-
- void explain(void)
- {
- puts("Utilisation : isoupd [options] fichier.iso");
- puts(" -l, --list liste d'un repertoire (defaut)");
- puts(" -p, --put modifie un fichier de l'iso");
- puts(" -g, --get extrait un fichier de l'iso");
- puts(" -v, --verbose mode verbeux, avec trace de la recherche");
- puts(" -f, --file chemin du fichier dans l'iso");
- puts(" -h, --host nom du fichier host. Obligatoire pour -p et -g");
- puts(" -d, --dir nom du repertoire a lister dans l'iso");
- puts(" --help affiche cette aide !");
- }
- void messerr(char * m, int err)
- {
- fprintf(stderr,"ERREUR : %s !!\n", m);
- if (err) {
- explain();
- exit(err);
- }
- }
- static int mode_contrad=0;
- void errmode(char * o)
- {
- fprintf(stderr,"Option %s en contradiction avec une autre !\n",o);
- mode_contrad=1;
- }
-
- int main(int N, char *P[])
- {
- int c, l, opt_ind = 0;
- FILE *fdh, *fdi;
- char etoile[2] = "*";
-
- if(sizeof(iso_rep_t) != 33) {
- fprintf(stderr, "Mauvaise compilation : tid=%lu\n",sizeof(iso_rep_t));
- return 9;
- }
- while (1) {
- if ((c=getopt_long(N,P,"vlpgd:h:f:",long_options,&opt_ind))==-1) break;
- switch (c) {
- case 0:
- if (long_options[opt_ind].flag != 0) break;
- printf ("option %s", long_options[opt_ind].name);
- if (optarg) printf (" avec arg %s", optarg);
- printf ("\n");
- break;
-
- case 'l':
- if (Mode != -2) errmode(P[opt_ind]);
- Mode=0;
- break;
- case 'p':
- if (Mode != -2) errmode(P[opt_ind]);
- Mode=1;
- break;
- case 'g':
- if (Mode != -2) errmode(P[opt_ind]);
- Mode=-1;
- break;
- case 'v':
- Verbose=1;
- break;
- case 'h':
- hostfilename = optarg;
- break;
- case 'f':
- targetfilename = optarg;
- break;
- case 'd':
- l = strlen(optarg);
- if (optarg[l-1]=='/') { l--; optarg[l]='\0'; }
- targetdirname = (char*) malloc(l+3);
- if (targetdirname == NULL) { perror("malloc"); return 4; }
- sprintf(targetdirname, "%s/%s", optarg,etoile);
- break;
- case '?': /* getopt_long already printed an error message. */
- explain();
- return 1;
- default:
- abort ();
- }
- }
- if (help_flag) {
- printf("isoupd version %s (c) E2L 2023\n",VERSION);
- explain();
- return 0;
- }
- if (optind < N) {
- isofilename = P[optind++];
- if (optind < N) {
- fprintf (stderr, "Non pris en compte : ");
- while (optind < N) fprintf (stderr, "%s ", P[optind++]);
- fprintf(stderr, "\n");
- messerr("parametre(s) inutile(s)",3);
- }
- }
- /* verifications */
- if (! isofilename) messerr("Fichier ISO absent",2);
- if (Mode == -2) Mode = 0; /* defaut */
- switch(Mode) {
- case 0 : /* list */
- if (targetfilename) messerr("option -f inutile",2);
- if (hostfilename) messerr("option -h inutile",2);
- if (!targetdirname) targetdirname = etoile;
- if (Verbose) printf("Liste de %s dans %s\n",targetdirname,isofilename);
- targetfilename = targetdirname;
- break;
- case 1 : /* put */
- if (targetdirname) messerr("option -d inutile",2);
- if (!targetfilename) messerr("Chemin du fichier dans l'ISO absent",2);
- if (!hostfilename) messerr("fichier host source absent",2);
- if (Verbose) printf("PUT de %s vers %s dans %s\n",hostfilename,targetfilename,isofilename);
- break;
- case -1 : /* get */
- if (targetdirname) messerr("option -d inutile",2);
- if (!targetfilename) messerr("Chemin du fichier dans l'ISO absent",2);
- if (!hostfilename) messerr("fichier host destination absent",2);
- if (Verbose) printf("GET de %s dans %s vers %s\n",targetfilename,isofilename,hostfilename);
- break;
- }
- if (Verbose) printf("Verbose : mode = %d\n",Mode);
-
- if ((fdi = fopen(isofilename, "r+")) == NULL) {
- fprintf(stderr, "Erreur ouverture ISO %s\n", isofilename);
- return 1;
- }
- if(hostfilename != NULL) {
- if ((fdh = fopen(hostfilename, "r")) == NULL) {
- if (Mode == 1) { /* put */
- fprintf(stderr, "Erreur ouverture fichier %s\n", hostfilename);
- return 1;
- }
- } else {
- if (Mode == -1) { /* get */
- fprintf(stderr,"Erreur : le fichier %s existe deja !\n",hostfilename);
- return 1;
- }
- }
- if (Mode == -1) { /* get */
- if ((fdh = fopen(hostfilename, "w")) == NULL) {
- fprintf(stderr, "Erreur creation fichier %s\n", hostfilename);
- return 1;
- }
- }
- }
- byte sec[CD_SECTOR_SIZE];
- iso_rep_t *dir = (iso_rep_t*)(sec);
- CdSetloc(fdi, ISO_PADSIZE);
- CdRead(sec, 1, fdi);
- if(!ispvd(sec)) {
- fprintf(stderr, "%s n'est pas un fichier ISO\n", isofilename);
- return 1;
- }
- loc_t root_lba = *(loc_t*)(sec+158);
- if (Verbose) printf("root lba = %x\n", root_lba);
- CdSetloc(fdi, root_lba);
- loc_t dir_lba, dir_offset;
- bool s = CdFindFile(dir, fdi, targetfilename, &dir_lba, &dir_offset);
- if (!Mode) { /* list */
- fclose(fdi);
- return 0;
- }
- if(!s) {
- fprintf(stderr, "Fichier %s absent de l'ISO %s\n", targetfilename, isofilename);
- return 1;
- }
- CdSetloc(fdi, dir_lba);
- CdRead(sec, 1, fdi);
- dir = (iso_rep_t*)(sec + dir_offset);
- int maxsize = ALIGN(dir->file_len, 0x800);
- printf("Taille du fichier sur l'ISO : %d\n", dir->file_len);
- if (Mode == -1) { /* get */
- byte *filedata = (byte*)(malloc(maxsize));
- CdSetloc(fdi, dir->lba);
- CdRead(filedata, (maxsize / CD_SECTOR_SIZE), fdi);
- fwrite(filedata, 1, dir->file_len, fdh);
- fclose(fdh);
- fclose(fdi);
- printf("Extraction faite dans %s.\n",hostfilename);
- return 0;
- }
- int len = getfilesize(fdh);
- int aligned_len = ALIGN(len, 0x800);
- printf("Taille du fichier local : %d\n", len);
- if(!ecrase) {
- if(len > maxsize) {
- fprintf(stderr, "Le fichier %s depasse de %d octets (%d > %d)\n",
- hostfilename, len - maxsize, len, maxsize);
- fclose(fdh);
- fclose(fdi);
- return 1;
- }
- if((uint32_t)len != dir->file_len) {
- if((uint32_t)aligned_len < dir->file_len) {
- printf("ATTENTION: La mise en place de ce fichier\n va retrecir l'espace d'allocation disponible !\n");
- printf(" (il sera de %d octets)\n", aligned_len);
- }
- printf("Les tailles sont differentes mais compatibles.\n");
- }
- }
- printf("AVERTISSEMENT : Version %s de test !!!\n",VERSION);
- printf("============= Il faut faire une sauvegarde de l'ISO avant.\n");
- printf("Modification ? [o/N]\n");
- int ch = getchar();
- if((ch != 'o') && (ch != 'O')) {
- printf("Annulation !!\n");
- return 1;
- }
- byte *filedata = (byte*)(malloc(aligned_len));
- memset(filedata, 0, aligned_len);
- fread(filedata, 1, len, fdh);
- fclose(fdh);
-
- printf("Ecriture de %d octets sur le secteur %u\n", len, dir->lba);
- CdSetloc(fdi, dir->lba);
- CdWrite(filedata, (aligned_len / CD_SECTOR_SIZE), fdi);
-
- dir->file_len = len;
- printf("Ecriture d'un nouveau repertoire sur %u\n", dir_lba);
- CdSetloc(fdi, dir_lba);
- CdWrite(sec, 1, fdi);
-
- printf("OK !\n");
-
- fclose(fdi);
- return 0;
- }
-
|