Petit utilitaire qui permet de mettre à jour un fichier contenant une image ISO.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

406 lignes
12 KiB

  1. /* Copyright (C) 2022-2023 Patrick H. E. Foubet - e2li.org
  2. Ecole du Logiciel Libre d'Ivry - FRANCE
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation, either version 3 of the License, or any
  6. later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>
  13. *******************************************************************/
  14. #include <inttypes.h>
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <unistd.h>
  18. #include <ctype.h>
  19. #include <memory.h>
  20. #include <string.h>
  21. #include <getopt.h>
  22. #define VERSION "0.4"
  23. typedef uint32_t loc_t;
  24. typedef uint8_t byte;
  25. #define CD_SECTOR_SIZE 0x800 /* 2048 */
  26. #define ISO_PADSIZE 0x10 /* 16 */
  27. #ifndef __cplusplus
  28. typedef uint8_t bool;
  29. #define true (uint8_t)1
  30. #define false (uint8_t)0
  31. #endif
  32. #define ALIGN(x,y) (((x) + ((y)-1)) & (~((y)-1)))
  33. static char *isofilename, *targetfilename, *targetdirname, *hostfilename;
  34. static bool ecrase = false;
  35. struct iso_rep_t {
  36. uint8_t len;
  37. uint8_t ex_len;
  38. uint32_t lba;
  39. uint32_t big_lba;
  40. uint32_t file_len;
  41. uint32_t big_file_len;
  42. byte time_date[7];
  43. byte file_flags;
  44. byte file_unit_size;
  45. byte interleave_gap_size;
  46. uint16_t volseq_num;
  47. uint16_t big_volseq_num;
  48. uint8_t fileid_len;
  49. char fileid[0];
  50. } __attribute__((packed));
  51. typedef struct iso_rep_t iso_rep_t;
  52. int getfilesize(FILE *f) {
  53. int spos = ftell(f);
  54. fseek(f, 0, SEEK_END);
  55. int len = ftell(f);
  56. fseek(f, spos, SEEK_SET);
  57. return len;
  58. }
  59. static int Verbose;
  60. static int Mode=-2; /* 0=list, 1=put, -1=get */
  61. void CdSetloc(FILE *f, loc_t newpos) {
  62. fseeko(f, newpos * CD_SECTOR_SIZE, SEEK_SET);
  63. }
  64. void CdRead(void *buf, loc_t nsectors, FILE *f) {
  65. fread(buf, nsectors, CD_SECTOR_SIZE, f);
  66. }
  67. void CdWrite(void *buf, loc_t nsectors, FILE *f) {
  68. fwrite(buf, nsectors, CD_SECTOR_SIZE, f);
  69. }
  70. bool ispvd(byte *sec) {
  71. return( (sec[0] == 1) && (memcmp(sec+1, "CD001", 5) == 0));
  72. }
  73. bool streq(const char *s1, const char *s2) {
  74. return (strcasecmp(s1,s2) == 0);
  75. }
  76. bool scmplen(const char *s1, const char *s2, int len) {
  77. for(int i = 0; i < len; i += 1) {
  78. if(tolower(s1[i]) != tolower(s2[i])) return false;
  79. }
  80. return true;
  81. }
  82. loc_t CdTell(FILE *fdi) {
  83. loc_t s = ftell(fdi);
  84. return (s & (~(0x7FF))) / 0x800;
  85. }
  86. bool CdFindFileInDir(iso_rep_t *out_dir, FILE* fdi, const char *filename, int filename_len, loc_t *out_secnum, loc_t *out_offset) {
  87. byte sec[CD_SECTOR_SIZE];
  88. iso_rep_t *dir = (iso_rep_t*)(sec);
  89. int slen = filename_len;
  90. int dirp = 0;
  91. CdRead(sec, 1, fdi);
  92. if (Verbose) printf("FFID %s %d\n", filename, slen);
  93. while(dir->len != 0) {
  94. int dlen = dir->fileid_len;
  95. if(!(dir->file_flags & 2)) dlen -= 2;
  96. if ((Mode == 0)&&((strcmp(filename,"*")==0)||(strcmp(filename,"/*")==0))){
  97. if (dlen>0) {
  98. dir->fileid[dlen] = '\0';
  99. if ((dlen==1) && (dir->fileid[0] <= ' ')) {
  100. if (Verbose) printf(" + 0x%x %d\n",(int)dir->fileid[0], dlen);
  101. } else printf(" - %s %d\n",dir->fileid, dlen);
  102. }
  103. } else {
  104. if(dlen == slen) {
  105. if (Verbose) printf(" + %s\n",dir->fileid);
  106. if(scmplen(dir->fileid, filename, slen)) {
  107. *out_dir = *dir;
  108. if(out_secnum != NULL) *out_secnum = CdTell(fdi) - 1;
  109. if(out_offset != NULL) *out_offset = dirp;
  110. return true;
  111. }
  112. }
  113. }
  114. dirp += dir->len;
  115. if(dirp >= 0x800) {
  116. CdRead(sec, 1, fdi);
  117. dirp = dirp % 0x800;
  118. }
  119. dir = (iso_rep_t*)(sec + dirp);
  120. }
  121. return false;
  122. }
  123. bool CdFindFile(iso_rep_t *outdir, FILE *fdi, const char *filename, loc_t *out_secnum, loc_t *out_offset)
  124. {
  125. const char *next;
  126. const char *cur = filename;
  127. int slen;
  128. if (Verbose) printf("> %s\n",filename);
  129. do {
  130. next = strchr(cur, '/');
  131. if(next == NULL) slen = strlen(cur);
  132. else slen = (int)(next - cur);
  133. if (!CdFindFileInDir(outdir, fdi, cur, slen, out_secnum, out_offset))
  134. return false;
  135. if (next != NULL) {
  136. CdSetloc(fdi, outdir->lba);
  137. next++; cur = next;
  138. } else break;
  139. } while(next != NULL);
  140. return true;
  141. }
  142. /* options definitions */
  143. static int help_flag;
  144. static struct option long_options[] = {
  145. {"verbose", no_argument, &Verbose, 1},
  146. {"help", no_argument, &help_flag, 1},
  147. {"list", no_argument, 0, 'l'},
  148. {"put", no_argument, 0, 'p'},
  149. {"get", no_argument, 0, 'g'},
  150. {"host", required_argument, 0, 'h'},
  151. {"file", required_argument, 0, 'f'},
  152. {"dir", required_argument, 0, 'd'},
  153. {0, 0, 0, 0}
  154. };
  155. void explain(void)
  156. {
  157. puts("Utilisation : isoupd [options] fichier.iso");
  158. puts(" -l, --list liste d'un repertoire (defaut)");
  159. puts(" -p, --put modifie un fichier de l'iso");
  160. puts(" -g, --get extrait un fichier de l'iso");
  161. puts(" -v, --verbose mode verbeux, avec trace de la recherche");
  162. puts(" -f, --file chemin du fichier dans l'iso");
  163. puts(" -h, --host nom du fichier host. Obligatoire pour -p et -g");
  164. puts(" -d, --dir nom du repertoire a lister dans l'iso");
  165. puts(" --help affiche cette aide !");
  166. }
  167. void messerr(char * m, int err)
  168. {
  169. fprintf(stderr,"ERREUR : %s !!\n", m);
  170. if (err) {
  171. explain();
  172. exit(err);
  173. }
  174. }
  175. static int mode_contrad=0;
  176. void errmode(char * o)
  177. {
  178. fprintf(stderr,"Option %s en contradiction avec une autre !\n",o);
  179. mode_contrad=1;
  180. }
  181. int main(int N, char *P[])
  182. {
  183. int c, l, opt_ind = 0;
  184. FILE *fdh, *fdi;
  185. char etoile[2] = "*";
  186. if(sizeof(iso_rep_t) != 33) {
  187. fprintf(stderr, "Mauvaise compilation : tid=%lu\n",sizeof(iso_rep_t));
  188. return 9;
  189. }
  190. while (1) {
  191. if ((c=getopt_long(N,P,"vlpgd:h:f:",long_options,&opt_ind))==-1) break;
  192. switch (c) {
  193. case 0:
  194. if (long_options[opt_ind].flag != 0) break;
  195. printf ("option %s", long_options[opt_ind].name);
  196. if (optarg) printf (" avec arg %s", optarg);
  197. printf ("\n");
  198. break;
  199. case 'l':
  200. if (Mode != -2) errmode(P[opt_ind]);
  201. Mode=0;
  202. break;
  203. case 'p':
  204. if (Mode != -2) errmode(P[opt_ind]);
  205. Mode=1;
  206. break;
  207. case 'g':
  208. if (Mode != -2) errmode(P[opt_ind]);
  209. Mode=-1;
  210. break;
  211. case 'v':
  212. Verbose=1;
  213. break;
  214. case 'h':
  215. hostfilename = optarg;
  216. break;
  217. case 'f':
  218. targetfilename = optarg;
  219. break;
  220. case 'd':
  221. l = strlen(optarg);
  222. if (optarg[l-1]=='/') { l--; optarg[l]='\0'; }
  223. targetdirname = (char*) malloc(l+3);
  224. if (targetdirname == NULL) { perror("malloc"); return 4; }
  225. sprintf(targetdirname, "%s/%s", optarg,etoile);
  226. break;
  227. case '?': /* getopt_long already printed an error message. */
  228. explain();
  229. return 1;
  230. default:
  231. abort ();
  232. }
  233. }
  234. if (help_flag) {
  235. printf("isoupd version %s (c) E2L 2023\n",VERSION);
  236. explain();
  237. return 0;
  238. }
  239. if (optind < N) {
  240. isofilename = P[optind++];
  241. if (optind < N) {
  242. fprintf (stderr, "Non pris en compte : ");
  243. while (optind < N) fprintf (stderr, "%s ", P[optind++]);
  244. fprintf(stderr, "\n");
  245. messerr("parametre(s) inutile(s)",3);
  246. }
  247. }
  248. /* verifications */
  249. if (! isofilename) messerr("Fichier ISO absent",2);
  250. if (Mode == -2) Mode = 0; /* defaut */
  251. switch(Mode) {
  252. case 0 : /* list */
  253. if (targetfilename) messerr("option -f inutile",2);
  254. if (hostfilename) messerr("option -h inutile",2);
  255. if (!targetdirname) targetdirname = etoile;
  256. if (Verbose) printf("Liste de %s dans %s\n",targetdirname,isofilename);
  257. targetfilename = targetdirname;
  258. break;
  259. case 1 : /* put */
  260. if (targetdirname) messerr("option -d inutile",2);
  261. if (!targetfilename) messerr("Chemin du fichier dans l'ISO absent",2);
  262. if (!hostfilename) messerr("fichier host source absent",2);
  263. if (Verbose) printf("PUT de %s vers %s dans %s\n",hostfilename,targetfilename,isofilename);
  264. break;
  265. case -1 : /* get */
  266. if (targetdirname) messerr("option -d inutile",2);
  267. if (!targetfilename) messerr("Chemin du fichier dans l'ISO absent",2);
  268. if (!hostfilename) messerr("fichier host destination absent",2);
  269. if (Verbose) printf("GET de %s dans %s vers %s\n",targetfilename,isofilename,hostfilename);
  270. break;
  271. }
  272. if (Verbose) printf("Verbose : mode = %d\n",Mode);
  273. if ((fdi = fopen(isofilename, "r+")) == NULL) {
  274. fprintf(stderr, "Erreur ouverture ISO %s\n", isofilename);
  275. return 1;
  276. }
  277. if(hostfilename != NULL) {
  278. if ((fdh = fopen(hostfilename, "r")) == NULL) {
  279. if (Mode == 1) { /* put */
  280. fprintf(stderr, "Erreur ouverture fichier %s\n", hostfilename);
  281. return 1;
  282. }
  283. } else {
  284. if (Mode == -1) { /* get */
  285. fprintf(stderr,"Erreur : le fichier %s existe deja !\n",hostfilename);
  286. return 1;
  287. }
  288. }
  289. if (Mode == -1) { /* get */
  290. if ((fdh = fopen(hostfilename, "w")) == NULL) {
  291. fprintf(stderr, "Erreur creation fichier %s\n", hostfilename);
  292. return 1;
  293. }
  294. }
  295. }
  296. byte sec[CD_SECTOR_SIZE];
  297. iso_rep_t *dir = (iso_rep_t*)(sec);
  298. CdSetloc(fdi, ISO_PADSIZE);
  299. CdRead(sec, 1, fdi);
  300. if(!ispvd(sec)) {
  301. fprintf(stderr, "%s n'est pas un fichier ISO\n", isofilename);
  302. return 1;
  303. }
  304. loc_t root_lba = *(loc_t*)(sec+158);
  305. if (Verbose) printf("root lba = %x\n", root_lba);
  306. CdSetloc(fdi, root_lba);
  307. loc_t dir_lba, dir_offset;
  308. bool s = CdFindFile(dir, fdi, targetfilename, &dir_lba, &dir_offset);
  309. if (!Mode) { /* list */
  310. fclose(fdi);
  311. return 0;
  312. }
  313. if(!s) {
  314. fprintf(stderr, "Fichier %s absent de l'ISO %s\n", targetfilename, isofilename);
  315. return 1;
  316. }
  317. CdSetloc(fdi, dir_lba);
  318. CdRead(sec, 1, fdi);
  319. dir = (iso_rep_t*)(sec + dir_offset);
  320. int maxsize = ALIGN(dir->file_len, 0x800);
  321. printf("Taille du fichier sur l'ISO : %d\n", dir->file_len);
  322. if (Mode == -1) { /* get */
  323. byte *filedata = (byte*)(malloc(maxsize));
  324. CdSetloc(fdi, dir->lba);
  325. CdRead(filedata, (maxsize / CD_SECTOR_SIZE), fdi);
  326. fwrite(filedata, 1, dir->file_len, fdh);
  327. fclose(fdh);
  328. fclose(fdi);
  329. printf("Extraction faite dans %s.\n",hostfilename);
  330. return 0;
  331. }
  332. int len = getfilesize(fdh);
  333. int aligned_len = ALIGN(len, 0x800);
  334. printf("Taille du fichier local : %d\n", len);
  335. if(!ecrase) {
  336. if(len > maxsize) {
  337. fprintf(stderr, "Le fichier %s depasse de %d octets (%d > %d)\n",
  338. hostfilename, len - maxsize, len, maxsize);
  339. fclose(fdh);
  340. fclose(fdi);
  341. return 1;
  342. }
  343. if((uint32_t)len != dir->file_len) {
  344. if((uint32_t)aligned_len < dir->file_len) {
  345. printf("ATTENTION: La mise en place de ce fichier\n va retrecir l'espace d'allocation disponible !\n");
  346. printf(" (il sera de %d octets)\n", aligned_len);
  347. }
  348. printf("Les tailles sont differentes mais compatibles.\n");
  349. }
  350. }
  351. printf("AVERTISSEMENT : Version %s de test !!!\n",VERSION);
  352. printf("============= Il faut faire une sauvegarde de l'ISO avant.\n");
  353. printf("Modification ? [o/N]\n");
  354. int ch = getchar();
  355. if((ch != 'o') && (ch != 'O')) {
  356. printf("Annulation !!\n");
  357. return 1;
  358. }
  359. byte *filedata = (byte*)(malloc(aligned_len));
  360. memset(filedata, 0, aligned_len);
  361. fread(filedata, 1, len, fdh);
  362. fclose(fdh);
  363. printf("Ecriture de %d octets sur le secteur %u\n", len, dir->lba);
  364. CdSetloc(fdi, dir->lba);
  365. CdWrite(filedata, (aligned_len / CD_SECTOR_SIZE), fdi);
  366. dir->file_len = len;
  367. printf("Ecriture d'un nouveau repertoire sur %u\n", dir_lba);
  368. CdSetloc(fdi, dir_lba);
  369. CdWrite(sec, 1, fdi);
  370. printf("OK !\n");
  371. fclose(fdi);
  372. return 0;
  373. }