Petit utilitaire qui permet de mettre à jour un fichier contenant une image ISO.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

422 line
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.2"
  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 length_override = false;
  35. struct iso_directory_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_directory_t iso_directory_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_flag;
  60. static int mode_flag=-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(
  72. (sec[0] == 1) &&
  73. (memcmp(sec+1, "CD001", 5) == 0)
  74. );
  75. }
  76. bool streq(const char *s1, const char *s2) {
  77. return (strcasecmp(s1,s2) == 0);
  78. }
  79. bool scmplen(const char *s1, const char *s2, int len) {
  80. for(int i = 0; i < len; i += 1) {
  81. if(tolower(s1[i]) != tolower(s2[i])) {
  82. return false;
  83. }
  84. }
  85. return true;
  86. }
  87. loc_t CdTell(FILE *isofile) {
  88. loc_t s = ftell(isofile);
  89. return (s & (~(0x7FF))) / 0x800;
  90. }
  91. bool CdFindFileInDir(iso_directory_t *out_dir, FILE* isofile, const char *filename, int filename_len, loc_t *out_secnum, loc_t *out_offset) {
  92. byte sec[CD_SECTOR_SIZE];
  93. iso_directory_t *dir = (iso_directory_t*)(sec);
  94. int slen = filename_len;
  95. int dirp = 0;
  96. CdRead(sec, 1, isofile);
  97. if (verbose_flag) printf("FFID %s %d\n", filename, slen);
  98. while(dir->len != 0) {
  99. int dlen = dir->fileid_len;
  100. if(!(dir->file_flags & 2)) {
  101. dlen -= 2;
  102. }
  103. if ((mode_flag == 0) && ((strcmp(filename,"*")==0)||(strcmp(filename,"/*")==0))) {
  104. if (dlen>0) {
  105. dir->fileid[dlen] = '\0';
  106. if ((dlen==1) && (dir->fileid[0] <= ' ')) {
  107. if (verbose_flag) printf(" + 0x%x %d\n",(int)dir->fileid[0], dlen);
  108. } else printf(" - %s %d\n",dir->fileid, dlen);
  109. }
  110. } else {
  111. if(dlen == slen) {
  112. if (verbose_flag) printf(" + %s\n",dir->fileid);
  113. if(scmplen(dir->fileid, filename, slen)) {
  114. *out_dir = *dir;
  115. if(NULL != out_secnum) {
  116. *out_secnum = CdTell(isofile) - 1;
  117. }
  118. if(NULL != out_offset) {
  119. *out_offset = dirp;
  120. }
  121. return true;
  122. }
  123. }
  124. }
  125. dirp += dir->len;
  126. if(dirp >= 0x800) {
  127. CdRead(sec, 1, isofile);
  128. dirp = dirp % 0x800;
  129. }
  130. dir = (iso_directory_t*)(sec + dirp);
  131. }
  132. return false;
  133. }
  134. bool CdFindFile(iso_directory_t *outdir, FILE *isofile, const char *filename, loc_t *out_secnum, loc_t *out_offset)
  135. {
  136. const char *next;
  137. const char *cur = filename;
  138. int slen;
  139. if (verbose_flag) printf("> %s\n",filename);
  140. do {
  141. next = strchr(cur, '/');
  142. if(next == NULL) {
  143. slen = strlen(cur);
  144. } else {
  145. slen = (int)(next - cur);
  146. }
  147. if(!CdFindFileInDir(outdir, isofile, cur, slen, out_secnum, out_offset))
  148. return false;
  149. if(next != NULL) {
  150. CdSetloc(isofile, outdir->lba);
  151. next++; cur = next;
  152. } else break;
  153. } while(next != NULL);
  154. return true;
  155. }
  156. /* options definitions */
  157. static int help_flag;
  158. static struct option long_options[] = {
  159. {"verbose", no_argument, &verbose_flag, 1},
  160. {"help", no_argument, &help_flag, 1},
  161. {"list", no_argument, 0, 'l'},
  162. {"put", no_argument, 0, 'p'},
  163. {"get", no_argument, 0, 'g'},
  164. {"host", required_argument, 0, 'h'},
  165. {"file", required_argument, 0, 'f'},
  166. {"dir", required_argument, 0, 'd'},
  167. {0, 0, 0, 0}
  168. };
  169. void explain(void)
  170. {
  171. puts("Utilisation : isoupd [options] isofile");
  172. puts(" -l, --list liste d'un repertoire (defaut)");
  173. puts(" -p, --put modifie un fichier de l'iso");
  174. puts(" -g, --get extrait un fichier de l'iso");
  175. puts(" -v, --verbose mode verbeux, avec trace de la recherche");
  176. puts(" -f, --file chemin du fichier dans l'iso");
  177. puts(" -h, --host nom du fichier host. Obligatoire pour -p et -g");
  178. puts(" -d, --dir nom du repertoire a lister dans l'iso");
  179. puts(" --help cette aide !");
  180. }
  181. void messerr(char * m, int err)
  182. {
  183. fprintf(stderr,"ERREUR : %s !!\n", m);
  184. if (err) {
  185. explain();
  186. exit(err);
  187. }
  188. }
  189. static int mode_contrad=0;
  190. void errmode(char * o)
  191. {
  192. fprintf(stderr,"Option %s en contradiction avec une autre !\n",o);
  193. mode_contrad=1;
  194. }
  195. int main(int N, char *P[])
  196. {
  197. int c, l, opt_ind = 0;
  198. FILE *hostfile, *isofile;
  199. char etoile[2] = "*";
  200. if(sizeof(iso_directory_t) != 33) {
  201. fprintf(stderr, "Mauvaise compilation : tid=%lu\n",sizeof(iso_directory_t));
  202. return 9;
  203. }
  204. while (1) {
  205. if ((c=getopt_long(N,P,"vlpgd:h:f:",long_options,&opt_ind))==-1) break;
  206. switch (c) {
  207. case 0:
  208. if (long_options[opt_ind].flag != 0) break;
  209. printf ("option %s", long_options[opt_ind].name);
  210. if (optarg) printf (" avec arg %s", optarg);
  211. printf ("\n");
  212. break;
  213. case 'l':
  214. if (mode_flag != -2) errmode(P[opt_ind]);
  215. mode_flag=0;
  216. break;
  217. case 'p':
  218. if (mode_flag != -2) errmode(P[opt_ind]);
  219. mode_flag=1;
  220. break;
  221. case 'g':
  222. if (mode_flag != -2) errmode(P[opt_ind]);
  223. mode_flag=-1;
  224. break;
  225. case 'v':
  226. verbose_flag=1;
  227. break;
  228. case 'h':
  229. hostfilename = optarg;
  230. break;
  231. case 'f':
  232. targetfilename = optarg;
  233. break;
  234. case 'd':
  235. l = strlen(optarg);
  236. if (optarg[l-1]=='/') { l--; optarg[l]='\0'; }
  237. targetdirname = (char*) malloc(l+3);
  238. if (targetdirname == NULL) { perror("malloc"); return 4; }
  239. sprintf(targetdirname, "%s/%s", optarg,etoile);
  240. break;
  241. case '?': /* getopt_long already printed an error message. */
  242. explain();
  243. return 1;
  244. default:
  245. abort ();
  246. }
  247. }
  248. if (help_flag) {
  249. printf("isoupd version %s (c) E2L 2023\n",VERSION);
  250. explain();
  251. return 0;
  252. }
  253. if (optind < N) {
  254. isofilename = P[optind++];
  255. if (optind < N) {
  256. fprintf (stderr, "Non pris en compte : ");
  257. while (optind < N) fprintf (stderr, "%s ", P[optind++]);
  258. fprintf(stderr, "\n");
  259. messerr("parametre(s) inutile(s)",3);
  260. }
  261. }
  262. /* verifications */
  263. if (! isofilename) messerr("Fichier ISO absent",2);
  264. if (mode_flag == -2) mode_flag = 0; /* defaut */
  265. switch(mode_flag) {
  266. case 0 : /* list */
  267. if (targetfilename) messerr("option -f inutile",2);
  268. if (hostfilename) messerr("option -h inutile",2);
  269. if (!targetdirname) targetdirname = etoile;
  270. if (verbose_flag) printf("Liste de %s dans %s\n",targetdirname,isofilename);
  271. targetfilename = targetdirname;
  272. break;
  273. case 1 : /* put */
  274. if (targetdirname) messerr("option -d inutile",2);
  275. if (!targetfilename) messerr("Chemin du fichier dans l'ISO absent",2);
  276. if (!hostfilename) messerr("fichier host source absent",2);
  277. if (verbose_flag) printf("PUT de %s vers %s dans %s\n",hostfilename,targetfilename,isofilename);
  278. break;
  279. case -1 : /* get */
  280. if (targetdirname) messerr("option -d inutile",2);
  281. if (!targetfilename) messerr("Chemin du fichier dans l'ISO absent",2);
  282. if (!hostfilename) messerr("fichier host destination absent",2);
  283. if (verbose_flag) printf("GET de %s dans %s vers %s\n",targetfilename,isofilename,hostfilename);
  284. break;
  285. }
  286. if (verbose_flag) printf("Verbose : mode = %d\n",mode_flag);
  287. if ((isofile = fopen(isofilename, "r+")) == NULL) {
  288. fprintf(stderr, "Erreur ouverture ISO %s\n", isofilename);
  289. return 1;
  290. }
  291. if(hostfilename != NULL) {
  292. if ((hostfile = fopen(hostfilename, "r")) == NULL) {
  293. if (mode_flag == 1) { /* put */
  294. fprintf(stderr, "Erreur ouverture fichier %s\n", hostfilename);
  295. return 1;
  296. }
  297. } else {
  298. if (mode_flag == -1) { /* get */
  299. fprintf(stderr,"Erreur : le fichier %s existe deja !\n",hostfilename);
  300. return 1;
  301. }
  302. }
  303. if (mode_flag == -1) { /* get */
  304. if ((hostfile = fopen(hostfilename, "w")) == NULL) {
  305. fprintf(stderr, "Erreur creation fichier %s\n", hostfilename);
  306. return 1;
  307. }
  308. }
  309. }
  310. byte sec[CD_SECTOR_SIZE];
  311. iso_directory_t *dir = (iso_directory_t*)(sec);
  312. CdSetloc(isofile, ISO_PADSIZE);
  313. CdRead(sec, 1, isofile);
  314. if(!ispvd(sec)) {
  315. fprintf(stderr, "%s n'est pas un fichier ISO\n", isofilename);
  316. return 1;
  317. }
  318. loc_t root_lba = *(loc_t*)(sec+158);
  319. if (verbose_flag) printf("root lba = %x\n", root_lba);
  320. CdSetloc(isofile, root_lba);
  321. loc_t dir_lba, dir_offset;
  322. bool s = CdFindFile(dir, isofile, targetfilename, &dir_lba, &dir_offset);
  323. if (!mode_flag) { /* list */
  324. fclose(isofile);
  325. return 0;
  326. }
  327. if(!s) {
  328. fprintf(stderr, "Fichier %s absent de l'ISO %s\n", targetfilename, isofilename);
  329. return 1;
  330. }
  331. CdSetloc(isofile, dir_lba);
  332. CdRead(sec, 1, isofile);
  333. dir = (iso_directory_t*)(sec + dir_offset);
  334. int maxsize = ALIGN(dir->file_len, 0x800);
  335. printf("Taille du fichier sur l'ISO : %d\n", dir->file_len);
  336. if (mode_flag == -1) { /* get */
  337. byte *filedata = (byte*)(malloc(maxsize));
  338. CdSetloc(isofile, dir->lba);
  339. CdRead(filedata, (maxsize / CD_SECTOR_SIZE), isofile);
  340. fwrite(filedata, 1, dir->file_len, hostfile);
  341. fclose(hostfile);
  342. fclose(isofile);
  343. printf("Extraction faite dans %s.\n",hostfilename);
  344. return 0;
  345. }
  346. int len = getfilesize(hostfile);
  347. int aligned_len = ALIGN(len, 0x800);
  348. printf("Taille du fichier local : %d\n", len);
  349. printf("La commande --put n'est pas encore au point !\n");
  350. return 0; /* test */
  351. if(!length_override) {
  352. if(len > maxsize) {
  353. fprintf(stderr, "Le fichier %s depasse de %d octets (%d > %d)\n",
  354. hostfilename,
  355. len - maxsize,
  356. len, maxsize
  357. );
  358. fclose(hostfile);
  359. fclose(isofile);
  360. return 1;
  361. }
  362. if((uint32_t)len != dir->file_len) {
  363. if((uint32_t)aligned_len < dir->file_len) {
  364. printf("ATTENTION: La mise en place de ce fichier va retrecir l'espace d'allocation disponible !\n");
  365. printf(" (il sera de %d octets)\n", aligned_len);
  366. }
  367. printf("Les tailles sont differentes mais compatibles. Modification ? [o/N]\n");
  368. int ch = getchar();
  369. if((ch != 'o') && (ch != 'O')) {
  370. printf("Annulation !!\n");
  371. return 1;
  372. }
  373. }
  374. }
  375. byte *filedata = (byte*)(malloc(aligned_len));
  376. memset(filedata, 0, aligned_len);
  377. fread(filedata, 1, len, hostfile);
  378. fclose(hostfile);
  379. printf("Ecriture de %d octets sur le secteur %u\n", len, dir->lba);
  380. CdSetloc(isofile, dir->lba);
  381. CdWrite(filedata, (aligned_len / CD_SECTOR_SIZE), isofile);
  382. dir->file_len = len;
  383. printf("Ecriture d'un nouveau repertoire sur %u\n", dir_lba);
  384. CdSetloc(isofile, dir_lba);
  385. CdWrite(sec, 1, isofile);
  386. printf("OK !\n");
  387. fclose(isofile);
  388. return 0;
  389. }