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.

isoupd.c 12 KiB

il y a 1 an
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  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.1"
  23. typedef uint32_t loc_t;
  24. typedef uint8_t byte;
  25. #define CD_SECTOR_SIZE 0x800
  26. #define ISO_PADSIZE 0x10
  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) == true) {
  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(false == CdFindFileInDir(outdir, isofile, cur, slen, out_secnum, out_offset)) {
  148. return false;
  149. }
  150. if(next != NULL) {
  151. CdSetloc(isofile, outdir->lba);
  152. next++; cur = next;
  153. } else break;
  154. } while(next != NULL);
  155. return true;
  156. }
  157. /* options definitions */
  158. static int help_flag;
  159. static struct option long_options[] = {
  160. {"verbose", no_argument, &verbose_flag, 1},
  161. {"help", no_argument, &help_flag, 1},
  162. {"list", no_argument, 0, 'l'},
  163. {"put", no_argument, 0, 'p'},
  164. {"get", no_argument, 0, 'g'},
  165. {"host", required_argument, 0, 'h'},
  166. {"file", required_argument, 0, 'f'},
  167. {"dir", required_argument, 0, 'd'},
  168. {0, 0, 0, 0}
  169. };
  170. void explain(void)
  171. {
  172. puts("Utilisation : isoupd [options] isofile");
  173. puts(" -l, --list liste d'un repertoire (defaut)");
  174. puts(" -p, --put modifie un fichier de l'iso");
  175. puts(" -g, --get extrait un fichier de l'iso");
  176. puts(" -v, --verbose mode verbeux, avec trace de la recherche");
  177. puts(" -f, --file chemin du fichier dans l'iso");
  178. puts(" -h, --host nom du fichier host. Obligatoire pour -p et -g");
  179. puts(" -d, --dir nom du repertoire a lister dans l'iso");
  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, "Bad Install %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. fprintf(stderr, "Erreur ouverture fichier %s\n", hostfilename);
  294. return 1;
  295. }
  296. }
  297. byte sec[CD_SECTOR_SIZE];
  298. iso_directory_t *dir = (iso_directory_t*)(sec);
  299. CdSetloc(isofile, ISO_PADSIZE);
  300. CdRead(sec, 1, isofile);
  301. if(ispvd(sec) == false) {
  302. fprintf(stderr, "%s n'est pas un fichier ISO\n", isofilename);
  303. return 1;
  304. }
  305. loc_t root_lba = *(loc_t*)(sec+158);
  306. if (verbose_flag) printf("root lba = %x\n", root_lba);
  307. CdSetloc(isofile, root_lba);
  308. loc_t dir_lba, dir_offset;
  309. bool s = CdFindFile(dir, isofile, targetfilename, &dir_lba, &dir_offset);
  310. if (!mode_flag) { /* list */
  311. fclose(isofile);
  312. return 0;
  313. }
  314. if(false == s) {
  315. fprintf(stderr, "Fichier %s absent de l'ISO %s\n", targetfilename, isofilename);
  316. return 1;
  317. }
  318. CdSetloc(isofile, dir_lba);
  319. CdRead(sec, 1, isofile);
  320. dir = (iso_directory_t*)(sec + dir_offset);
  321. printf("File size on ISO is %d\n", dir->file_len);
  322. int maxsize = ALIGN(dir->file_len, 0x800);
  323. int len = getfilesize(hostfile);
  324. int aligned_len = ALIGN(len, 0x800);
  325. printf("File size on HOST is %d\n", len);
  326. return 0; /* test */
  327. if(false == length_override) {
  328. if(len > maxsize) {
  329. fprintf(stderr, "Le fichier %s depasse de %d octets (%d > %d)\n",
  330. hostfilename,
  331. len - maxsize,
  332. len, maxsize
  333. );
  334. fclose(hostfile);
  335. fclose(isofile);
  336. return 1;
  337. }
  338. if((uint32_t)len != dir->file_len) {
  339. if((uint32_t)aligned_len < dir->file_len) {
  340. printf("ATTENTION: La mise en place de ce fichier va retrecir l'espace d'allocation disponible !\n");
  341. printf(" (il sera de %d octets)\n", aligned_len);
  342. }
  343. printf("Les tailles sont differentes mais compatibles. Modification ? [o/N]\n");
  344. int ch = getchar();
  345. if((ch != 'o') && (ch != 'O')) {
  346. printf("Annulation !!\n");
  347. return 1;
  348. }
  349. }
  350. }
  351. byte *filedata = (byte*)(malloc(aligned_len));
  352. memset(filedata, 0, aligned_len);
  353. fread(filedata, 1, len, hostfile);
  354. fclose(hostfile);
  355. printf("Ecriture de %d octets sur le secteur %u\n", len, dir->lba);
  356. CdSetloc(isofile, dir->lba);
  357. CdWrite(filedata, (aligned_len / CD_SECTOR_SIZE), isofile);
  358. dir->file_len = len;
  359. printf("Ecriture d'un nouveau repertoire sur %u\n", dir_lba);
  360. CdSetloc(isofile, dir_lba);
  361. CdWrite(sec, 1, isofile);
  362. printf("OK !\n");
  363. fclose(isofile);
  364. return 0;
  365. }